[git commit master] ntpd: locally bind every peer socket. +22 bytes

Denys Vlasenko vda.linux at googlemail.com
Tue Nov 24 15:03:47 UTC 2009


commit: http://git.busybox.net/busybox/commit/?id=b1278a38bcb108fad3230ecce94a53b64571f9de
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 include/libbb.h   |    3 +-
 libbb/xconnect.c  |    2 +-
 networking/ntpd.c |   87 +++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 64 insertions(+), 28 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 77c9e28..1194f7e 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -490,7 +490,8 @@ enum {
 /* Create stream socket, and allocate suitable lsa.
  * (lsa of correct size and lsa->sa.sa_family (AF_INET/AF_INET6))
  * 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
 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 b6848ea..8a1e1c1 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,)
 		len = sizeof(struct sockaddr_in6);
 	}
 #endif
-	lsa = xzalloc(offsetof(len_and_sockaddr, u.sa) + len);
+	lsa = xzalloc(LSA_LEN_SIZE + len);
 	lsa->len = len;
 	lsa->u.sa.sa_family = family;
 	*lsap = lsa;
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 086b3ea..12e498d 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -12,22 +12,22 @@
 # error "Sorry, your kernel has to support IP_PKTINFO"
 #endif
 
-#define	INTERVAL_QUERY_NORMAL		30	/* sync to peers every n secs */
-#define	INTERVAL_QUERY_PATHETIC		60
-#define	INTERVAL_QUERY_AGRESSIVE	5
+#define INTERVAL_QUERY_NORMAL		30	/* sync to peers every n secs */
+#define INTERVAL_QUERY_PATHETIC		60
+#define INTERVAL_QUERY_AGRESSIVE	5
 
-#define	TRUSTLEVEL_BADPEER		6	/* bad if *less than* TRUSTLEVEL_BADPEER */
-#define	TRUSTLEVEL_PATHETIC		2
-#define	TRUSTLEVEL_AGRESSIVE		8
-#define	TRUSTLEVEL_MAX			10
+#define TRUSTLEVEL_BADPEER		6	/* bad if *less than* TRUSTLEVEL_BADPEER */
+#define TRUSTLEVEL_PATHETIC		2
+#define TRUSTLEVEL_AGRESSIVE		8
+#define TRUSTLEVEL_MAX			10
 
-#define	QSCALE_OFF_MIN			0.05
-#define	QSCALE_OFF_MAX			0.50
+#define QSCALE_OFF_MIN			0.05
+#define QSCALE_OFF_MAX			0.50
 
-#define	QUERYTIME_MAX		15	/* single query might take n secs max */
-#define	OFFSET_ARRAY_SIZE	8
-#define	SETTIME_MIN_OFFSET	180	/* min offset for settime at start */
-#define	SETTIME_TIMEOUT		15	/* max seconds to wait with -s */
+#define QUERYTIME_MAX		15	/* single query might take n secs max */
+#define OFFSET_ARRAY_SIZE	8
+#define SETTIME_MIN_OFFSET	180	/* min offset for settime at start */
+#define SETTIME_TIMEOUT		15	/* max seconds to wait with -s */
 
 /* Style borrowed from NTP ref/tcpdump and updated for SNTPv4 (RFC2030). */
 
@@ -112,7 +112,7 @@ enum {
 	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 {
 	STATE_NONE,
@@ -173,12 +173,12 @@ struct globals {
 #if ENABLE_FEATURE_NTPD_SERVER
 	int		listen_fd;
 #endif
+	unsigned	peer_cnt;
 	llist_t		*ntp_peers;
 	ntp_status_t	status;
 	uint32_t	scale;
 	uint8_t		settime;
 	uint8_t		firstadj;
-	smallint	peer_cnt;
 };
 #define G (*ptr_to_globals)
 
@@ -214,11 +214,11 @@ add_peers(const char *s)
 }
 
 static double
-gettime_fp(void)
+gettime1900fp(void)
 {
 	struct timeval tv;
 	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
@@ -311,12 +311,43 @@ sendmsg_wrap(int fd,
 static int
 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) {
-		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 (p->lsa->u.sa.sa_family == AF_INET)
+		if (family == AF_INET)
 #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.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,
 			&p->query.msg, NTP_MSGSIZE_NOAUTH) == -1) {
@@ -437,7 +468,7 @@ adjtime_wrap(void)
 	}
 
 	G.firstadj = 0;
-	G.status.reftime = gettime_fp();
+	G.status.reftime = gettime1900fp();
 	G.status.stratum++;	/* one more than selected peer */
 	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);
 
+	/* 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);
 	if (size == -1) {
 		bb_perror_msg("recv(%s) error", addr);
@@ -583,7 +618,7 @@ recv_and_process_peer_pkt(ntp_peer_t *p)
 		xfunc_die();
 	}
 
-	T4 = gettime_fp();
+	T4 = gettime1900fp();
 
 	if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) {
 		bb_error_msg("malformed packet received from %s", addr);
@@ -635,7 +670,7 @@ recv_and_process_peer_pkt(ntp_peer_t *p)
 		goto bail;
 	}
 	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->good = 1;
 
@@ -724,10 +759,10 @@ recv_and_process_client_pkt(void /*int fd*/)
 	msg.stratum = G.status.stratum;
 	msg.ppoll = query_ppoll;
 	msg.precision = G.status.precision;
-	rectime = gettime_fp();
+	rectime = gettime1900fp();
 	msg.xmttime = msg.rectime = d_to_lfp(rectime);
 	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.rootdelay = d_to_sfp(G.status.rootdelay);
 	version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */
-- 
1.6.3.3



More information about the busybox-cvs mailing list