Module Name:    src
Committed By:   christos
Date:           Fri Jun  7 17:17:15 UTC 2013

Modified Files:
        src/usr.sbin/pppd/pppd: sys-bsd.c

Log Message:
- skip addresses that don't have a link address by finding the link address
  immediately.
- don't skip v6 only interfaces.
- default to the first interface with a link address or to the best matching
  one, printing a warning if there are more than one.
- consume data after sending messages to the routing socket.


To generate a diff of this commit:
cvs rdiff -u -r1.65 -r1.66 src/usr.sbin/pppd/pppd/sys-bsd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.sbin/pppd/pppd/sys-bsd.c
diff -u src/usr.sbin/pppd/pppd/sys-bsd.c:1.65 src/usr.sbin/pppd/pppd/sys-bsd.c:1.66
--- src/usr.sbin/pppd/pppd/sys-bsd.c:1.65	Sat Sep 24 16:19:39 2011
+++ src/usr.sbin/pppd/pppd/sys-bsd.c	Fri Jun  7 13:17:14 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys-bsd.c,v 1.65 2011/09/24 20:19:39 christos Exp $	*/
+/*	$NetBSD: sys-bsd.c,v 1.66 2013/06/07 17:17:14 christos Exp $	*/
 
 /*
  * sys-bsd.c - System-dependent procedures for setting up
@@ -79,7 +79,7 @@
 #if 0
 #define RCSID	"Id: sys-bsd.c,v 1.47 2000/04/13 12:04:23 paulus Exp "
 #else
-__RCSID("$NetBSD: sys-bsd.c,v 1.65 2011/09/24 20:19:39 christos Exp $");
+__RCSID("$NetBSD: sys-bsd.c,v 1.66 2013/06/07 17:17:14 christos Exp $");
 #endif
 #endif
 
@@ -1540,6 +1540,27 @@ cifdefaultroute(int u, u_int32_t l, u_in
     return dodefaultroute(g, 'c');
 }
 
+#if RTM_VERSION >= 3
+static struct {
+    struct rt_msghdr		hdr;
+    char			space[512];
+} arpmsg;
+
+static int arpmsg_valid;
+
+static void
+consume(int routes) {
+    ssize_t l;
+    pid_t pid = getpid();
+    struct rt_msghdr *rtm = &arpmsg.hdr;
+
+    do
+	l = read(routes, &arpmsg, sizeof(arpmsg));
+    while (l > 0 && (rtm->rtm_seq != rtm_seq || rtm->rtm_pid != pid));
+    if (l < 0)
+	warn("read from routing socket");
+}
+
 /*
  * dodefaultroute - talk to a routing socket to add/delete a default route.
  */
@@ -1555,7 +1576,7 @@ dodefaultroute(u_int32_t g, int cmd)
 	struct sockaddr_dl	ifp;
     } rtmsg;
 
-    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
 	if (!doing_cleanup)
 	    error("%s: Couldn't %s default route: socket: %m", __func__,
 		cmd == 's' ? "add" : "delete");
@@ -1596,42 +1617,55 @@ dodefaultroute(u_int32_t g, int cmd)
 	close(routes);
 	return 0;
     }
+    consume(routes);
 
     close(routes);
     default_route_gateway = (cmd == 's') ? g : 0;
     return 1;
 }
 
-#if RTM_VERSION >= 3
+
+#if 0
+static void
+hdrprint(const struct rt_msghdr *rtm) {
+	printf("rtm_msglen=%u\n", rtm->rtm_msglen);
+	printf("rtm_version=%u\n", rtm->rtm_version);
+	printf("rtm_type=%u\n", rtm->rtm_type);
+	printf("rtm_index=%u\n", rtm->rtm_index);
+	printf("rtm_flags=%x\n", rtm->rtm_flags);
+	printf("rtm_addrs=%d\n", rtm->rtm_addrs);
+	printf("rtm_pid=%lu\n", (unsigned long)rtm->rtm_pid);
+	printf("rtm_seq=%d\n", rtm->rtm_seq);
+	printf("rtm_errno=%d\n", rtm->rtm_errno);
+	printf("rtm_use=%d\n", rtm->rtm_use);
+	printf("rtm_inits=%d\n", rtm->rtm_inits);
+	printf("rtm_rmx.rmx_expire=%lld\n", (long long)rtm->rtm_rmx.rmx_expire);
+}
+#endif
+
 
 /*
  * sifproxyarp - Make a proxy ARP entry for the peer.
  */
-static struct {
-    struct rt_msghdr		hdr;
-    struct sockaddr_inarp	dst;
-    struct sockaddr_dl		hwa;
-    char			extra[128];
-} arpmsg;
-
-static int arpmsg_valid;
-
 int
 sifproxyarp(int unit, u_int32_t hisaddr)
 {
     int routes;
+    struct sockaddr_inarp dst;
+    struct sockaddr_dl sdl;
+    char *cp;
 
     /*
      * Get the hardware address of an interface on the same subnet
      * as our local address.
      */
     memset(&arpmsg, 0, sizeof(arpmsg));
-    if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
+    if (!get_ether_addr(hisaddr, &sdl)) {
 	error("%s: Cannot determine ethernet address for proxy ARP", __func__);
 	return 0;
     }
 
-    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
 	error("%s: Couldn't add proxy arp entry: socket: %m", __func__);
 	return 0;
     }
@@ -1642,19 +1676,29 @@ sifproxyarp(int unit, u_int32_t hisaddr)
     arpmsg.hdr.rtm_seq = ++rtm_seq;
     arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
     arpmsg.hdr.rtm_inits = RTV_EXPIRE;
-    arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
-    arpmsg.dst.sin_family = AF_INET;
-    arpmsg.dst.sin_addr.s_addr = hisaddr;
-    arpmsg.dst.sin_other = SIN_PROXY;
 
-    arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
-	+ RT_ROUNDUP(arpmsg.hwa.sdl_len);
+    memset(&dst, 0, sizeof(dst));
+    dst.sin_len = sizeof(struct sockaddr_in);
+    dst.sin_family = AF_INET;
+    dst.sin_addr.s_addr = hisaddr;
+    dst.sin_other = SIN_PROXY;
+
+    cp = arpmsg.space;
+#define NEXTADDR(s) \
+    (void)memcpy(cp, &s, (size_t)((struct sockaddr *)(void *)&s)->sa_len), \
+    RT_ADVANCE(cp, ((struct sockaddr *)(void *)&s))
+    NEXTADDR(dst);
+    NEXTADDR(sdl);
+    arpmsg.hdr.rtm_msglen = cp - (char *)(void *)&arpmsg;
+
     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
 	error("%s: Couldn't add proxy arp entry: %m", __func__);
 	close(routes);
 	return 0;
     }
 
+    consume(routes);
+
     close(routes);
     arpmsg_valid = 1;
     proxy_arp_addr = hisaddr;
@@ -1676,7 +1720,7 @@ cifproxyarp(int unit, u_int32_t hisaddr)
     arpmsg.hdr.rtm_type = RTM_DELETE;
     arpmsg.hdr.rtm_seq = ++rtm_seq;
 
-    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
 	if (!doing_cleanup)
 	    error("%s: Couldn't delete proxy arp entry: socket: %m", __func__);
 	return 0;
@@ -1688,6 +1732,8 @@ cifproxyarp(int unit, u_int32_t hisaddr)
 	close(routes);
 	return 0;
     }
+    consume(routes);
+
 
     close(routes);
     proxy_arp_addr = 0;
@@ -1754,6 +1800,16 @@ cifproxyarp(int unit, u_int32_t hisaddr)
 }
 #endif	/* RTM_VERSION */
 
+static struct ifaddrs *
+getlink(struct ifaddrs *ifa, const char *name)
+{
+    for (; ifa; ifa = ifa->ifa_next)
+	if (strcmp(ifa->ifa_name, name) == 0 &&
+	    ifa->ifa_addr->sa_family == AF_LINK)
+	    return ifa;
+    return NULL;
+}
+
 
 /*
  * get_ether_addr - get the hardware address of an interface on the
@@ -1762,9 +1818,8 @@ cifproxyarp(int unit, u_int32_t hisaddr)
 static int
 get_ether_addr(u_int32_t ipaddr, struct sockaddr_dl *hwaddr)
 {
-    u_int32_t ina, mask;
     struct sockaddr_dl *dla;
-    struct ifaddrs *ifap, *ifa, *ifp;
+    struct ifaddrs *ifap, *ifa, *ifp, *iflink;
 
     /*
      * Scan through looking for an interface with an Internet
@@ -1775,55 +1830,68 @@ get_ether_addr(u_int32_t ipaddr, struct 
 	return 0;
     }
 
-    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-	if (ifa->ifa_addr->sa_family != AF_INET)
-	    continue;
-	ina = ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr;
+    for (ifp = NULL, ifa = ifap; ifa; ifa = ifa->ifa_next) {
 	/*
 	 * Check that the interface is up, and not point-to-point
 	 * or loopback.
 	 */
 	if ((ifa->ifa_flags &
 	     (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
-	     != (IFF_UP|IFF_BROADCAST))
+	     != (IFF_UP|IFF_BROADCAST)) {
 	    continue;
-	/*
-	 * Get its netmask and check that it's on the right subnet.
-	 */
-	mask = ((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr;
-	if ((ipaddr & mask) != (ina & mask))
+	}
+
+	switch (ifa->ifa_addr->sa_family) {
+	case AF_INET:
+	case AF_INET6:
+	    /*
+	     * See if it has a link address and remember it.
+	     */
+	    if ((iflink = getlink(ifap, ifa->ifa_name)) == NULL)
+		continue;
+	    if (ifp == NULL)
+		ifp = iflink;
+	    else
+		info("more than one interfaces match for proxy arp");
+	    break;
+	default:
 	    continue;
+	}
+
+	switch (ifa->ifa_addr->sa_family) {
+	    u_int32_t ina, mask;
+	case AF_INET:
+	    /*
+	     * Get its netmask and check that it's on the right subnet.
+	     */
+	    ina = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
+	    mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;
+	    if ((ipaddr & mask) != (ina & mask))
+		continue;
+	    ifp = iflink;
+	    break;
+	case AF_INET6:
+	    /* XXX */
+	    break;
+	default:
+	    abort();
+	}
 	break;
     }
 
-    if (!ifa) {
+    if (!ifp) {
 	freeifaddrs(ifap);
 	return 0;
     }
-    info("found interface %s for proxy arp", ifa->ifa_name);
-
-    ifp = ifa;
+    info("found interface %s for proxy arp", ifp->ifa_name);
 
     /*
-     * Now scan through again looking for a link-level address
-     * for this interface.
+     * copy out the link-level address
      */
-    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-	if (strcmp(ifp->ifa_name, ifa->ifa_name) != 0)
-	    continue;
-	if (ifa->ifa_addr->sa_family != AF_LINK)
-	    continue;
-	/*
-	 * Found the link-level address - copy it out
-	 */
-	dla = (struct sockaddr_dl *) ifa->ifa_addr;
-	BCOPY(dla, hwaddr, dla->sdl_len);
-	freeifaddrs(ifap);
-	return 1;
-    }
-
+    dla = (struct sockaddr_dl *) ifp->ifa_addr;
+    BCOPY(dla, hwaddr, sizeof(*dla));
     freeifaddrs(ifap);
-    return 0;
+    return 1;
 }
 
 /*

Reply via email to