ntpd: locally bind every peer socket. +22 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
9cc60d7e6b
commit
b1278a38bc
@ -490,7 +490,8 @@ enum {
|
|||||||
/* Create stream socket, and allocate suitable lsa.
|
/* Create stream socket, and allocate suitable lsa.
|
||||||
* (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6))
|
* (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6))
|
||||||
* af == AF_UNSPEC will result in trying to create IPv6 socket,
|
* af == AF_UNSPEC will result in trying to create IPv6 socket,
|
||||||
* and if kernel doesn't support it, IPv4.
|
* and if kernel doesn't support it, fall back to IPv4.
|
||||||
|
* This is useful if you plan to bind to resulting local lsa.
|
||||||
*/
|
*/
|
||||||
#if ENABLE_FEATURE_IPV6
|
#if ENABLE_FEATURE_IPV6
|
||||||
int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC;
|
int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC;
|
||||||
|
@ -346,7 +346,7 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,)
|
|||||||
len = sizeof(struct sockaddr_in6);
|
len = sizeof(struct sockaddr_in6);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
lsa = xzalloc(offsetof(len_and_sockaddr, u.sa) + len);
|
lsa = xzalloc(LSA_LEN_SIZE + len);
|
||||||
lsa->len = len;
|
lsa->len = len;
|
||||||
lsa->u.sa.sa_family = family;
|
lsa->u.sa.sa_family = family;
|
||||||
*lsap = lsa;
|
*lsap = lsa;
|
||||||
|
@ -12,22 +12,22 @@
|
|||||||
# error "Sorry, your kernel has to support IP_PKTINFO"
|
# error "Sorry, your kernel has to support IP_PKTINFO"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INTERVAL_QUERY_NORMAL 30 /* sync to peers every n secs */
|
#define INTERVAL_QUERY_NORMAL 30 /* sync to peers every n secs */
|
||||||
#define INTERVAL_QUERY_PATHETIC 60
|
#define INTERVAL_QUERY_PATHETIC 60
|
||||||
#define INTERVAL_QUERY_AGRESSIVE 5
|
#define INTERVAL_QUERY_AGRESSIVE 5
|
||||||
|
|
||||||
#define TRUSTLEVEL_BADPEER 6 /* bad if *less than* TRUSTLEVEL_BADPEER */
|
#define TRUSTLEVEL_BADPEER 6 /* bad if *less than* TRUSTLEVEL_BADPEER */
|
||||||
#define TRUSTLEVEL_PATHETIC 2
|
#define TRUSTLEVEL_PATHETIC 2
|
||||||
#define TRUSTLEVEL_AGRESSIVE 8
|
#define TRUSTLEVEL_AGRESSIVE 8
|
||||||
#define TRUSTLEVEL_MAX 10
|
#define TRUSTLEVEL_MAX 10
|
||||||
|
|
||||||
#define QSCALE_OFF_MIN 0.05
|
#define QSCALE_OFF_MIN 0.05
|
||||||
#define QSCALE_OFF_MAX 0.50
|
#define QSCALE_OFF_MAX 0.50
|
||||||
|
|
||||||
#define QUERYTIME_MAX 15 /* single query might take n secs max */
|
#define QUERYTIME_MAX 15 /* single query might take n secs max */
|
||||||
#define OFFSET_ARRAY_SIZE 8
|
#define OFFSET_ARRAY_SIZE 8
|
||||||
#define SETTIME_MIN_OFFSET 180 /* min offset for settime at start */
|
#define SETTIME_MIN_OFFSET 180 /* min offset for settime at start */
|
||||||
#define SETTIME_TIMEOUT 15 /* max seconds to wait with -s */
|
#define SETTIME_TIMEOUT 15 /* max seconds to wait with -s */
|
||||||
|
|
||||||
/* Style borrowed from NTP ref/tcpdump and updated for SNTPv4 (RFC2030). */
|
/* Style borrowed from NTP ref/tcpdump and updated for SNTPv4 (RFC2030). */
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ enum {
|
|||||||
MODE_RES2 = 7, /* reserved for private use */
|
MODE_RES2 = 7, /* reserved for private use */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
|
#define OFFSET_1900_1970 2208988800UL /* 1970 - 1900 in seconds */
|
||||||
|
|
||||||
enum client_state {
|
enum client_state {
|
||||||
STATE_NONE,
|
STATE_NONE,
|
||||||
@ -173,12 +173,12 @@ struct globals {
|
|||||||
#if ENABLE_FEATURE_NTPD_SERVER
|
#if ENABLE_FEATURE_NTPD_SERVER
|
||||||
int listen_fd;
|
int listen_fd;
|
||||||
#endif
|
#endif
|
||||||
|
unsigned peer_cnt;
|
||||||
llist_t *ntp_peers;
|
llist_t *ntp_peers;
|
||||||
ntp_status_t status;
|
ntp_status_t status;
|
||||||
uint32_t scale;
|
uint32_t scale;
|
||||||
uint8_t settime;
|
uint8_t settime;
|
||||||
uint8_t firstadj;
|
uint8_t firstadj;
|
||||||
smallint peer_cnt;
|
|
||||||
};
|
};
|
||||||
#define G (*ptr_to_globals)
|
#define G (*ptr_to_globals)
|
||||||
|
|
||||||
@ -214,11 +214,11 @@ add_peers(const char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static double
|
static double
|
||||||
gettime_fp(void)
|
gettime1900fp(void)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
gettimeofday(&tv, NULL); /* never fails */
|
gettimeofday(&tv, NULL); /* never fails */
|
||||||
return (tv.tv_sec + 1.0e-6 * tv.tv_usec + JAN_1970);
|
return (tv.tv_sec + 1.0e-6 * tv.tv_usec + OFFSET_1900_1970);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -311,12 +311,43 @@ sendmsg_wrap(int fd,
|
|||||||
static int
|
static int
|
||||||
send_query_to_peer(ntp_peer_t *p)
|
send_query_to_peer(ntp_peer_t *p)
|
||||||
{
|
{
|
||||||
|
// Why do we need to bind()?
|
||||||
|
// See what happens when we don't bind:
|
||||||
|
//
|
||||||
|
// socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
|
||||||
|
// setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0
|
||||||
|
// gettimeofday({1259071266, 327885}, NULL) = 0
|
||||||
|
// sendto(3, "xxx", 48, MSG_DONTWAIT, {sa_family=AF_INET, sin_port=htons(123), sin_addr=inet_addr("10.34.32.125")}, 16) = 48
|
||||||
|
// ^^^ we sent it from some source port picked by kernel.
|
||||||
|
// time(NULL) = 1259071266
|
||||||
|
// write(2, "ntpd: entering poll 15 secs\n", 28) = 28
|
||||||
|
// poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}])
|
||||||
|
// recv(3, "yyy", 68, MSG_DONTWAIT) = 48
|
||||||
|
// ^^^ this recv will receive packets to any local port!
|
||||||
|
//
|
||||||
|
// Uncomment this and use strace to see it in action:
|
||||||
|
#define PROBE_LOCAL_ADDR // { len_and_sockaddr lsa; lsa.len = LSA_SIZEOF_SA; getsockname(p->query.fd, &lsa.u.sa, &lsa.len); }
|
||||||
|
|
||||||
if (p->query.fd == -1) {
|
if (p->query.fd == -1) {
|
||||||
p->query.fd = xsocket(p->lsa->u.sa.sa_family, SOCK_DGRAM, 0);
|
int fd, family;
|
||||||
|
len_and_sockaddr *local_lsa;
|
||||||
|
|
||||||
|
family = p->lsa->u.sa.sa_family;
|
||||||
|
//was: p->query.fd = xsocket(family, SOCK_DGRAM, 0);
|
||||||
|
p->query.fd = fd = xsocket_type(&local_lsa, family, SOCK_DGRAM);
|
||||||
|
/* local_lsa has "null" address and port 0 now.
|
||||||
|
* bind() ensures we have a *particular port* selected by kernel
|
||||||
|
* and remembered in p->query.fd, thus later recv(p->query.fd)
|
||||||
|
* receives only packets sent to this port.
|
||||||
|
*/
|
||||||
|
PROBE_LOCAL_ADDR
|
||||||
|
xbind(fd, &local_lsa->u.sa, local_lsa->len);
|
||||||
|
PROBE_LOCAL_ADDR
|
||||||
#if ENABLE_FEATURE_IPV6
|
#if ENABLE_FEATURE_IPV6
|
||||||
if (p->lsa->u.sa.sa_family == AF_INET)
|
if (family == AF_INET)
|
||||||
#endif
|
#endif
|
||||||
setsockopt(p->query.fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY));
|
setsockopt(fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY));
|
||||||
|
free(local_lsa);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -335,7 +366,7 @@ send_query_to_peer(ntp_peer_t *p)
|
|||||||
|
|
||||||
p->query.msg.xmttime.int_partl = random();
|
p->query.msg.xmttime.int_partl = random();
|
||||||
p->query.msg.xmttime.fractionl = random();
|
p->query.msg.xmttime.fractionl = random();
|
||||||
p->query.xmttime = gettime_fp();
|
p->query.xmttime = gettime1900fp();
|
||||||
|
|
||||||
if (sendmsg_wrap(p->query.fd, /*from:*/ NULL, /*to:*/ &p->lsa->u.sa, /*addrlen:*/ p->lsa->len,
|
if (sendmsg_wrap(p->query.fd, /*from:*/ NULL, /*to:*/ &p->lsa->u.sa, /*addrlen:*/ p->lsa->len,
|
||||||
&p->query.msg, NTP_MSGSIZE_NOAUTH) == -1) {
|
&p->query.msg, NTP_MSGSIZE_NOAUTH) == -1) {
|
||||||
@ -437,7 +468,7 @@ adjtime_wrap(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
G.firstadj = 0;
|
G.firstadj = 0;
|
||||||
G.status.reftime = gettime_fp();
|
G.status.reftime = gettime1900fp();
|
||||||
G.status.stratum++; /* one more than selected peer */
|
G.status.stratum++; /* one more than selected peer */
|
||||||
G.scale = updated_scale(offset_median);
|
G.scale = updated_scale(offset_median);
|
||||||
|
|
||||||
@ -568,6 +599,10 @@ recv_and_process_peer_pkt(ntp_peer_t *p)
|
|||||||
|
|
||||||
addr = xmalloc_sockaddr2dotted_noport(&p->lsa->u.sa);
|
addr = xmalloc_sockaddr2dotted_noport(&p->lsa->u.sa);
|
||||||
|
|
||||||
|
/* We can recvfrom here and check from.IP, but some multihomed
|
||||||
|
* ntp servers reply from their *other IP*.
|
||||||
|
* TODO: maybe we should check at least what we can: from.port == 123?
|
||||||
|
*/
|
||||||
size = recv(p->query.fd, &msg, sizeof(msg), MSG_DONTWAIT);
|
size = recv(p->query.fd, &msg, sizeof(msg), MSG_DONTWAIT);
|
||||||
if (size == -1) {
|
if (size == -1) {
|
||||||
bb_perror_msg("recv(%s) error", addr);
|
bb_perror_msg("recv(%s) error", addr);
|
||||||
@ -583,7 +618,7 @@ recv_and_process_peer_pkt(ntp_peer_t *p)
|
|||||||
xfunc_die();
|
xfunc_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
T4 = gettime_fp();
|
T4 = gettime1900fp();
|
||||||
|
|
||||||
if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) {
|
if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) {
|
||||||
bb_error_msg("malformed packet received from %s", addr);
|
bb_error_msg("malformed packet received from %s", addr);
|
||||||
@ -635,7 +670,7 @@ recv_and_process_peer_pkt(ntp_peer_t *p)
|
|||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
offset->error = (T2 - T1) - (T3 - T4);
|
offset->error = (T2 - T1) - (T3 - T4);
|
||||||
// Can we use (T4 - JAN_1970) instead of time(NULL)?
|
// Can we use (T4 - OFFSET_1900_1970) instead of time(NULL)?
|
||||||
offset->rcvd = time(NULL);
|
offset->rcvd = time(NULL);
|
||||||
offset->good = 1;
|
offset->good = 1;
|
||||||
|
|
||||||
@ -724,10 +759,10 @@ recv_and_process_client_pkt(void /*int fd*/)
|
|||||||
msg.stratum = G.status.stratum;
|
msg.stratum = G.status.stratum;
|
||||||
msg.ppoll = query_ppoll;
|
msg.ppoll = query_ppoll;
|
||||||
msg.precision = G.status.precision;
|
msg.precision = G.status.precision;
|
||||||
rectime = gettime_fp();
|
rectime = gettime1900fp();
|
||||||
msg.xmttime = msg.rectime = d_to_lfp(rectime);
|
msg.xmttime = msg.rectime = d_to_lfp(rectime);
|
||||||
msg.reftime = d_to_lfp(G.status.reftime);
|
msg.reftime = d_to_lfp(G.status.reftime);
|
||||||
//msg.xmttime = d_to_lfp(gettime_fp()); // = msg.rectime
|
//msg.xmttime = d_to_lfp(gettime1900fp()); // = msg.rectime
|
||||||
msg.orgtime = query_xmttime;
|
msg.orgtime = query_xmttime;
|
||||||
msg.rootdelay = d_to_sfp(G.status.rootdelay);
|
msg.rootdelay = d_to_sfp(G.status.rootdelay);
|
||||||
version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */
|
version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */
|
||||||
|
Loading…
Reference in New Issue
Block a user