summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/ppp/arp.c145
1 files changed, 80 insertions, 65 deletions
diff --git a/usr.sbin/ppp/arp.c b/usr.sbin/ppp/arp.c
index 08244d2..963c154 100644
--- a/usr.sbin/ppp/arp.c
+++ b/usr.sbin/ppp/arp.c
@@ -17,7 +17,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * $Id: arp.c,v 1.23 1998/01/19 22:34:20 brian Exp $
+ * $Id: arp.c,v 1.24 1998/01/21 12:52:14 brian Exp $
*
*/
@@ -34,6 +34,7 @@
#include <netinet/in.h>
#include <net/if_types.h>
#include <netinet/if_ether.h>
+#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
@@ -65,7 +66,7 @@
* and type ``make arp-test''.
*
*/
-#define LogIsKept(x) 0
+#define LogIsKept(x) 1
#define LogPrintf fprintf
#undef LogDEBUG
#define LogDEBUG stderr
@@ -240,90 +241,104 @@ cifproxyarp(int unit, struct in_addr hisaddr)
* get_ether_addr - get the hardware address of an interface on the
* the same subnet as ipaddr.
*/
-#define MAX_IFS 32
static int
get_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr)
{
- int idx;
- const char *got;
- char *sp, *ep, *cp, *wp;
- struct ifreq ifrq;
- struct in_addr addr, mask;
- struct rt_msghdr *rtm;
- struct sockaddr *sa_dst, *sa_gw;
- struct sockaddr_dl *dl;
+ int mib[6], sa_len, skip, b;
size_t needed;
- int mib[6];
-
- idx = 1;
- while (strcmp(got = Index2Nam(idx), "???")) {
- strncpy(ifrq.ifr_name, got, sizeof ifrq.ifr_name - 1);
- ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
- if (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0 &&
- ifrq.ifr_addr.sa_family == AF_INET) {
- addr = ((struct sockaddr_in *)&ifrq.ifr_addr)->sin_addr;
- if (ID0ioctl(s, SIOCGIFNETMASK, &ifrq) == 0) {
- mask = ((struct sockaddr_in *)&ifrq.ifr_broadaddr)->sin_addr;
- if ((ipaddr.s_addr & mask.s_addr) == (addr.s_addr & mask.s_addr))
- break;
- }
- }
- idx++;
- }
-
- if (!strcmp(got, "???"))
- return 0;
-
- LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", got);
+ char *buf, *ptr, *end;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr *sa;
+ struct sockaddr_dl *dl;
+ struct sockaddr_in *ifa, *mask;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
- mib[4] = NET_RT_DUMP;
+ mib[4] = NET_RT_IFLIST;
mib[5] = 0;
+
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
- LogPrintf(LogERROR, "get_ether_addr: sysctl: estimate: %s\n",
- strerror(errno));
+ LogPrintf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
return 0;
}
- if (needed < 0)
+
+ if ((buf = malloc(needed)) == NULL)
return 0;
- if ((sp = malloc(needed)) == NULL)
+
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ free(buf);
return 0;
- if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
- LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno));
- free(sp);
- return (1);
}
- ep = sp + needed;
-
- for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *) cp;
- if (rtm->rtm_index == idx) {
- wp = (char *)(rtm+1);
-
- if (rtm->rtm_addrs & RTA_DST) {
- sa_dst = (struct sockaddr *)wp;
- wp += sa_dst->sa_len;
- } else
- sa_dst = NULL;
-
- if (rtm->rtm_addrs & RTA_GATEWAY) {
- sa_gw = (struct sockaddr *)wp;
- if (sa_gw->sa_family == AF_LINK) {
- dl = (struct sockaddr_dl *)wp;
- if (!dl->sdl_nlen && !dl->sdl_alen && !dl->sdl_slen) {
- memcpy(hwaddr, dl, dl->sdl_len);
- free(sp);
- return 1;
- }
+ end = buf + needed;
+
+ ptr = buf;
+ while (ptr < end) {
+ ifm = (struct if_msghdr *)ptr; /* On if_msghdr */
+ if (ifm->ifm_type != RTM_IFINFO)
+ break;
+ dl = (struct sockaddr_dl *)(ifm + 1); /* Single _dl at end */
+ skip = (ifm->ifm_flags & (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT |
+ IFF_NOARP | IFF_LOOPBACK)) != (IFF_UP | IFF_BROADCAST);
+ ptr += ifm->ifm_msglen; /* First ifa_msghdr */
+ while (ptr < end) {
+ ifam = (struct ifa_msghdr *)ptr; /* Next ifa_msghdr (alias) */
+ if (ifam->ifam_type != RTM_NEWADDR) /* finished ? */
+ break;
+ sa = (struct sockaddr *)(ifam+1); /* pile of sa's at end */
+ ptr += ifam->ifam_msglen;
+ if (skip || (ifam->ifam_addrs & (RTA_NETMASK|RTA_IFA)) !=
+ (RTA_NETMASK|RTA_IFA))
+ continue;
+ /* Found a candidate. Do the addresses match ? */
+ if (LogIsKept(LogDEBUG) &&
+ ptr == (char *)ifm + ifm->ifm_msglen + ifam->ifam_msglen)
+ LogPrintf(LogDEBUG, "%.*s interface is a candidate for proxy\n",
+ dl->sdl_nlen, dl->sdl_data);
+ b = 1;
+ while (b < (RTA_NETMASK|RTA_IFA) && sa < (struct sockaddr *)ptr) {
+ switch (b) {
+ case RTA_IFA:
+ ifa = (struct sockaddr_in *)sa;
+ break;
+ case RTA_NETMASK:
+ /*
+ * Careful here ! this sockaddr doesn't have sa_family set to
+ * AF_INET, and is only 8 bytes big ! I have no idea why !
+ */
+ mask = (struct sockaddr_in *)sa;
+ break;
}
+ if (ifam->ifam_addrs & b) {
+#define ALN sizeof(ifa->sin_addr.s_addr)
+ sa_len = sa->sa_len > 0 ? ((sa->sa_len-1)|(ALN-1))+1 : ALN;
+ sa = (struct sockaddr *)((char *)sa + sa_len);
+ }
+ b <<= 1;
+ }
+ if (LogIsKept(LogDEBUG)) {
+ char a[16];
+ strncpy(a, inet_ntoa(mask->sin_addr), sizeof a - 1);
+ a[sizeof a - 1] = '\0';
+ LogPrintf(LogDEBUG, "Check addr %s, mask %s\n",
+ inet_ntoa(ifa->sin_addr), a);
+ }
+ if (ifa->sin_family == AF_INET &&
+ (ifa->sin_addr.s_addr & mask->sin_addr.s_addr) ==
+ (ipaddr.s_addr & mask->sin_addr.s_addr)) {
+ LogPrintf(LogPHASE, "Found interface %.*s for proxy arp\n",
+ dl->sdl_alen, dl->sdl_data);
+ memcpy(hwaddr, dl, dl->sdl_len);
+ free(buf);
+ return 1;
}
}
}
- free(sp);
+ free(buf);
+
return 0;
}
OpenPOWER on IntegriCloud