diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-24 16:03:47 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-24 16:03:47 +0100 |
commit | b1278a38bcb108fad3230ecce94a53b64571f9de (patch) | |
tree | 27ccecf5dd5a76cff75e809d5518fb1589479d85 | |
parent | 9cc60d7e6b21e659a07042e46b9cd88f498fc8c0 (diff) | |
download | busybox-w32-b1278a38bcb108fad3230ecce94a53b64571f9de.tar.gz busybox-w32-b1278a38bcb108fad3230ecce94a53b64571f9de.tar.bz2 busybox-w32-b1278a38bcb108fad3230ecce94a53b64571f9de.zip |
ntpd: locally bind every peer socket. +22 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | include/libbb.h | 3 | ||||
-rw-r--r-- | libbb/xconnect.c | 2 | ||||
-rw-r--r-- | networking/ntpd.c | 87 |
3 files changed, 64 insertions, 28 deletions
diff --git a/include/libbb.h b/include/libbb.h index 77c9e2888..1194f7eca 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -490,7 +490,8 @@ enum { | |||
490 | /* Create stream socket, and allocate suitable lsa. | 490 | /* Create stream socket, and allocate suitable lsa. |
491 | * (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6)) | 491 | * (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6)) |
492 | * af == AF_UNSPEC will result in trying to create IPv6 socket, | 492 | * af == AF_UNSPEC will result in trying to create IPv6 socket, |
493 | * and if kernel doesn't support it, IPv4. | 493 | * and if kernel doesn't support it, fall back to IPv4. |
494 | * This is useful if you plan to bind to resulting local lsa. | ||
494 | */ | 495 | */ |
495 | #if ENABLE_FEATURE_IPV6 | 496 | #if ENABLE_FEATURE_IPV6 |
496 | int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; | 497 | int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; |
diff --git a/libbb/xconnect.c b/libbb/xconnect.c index b6848ea6f..8a1e1c1b2 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c | |||
@@ -346,7 +346,7 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) | |||
346 | len = sizeof(struct sockaddr_in6); | 346 | len = sizeof(struct sockaddr_in6); |
347 | } | 347 | } |
348 | #endif | 348 | #endif |
349 | lsa = xzalloc(offsetof(len_and_sockaddr, u.sa) + len); | 349 | lsa = xzalloc(LSA_LEN_SIZE + len); |
350 | lsa->len = len; | 350 | lsa->len = len; |
351 | lsa->u.sa.sa_family = family; | 351 | lsa->u.sa.sa_family = family; |
352 | *lsap = lsa; | 352 | *lsap = lsa; |
diff --git a/networking/ntpd.c b/networking/ntpd.c index 086b3ea74..12e498d48 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c | |||
@@ -12,22 +12,22 @@ | |||
12 | # error "Sorry, your kernel has to support IP_PKTINFO" | 12 | # error "Sorry, your kernel has to support IP_PKTINFO" |
13 | #endif | 13 | #endif |
14 | 14 | ||
15 | #define INTERVAL_QUERY_NORMAL 30 /* sync to peers every n secs */ | 15 | #define INTERVAL_QUERY_NORMAL 30 /* sync to peers every n secs */ |
16 | #define INTERVAL_QUERY_PATHETIC 60 | 16 | #define INTERVAL_QUERY_PATHETIC 60 |
17 | #define INTERVAL_QUERY_AGRESSIVE 5 | 17 | #define INTERVAL_QUERY_AGRESSIVE 5 |
18 | 18 | ||
19 | #define TRUSTLEVEL_BADPEER 6 /* bad if *less than* TRUSTLEVEL_BADPEER */ | 19 | #define TRUSTLEVEL_BADPEER 6 /* bad if *less than* TRUSTLEVEL_BADPEER */ |
20 | #define TRUSTLEVEL_PATHETIC 2 | 20 | #define TRUSTLEVEL_PATHETIC 2 |
21 | #define TRUSTLEVEL_AGRESSIVE 8 | 21 | #define TRUSTLEVEL_AGRESSIVE 8 |
22 | #define TRUSTLEVEL_MAX 10 | 22 | #define TRUSTLEVEL_MAX 10 |
23 | 23 | ||
24 | #define QSCALE_OFF_MIN 0.05 | 24 | #define QSCALE_OFF_MIN 0.05 |
25 | #define QSCALE_OFF_MAX 0.50 | 25 | #define QSCALE_OFF_MAX 0.50 |
26 | 26 | ||
27 | #define QUERYTIME_MAX 15 /* single query might take n secs max */ | 27 | #define QUERYTIME_MAX 15 /* single query might take n secs max */ |
28 | #define OFFSET_ARRAY_SIZE 8 | 28 | #define OFFSET_ARRAY_SIZE 8 |
29 | #define SETTIME_MIN_OFFSET 180 /* min offset for settime at start */ | 29 | #define SETTIME_MIN_OFFSET 180 /* min offset for settime at start */ |
30 | #define SETTIME_TIMEOUT 15 /* max seconds to wait with -s */ | 30 | #define SETTIME_TIMEOUT 15 /* max seconds to wait with -s */ |
31 | 31 | ||
32 | /* Style borrowed from NTP ref/tcpdump and updated for SNTPv4 (RFC2030). */ | 32 | /* Style borrowed from NTP ref/tcpdump and updated for SNTPv4 (RFC2030). */ |
33 | 33 | ||
@@ -112,7 +112,7 @@ enum { | |||
112 | MODE_RES2 = 7, /* reserved for private use */ | 112 | MODE_RES2 = 7, /* reserved for private use */ |
113 | }; | 113 | }; |
114 | 114 | ||
115 | #define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */ | 115 | #define OFFSET_1900_1970 2208988800UL /* 1970 - 1900 in seconds */ |
116 | 116 | ||
117 | enum client_state { | 117 | enum client_state { |
118 | STATE_NONE, | 118 | STATE_NONE, |
@@ -173,12 +173,12 @@ struct globals { | |||
173 | #if ENABLE_FEATURE_NTPD_SERVER | 173 | #if ENABLE_FEATURE_NTPD_SERVER |
174 | int listen_fd; | 174 | int listen_fd; |
175 | #endif | 175 | #endif |
176 | unsigned peer_cnt; | ||
176 | llist_t *ntp_peers; | 177 | llist_t *ntp_peers; |
177 | ntp_status_t status; | 178 | ntp_status_t status; |
178 | uint32_t scale; | 179 | uint32_t scale; |
179 | uint8_t settime; | 180 | uint8_t settime; |
180 | uint8_t firstadj; | 181 | uint8_t firstadj; |
181 | smallint peer_cnt; | ||
182 | }; | 182 | }; |
183 | #define G (*ptr_to_globals) | 183 | #define G (*ptr_to_globals) |
184 | 184 | ||
@@ -214,11 +214,11 @@ add_peers(const char *s) | |||
214 | } | 214 | } |
215 | 215 | ||
216 | static double | 216 | static double |
217 | gettime_fp(void) | 217 | gettime1900fp(void) |
218 | { | 218 | { |
219 | struct timeval tv; | 219 | struct timeval tv; |
220 | gettimeofday(&tv, NULL); /* never fails */ | 220 | gettimeofday(&tv, NULL); /* never fails */ |
221 | return (tv.tv_sec + 1.0e-6 * tv.tv_usec + JAN_1970); | 221 | return (tv.tv_sec + 1.0e-6 * tv.tv_usec + OFFSET_1900_1970); |
222 | } | 222 | } |
223 | 223 | ||
224 | static void | 224 | static void |
@@ -311,12 +311,43 @@ sendmsg_wrap(int fd, | |||
311 | static int | 311 | static int |
312 | send_query_to_peer(ntp_peer_t *p) | 312 | send_query_to_peer(ntp_peer_t *p) |
313 | { | 313 | { |
314 | // Why do we need to bind()? | ||
315 | // See what happens when we don't bind: | ||
316 | // | ||
317 | // socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 3 | ||
318 | // setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0 | ||
319 | // gettimeofday({1259071266, 327885}, NULL) = 0 | ||
320 | // sendto(3, "xxx", 48, MSG_DONTWAIT, {sa_family=AF_INET, sin_port=htons(123), sin_addr=inet_addr("10.34.32.125")}, 16) = 48 | ||
321 | // ^^^ we sent it from some source port picked by kernel. | ||
322 | // time(NULL) = 1259071266 | ||
323 | // write(2, "ntpd: entering poll 15 secs\n", 28) = 28 | ||
324 | // poll([{fd=3, events=POLLIN}], 1, 15000) = 1 ([{fd=3, revents=POLLIN}]) | ||
325 | // recv(3, "yyy", 68, MSG_DONTWAIT) = 48 | ||
326 | // ^^^ this recv will receive packets to any local port! | ||
327 | // | ||
328 | // Uncomment this and use strace to see it in action: | ||
329 | #define PROBE_LOCAL_ADDR // { len_and_sockaddr lsa; lsa.len = LSA_SIZEOF_SA; getsockname(p->query.fd, &lsa.u.sa, &lsa.len); } | ||
330 | |||
314 | if (p->query.fd == -1) { | 331 | if (p->query.fd == -1) { |
315 | p->query.fd = xsocket(p->lsa->u.sa.sa_family, SOCK_DGRAM, 0); | 332 | int fd, family; |
333 | len_and_sockaddr *local_lsa; | ||
334 | |||
335 | family = p->lsa->u.sa.sa_family; | ||
336 | //was: p->query.fd = xsocket(family, SOCK_DGRAM, 0); | ||
337 | p->query.fd = fd = xsocket_type(&local_lsa, family, SOCK_DGRAM); | ||
338 | /* local_lsa has "null" address and port 0 now. | ||
339 | * bind() ensures we have a *particular port* selected by kernel | ||
340 | * and remembered in p->query.fd, thus later recv(p->query.fd) | ||
341 | * receives only packets sent to this port. | ||
342 | */ | ||
343 | PROBE_LOCAL_ADDR | ||
344 | xbind(fd, &local_lsa->u.sa, local_lsa->len); | ||
345 | PROBE_LOCAL_ADDR | ||
316 | #if ENABLE_FEATURE_IPV6 | 346 | #if ENABLE_FEATURE_IPV6 |
317 | if (p->lsa->u.sa.sa_family == AF_INET) | 347 | if (family == AF_INET) |
318 | #endif | 348 | #endif |
319 | setsockopt(p->query.fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); | 349 | setsockopt(fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); |
350 | free(local_lsa); | ||
320 | } | 351 | } |
321 | 352 | ||
322 | /* | 353 | /* |
@@ -335,7 +366,7 @@ send_query_to_peer(ntp_peer_t *p) | |||
335 | 366 | ||
336 | p->query.msg.xmttime.int_partl = random(); | 367 | p->query.msg.xmttime.int_partl = random(); |
337 | p->query.msg.xmttime.fractionl = random(); | 368 | p->query.msg.xmttime.fractionl = random(); |
338 | p->query.xmttime = gettime_fp(); | 369 | p->query.xmttime = gettime1900fp(); |
339 | 370 | ||
340 | if (sendmsg_wrap(p->query.fd, /*from:*/ NULL, /*to:*/ &p->lsa->u.sa, /*addrlen:*/ p->lsa->len, | 371 | if (sendmsg_wrap(p->query.fd, /*from:*/ NULL, /*to:*/ &p->lsa->u.sa, /*addrlen:*/ p->lsa->len, |
341 | &p->query.msg, NTP_MSGSIZE_NOAUTH) == -1) { | 372 | &p->query.msg, NTP_MSGSIZE_NOAUTH) == -1) { |
@@ -437,7 +468,7 @@ adjtime_wrap(void) | |||
437 | } | 468 | } |
438 | 469 | ||
439 | G.firstadj = 0; | 470 | G.firstadj = 0; |
440 | G.status.reftime = gettime_fp(); | 471 | G.status.reftime = gettime1900fp(); |
441 | G.status.stratum++; /* one more than selected peer */ | 472 | G.status.stratum++; /* one more than selected peer */ |
442 | G.scale = updated_scale(offset_median); | 473 | G.scale = updated_scale(offset_median); |
443 | 474 | ||
@@ -568,6 +599,10 @@ recv_and_process_peer_pkt(ntp_peer_t *p) | |||
568 | 599 | ||
569 | addr = xmalloc_sockaddr2dotted_noport(&p->lsa->u.sa); | 600 | addr = xmalloc_sockaddr2dotted_noport(&p->lsa->u.sa); |
570 | 601 | ||
602 | /* We can recvfrom here and check from.IP, but some multihomed | ||
603 | * ntp servers reply from their *other IP*. | ||
604 | * TODO: maybe we should check at least what we can: from.port == 123? | ||
605 | */ | ||
571 | size = recv(p->query.fd, &msg, sizeof(msg), MSG_DONTWAIT); | 606 | size = recv(p->query.fd, &msg, sizeof(msg), MSG_DONTWAIT); |
572 | if (size == -1) { | 607 | if (size == -1) { |
573 | bb_perror_msg("recv(%s) error", addr); | 608 | bb_perror_msg("recv(%s) error", addr); |
@@ -583,7 +618,7 @@ recv_and_process_peer_pkt(ntp_peer_t *p) | |||
583 | xfunc_die(); | 618 | xfunc_die(); |
584 | } | 619 | } |
585 | 620 | ||
586 | T4 = gettime_fp(); | 621 | T4 = gettime1900fp(); |
587 | 622 | ||
588 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { | 623 | if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { |
589 | bb_error_msg("malformed packet received from %s", addr); | 624 | bb_error_msg("malformed packet received from %s", addr); |
@@ -635,7 +670,7 @@ recv_and_process_peer_pkt(ntp_peer_t *p) | |||
635 | goto bail; | 670 | goto bail; |
636 | } | 671 | } |
637 | offset->error = (T2 - T1) - (T3 - T4); | 672 | offset->error = (T2 - T1) - (T3 - T4); |
638 | // Can we use (T4 - JAN_1970) instead of time(NULL)? | 673 | // Can we use (T4 - OFFSET_1900_1970) instead of time(NULL)? |
639 | offset->rcvd = time(NULL); | 674 | offset->rcvd = time(NULL); |
640 | offset->good = 1; | 675 | offset->good = 1; |
641 | 676 | ||
@@ -724,10 +759,10 @@ recv_and_process_client_pkt(void /*int fd*/) | |||
724 | msg.stratum = G.status.stratum; | 759 | msg.stratum = G.status.stratum; |
725 | msg.ppoll = query_ppoll; | 760 | msg.ppoll = query_ppoll; |
726 | msg.precision = G.status.precision; | 761 | msg.precision = G.status.precision; |
727 | rectime = gettime_fp(); | 762 | rectime = gettime1900fp(); |
728 | msg.xmttime = msg.rectime = d_to_lfp(rectime); | 763 | msg.xmttime = msg.rectime = d_to_lfp(rectime); |
729 | msg.reftime = d_to_lfp(G.status.reftime); | 764 | msg.reftime = d_to_lfp(G.status.reftime); |
730 | //msg.xmttime = d_to_lfp(gettime_fp()); // = msg.rectime | 765 | //msg.xmttime = d_to_lfp(gettime1900fp()); // = msg.rectime |
731 | msg.orgtime = query_xmttime; | 766 | msg.orgtime = query_xmttime; |
732 | msg.rootdelay = d_to_sfp(G.status.rootdelay); | 767 | msg.rootdelay = d_to_sfp(G.status.rootdelay); |
733 | version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */ | 768 | version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */ |