X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/30c9b9dffacb6b3108a71c88fae788410d32896e..ed5d57202ebab0e923eb8e9d967a9f97792a6e8f:/usr.sbin/rarpd/rarpd.c diff --git a/usr.sbin/rarpd/rarpd.c b/usr.sbin/rarpd/rarpd.c index 5eb8971753..b52f410b54 100644 --- a/usr.sbin/rarpd/rarpd.c +++ b/usr.sbin/rarpd/rarpd.c @@ -7,27 +7,22 @@ * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials - * provided with the distribution, and (3) all advertising materials mentioning - * features or use of this software display the following acknowledgement: - * ``This product includes software developed by the University of California, - * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of - * the University nor the names of its contributors may be used to endorse - * or promote products derived from this software without specific prior - * written permission. + * provided with the distribution + * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#) Copyright (c) 1990, 1991, 1992, 1993, 1996 The Regents of the University of California. All rights reserved. - * $FreeBSD: src/usr.sbin/rarpd/rarpd.c,v 1.23.2.4 2002/12/01 19:19:34 dwmalone Exp $ + * $FreeBSD: src/usr.sbin/rarpd/rarpd.c,v 1.41 2004/08/07 04:28:54 imp Exp $ * $DragonFly: src/usr.sbin/rarpd/rarpd.c,v 1.4 2004/12/18 22:48:05 swildner Exp $ */ /* * rarpd - Reverse ARP Daemon * - * Usage: rarpd -a [ -dfsv ] [-t directory] [ hostname ] - * rarpd [ -dfsv ] [-t directory] interface [ hostname ] + * Usage: rarpd -a [-dfsv] [-t directory] [hostname] + * rarpd [-dfsv] [-t directory] interface [hostname] * * 'hostname' is optional solely for backwards compatibility with Sun's rarpd. * Currently, the argument is ignored. @@ -50,7 +45,9 @@ #include +#include #include +#include #include #include #include @@ -59,59 +56,27 @@ #include #include -#if defined(SUNOS4) || defined(__DragonFly__) /* XXX */ -#define HAVE_DIRENT_H -#endif - -#ifdef HAVE_DIRENT_H -#include -#else -#include -#endif - -/* Cast a struct sockaddr to a structaddr_in */ +/* Cast a struct sockaddr to a struct sockaddr_in */ #define SATOSIN(sa) ((struct sockaddr_in *)(sa)) #ifndef TFTP_DIR #define TFTP_DIR "/tftpboot" #endif -#if BSD >= 199200 #define ARPSECS (20 * 60) /* as per code in netinet/if_ether.c */ #define REVARP_REQUEST ARPOP_REVREQUEST #define REVARP_REPLY ARPOP_REVREPLY -#endif - -#ifndef ETHERTYPE_REVARP -#define ETHERTYPE_REVARP 0x8035 -#define REVARP_REQUEST 3 -#define REVARP_REPLY 4 -#endif - -/* - * Map field names in ether_arp struct. What a pain in the neck. - */ -#ifdef SUNOS3 -#undef arp_sha -#undef arp_spa -#undef arp_tha -#undef arp_tpa -#define arp_sha arp_xsha -#define arp_spa arp_xspa -#define arp_tha arp_xtha -#define arp_tpa arp_xtpa -#endif /* * The structure for each interface. */ struct if_info { - struct if_info *ii_next; - int ii_fd; /* BPF file descriptor */ - u_long ii_ipaddr; /* IP address of this interface */ - u_long ii_netmask; /* subnet or net mask */ - u_char ii_eaddr[6]; /* Ethernet address of this interface */ - char ii_ifname[sizeof(((struct ifreq *)0)->ifr_name) + 1]; + struct if_info *ii_next; + int ii_fd; /* BPF file descriptor */ + in_addr_t ii_ipaddr; /* IP address */ + in_addr_t ii_netmask; /* subnet or net mask */ + u_char ii_eaddr[ETHER_ADDR_LEN]; /* ethernet address */ + char ii_ifname[IF_NAMESIZE]; }; /* @@ -121,7 +86,6 @@ struct if_info { struct if_info *iflist; int verbose; /* verbose messages */ -int s; /* inet datagram socket */ const char *tftp_dir = TFTP_DIR; /* tftp directory */ int dflag; /* messages to stdout/stderr, not syslog(3) */ @@ -130,22 +94,22 @@ int sflag; /* ignore /tftpboot */ static u_char zero[6]; static int bpf_open(void); -static u_long choose_ipaddr(u_long **, u_long, u_long); +static in_addr_t choose_ipaddr(in_addr_t **, in_addr_t, in_addr_t); static char *eatoa(u_char *); static int expand_syslog_m(const char *fmt, char **newfmt); static void init(char *); -static void init_one(struct ifreq *, char *); -static char *intoa(u_long); -static u_long ipaddrtonetmask(u_long); +static void init_one(struct ifaddrs *, char *, int); +static char *intoa(in_addr_t); +static in_addr_t ipaddrtonetmask(in_addr_t); static void logmsg(int, const char *, ...) __printflike(2, 3); -static int rarp_bootable(u_long); +static int rarp_bootable(in_addr_t); static int rarp_check(u_char *, u_int); static void rarp_loop(void); static int rarp_open(char *); static void rarp_process(struct if_info *, u_char *, u_int); static void rarp_reply(struct if_info *, struct ether_header *, - u_long, u_int); -static void update_arptab(u_char *, u_long); + in_addr_t, u_int); +static void update_arptab(u_char *, in_addr_t); static void usage(void); int @@ -170,7 +134,7 @@ main(int argc, char *argv[]) openlog(name, LOG_PID | LOG_CONS, LOG_DAEMON); opterr = 0; - while ((op = getopt(argc, argv, "adfst:v")) != -1) { + while ((op = getopt(argc, argv, "adfst:v")) != -1) switch (op) { case 'a': ++aflag; @@ -200,16 +164,16 @@ main(int argc, char *argv[]) usage(); /* NOTREACHED */ } - } - ifname = argv[optind++]; - hostname = ifname ? argv[optind] : NULL; + argc -= optind; + argv += optind; + + ifname = (aflag == 0) ? argv[0] : NULL; + hostname = ifname ? argv[1] : argv[0]; + if ((aflag && ifname) || (!aflag && ifname == NULL)) usage(); - if (aflag) - init(NULL); - else - init(ifname); + init(ifname); if (!fflag) { if (daemon(0,0)) { @@ -224,49 +188,42 @@ main(int argc, char *argv[]) /* * Add to the interface list. */ -void -init_one(struct ifreq *ifrp, char *target) +static void +init_one(struct ifaddrs *ifa, char *target, int pass1) { - struct if_info *ii; + struct if_info *ii, *ii2; struct sockaddr_dl *ll; int family; - struct ifreq ifr; - family = ifrp->ifr_addr.sa_family; + family = ifa->ifa_addr->sa_family; switch (family) { - case AF_INET: -#if BSD >= 199100 + if (pass1) + /* Consider only AF_LINK during pass1. */ + return; + /* FALLTHROUGH */ case AF_LINK: -#endif - strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifrp->ifr_name)); - if (ioctl(s, SIOCGIFFLAGS, (char *)&ifr) == -1) { - logmsg(LOG_ERR, - "SIOCGIFFLAGS: %.*s: %m", - (int)sizeof(ifrp->ifr_name), ifrp->ifr_name); - exit(1); - } - if ((ifr.ifr_flags & IFF_UP) == 0 || - (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) + if (!(ifa->ifa_flags & IFF_UP) || + (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) return; break; - - default: return; } /* Don't bother going any further if not the target interface */ - if (target != NULL && - strncmp(ifrp->ifr_name, target, sizeof(ifrp->ifr_name)) != 0) + if (target != NULL && strcmp(ifa->ifa_name, target) != 0) return; /* Look for interface in list */ for (ii = iflist; ii != NULL; ii = ii->ii_next) - if (strncmp(ifrp->ifr_name, ii->ii_ifname, - sizeof(ifrp->ifr_name)) == 0) + if (strcmp(ifa->ifa_name, ii->ii_ifname) == 0) break; + if (pass1 && ii != NULL) + /* We've already seen that interface once. */ + return; + /* Allocate a new one if not found */ if (ii == NULL) { ii = (struct if_info *)malloc(sizeof(*ii)); @@ -276,90 +233,76 @@ init_one(struct ifreq *ifrp, char *target) } bzero(ii, sizeof(*ii)); ii->ii_fd = -1; - strncpy(ii->ii_ifname, ifrp->ifr_name, sizeof(ifrp->ifr_name)); - ii->ii_ifname[sizeof(ii->ii_ifname) - 1] = '\0'; + strlcpy(ii->ii_ifname, ifa->ifa_name, sizeof(ii->ii_ifname)); ii->ii_next = iflist; iflist = ii; + } else if (!pass1 && ii->ii_ipaddr != 0) { + /* + * Second AF_INET definition for that interface: clone + * the existing one, and work on that cloned one. + * This must be another IP address for this interface, + * so avoid killing the previous configuration. + */ + ii2 = (struct if_info *)malloc(sizeof(*ii2)); + if (ii2 == NULL) { + logmsg(LOG_ERR, "malloc: %m"); + exit(1); + } + memcpy(ii2, ii, sizeof(*ii2)); + ii2->ii_fd = -1; + ii2->ii_next = iflist; + iflist = ii2; + + ii = ii2; } switch (family) { - case AF_INET: - if (ioctl(s, SIOCGIFADDR, (char *)&ifr) == -1) { - logmsg(LOG_ERR, "ipaddr SIOCGIFADDR: %s: %m", - ii->ii_ifname); - exit(1); - } - ii->ii_ipaddr = SATOSIN(&ifr.ifr_addr)->sin_addr.s_addr; - if (ioctl(s, SIOCGIFNETMASK, (char *)&ifr) == -1) { - logmsg(LOG_ERR, "SIOCGIFNETMASK: %m"); - exit(1); - } - ii->ii_netmask = SATOSIN(&ifr.ifr_addr)->sin_addr.s_addr; + ii->ii_ipaddr = SATOSIN(ifa->ifa_addr)->sin_addr.s_addr; + ii->ii_netmask = SATOSIN(ifa->ifa_netmask)->sin_addr.s_addr; if (ii->ii_netmask == 0) ii->ii_netmask = ipaddrtonetmask(ii->ii_ipaddr); - if (ii->ii_fd < 0) { + if (ii->ii_fd < 0) ii->ii_fd = rarp_open(ii->ii_ifname); -#if BSD < 199100 - /* Use BPF descriptor to get ethernet address. */ - if (ioctl(ii->ii_fd, SIOCGIFADDR, (char *)&ifr) == -1) { - logmsg(LOG_ERR, "eaddr SIOCGIFADDR: %s: %m", - ii->ii_ifname); - exit(1); - } - bcopy(&ifr.ifr_addr.sa_data[0], ii->ii_eaddr, 6); -#endif - } break; -#if BSD >= 199100 - case AF_LINK: - ll = (struct sockaddr_dl *)&ifrp->ifr_addr; - if (ll->sdl_type == IFT_ETHER) - bcopy(LLADDR(ll), ii->ii_eaddr, 6); - break; -#endif - } + case AF_LINK: + ll = (struct sockaddr_dl *)ifa->ifa_addr; + if (ll->sdl_type == IFT_ETHER) + bcopy(LLADDR(ll), ii->ii_eaddr, 6); + break; + } } /* * Initialize all "candidate" interfaces that are in the system * configuration list. A "candidate" is up, not loopback and not * point to point. */ -void +static void init(char *target) { - u_int n; - struct ifreq *ifrp, *ifend; struct if_info *ii, *nii, *lii; - struct ifconf ifc; - struct ifreq ibuf[16]; + struct ifaddrs *ifhead, *ifa; + int error; - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logmsg(LOG_ERR, "socket: %m"); - exit(1); - } - ifc.ifc_len = sizeof ibuf; - ifc.ifc_buf = (caddr_t)ibuf; - if ((ioctl(s, SIOCGIFCONF, (char *)&ifc) == -1) || - ((u_int)ifc.ifc_len < sizeof(struct ifreq))) { - logmsg(LOG_ERR, "SIOCGIFCONF: %m"); + error = getifaddrs(&ifhead); + if (error) { + logmsg(LOG_ERR, "getifaddrs: %m"); exit(1); } - ifrp = ibuf; - ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); - while (ifrp < ifend) { - init_one(ifrp, target); - -#if BSD >= 199100 - n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); - if (n < sizeof(*ifrp)) - n = sizeof(*ifrp); - ifrp = (struct ifreq *)((char *)ifrp + n); -#else - ++ifrp; -#endif - } + /* + * We make two passes over the list we have got. In the first + * one, we only collect AF_LINK interfaces, and initialize our + * list of interfaces from them. In the second pass, we + * collect the actual IP addresses from the AF_INET + * interfaces, and allow for the same interface name to appear + * multiple times (in case of more than one IP address). + */ + for (ifa = ifhead; ifa != NULL; ifa = ifa->ifa_next) + init_one(ifa, target, 1); + for (ifa = ifhead; ifa != NULL; ifa = ifa->ifa_next) + init_one(ifa, target, 0); + freeifaddrs(ifhead); /* Throw away incomplete interfaces */ lii = NULL; @@ -382,19 +325,21 @@ init(char *target) /* Verbose stuff */ if (verbose) for (ii = iflist; ii != NULL; ii = ii->ii_next) - logmsg(LOG_DEBUG, "%s %s 0x%08lx %s", + logmsg(LOG_DEBUG, "%s %s 0x%08x %s", ii->ii_ifname, intoa(ntohl(ii->ii_ipaddr)), - (u_long)ntohl(ii->ii_netmask), eatoa(ii->ii_eaddr)); + (in_addr_t)ntohl(ii->ii_netmask), eatoa(ii->ii_eaddr)); } -void +static void usage(void) { - fprintf(stderr, "usage: rarpd [-adfsv] [-t directory] [interface]\n"); + fprintf(stderr, "%s\n%s\n", + "usage: rarpd -a [-dfsv] [-t directory]", + " rarpd [-dfsv] [-t directory] interface"); exit(1); } -int +static int bpf_open(void) { int fd; @@ -420,7 +365,7 @@ bpf_open(void) * Open a BPF file and attach it to the interface named 'device'. * Set immediate mode, and set a filter that accepts only RARP requests. */ -int +static int rarp_open(char *device) { int fd; @@ -451,7 +396,7 @@ rarp_open(char *device) logmsg(LOG_ERR, "BIOCIMMEDIATE: %m"); exit(1); } - strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name); + strlcpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) == -1) { logmsg(LOG_ERR, "BIOCSETIF: %m"); exit(1); @@ -482,7 +427,7 @@ rarp_open(char *device) * Perform various sanity checks on the RARP request packet. Return * false on failure and log the reason. */ -int +static int rarp_check(u_char *p, u_int len) { struct ether_header *ep = (struct ether_header *)p; @@ -515,17 +460,11 @@ rarp_check(u_char *p, u_int len) return 1; } -#ifndef FD_SETSIZE -#define FD_SET(n, fdp) ((fdp)->fds_bits[0] |= (1 << (n))) -#define FD_ISSET(n, fdp) ((fdp)->fds_bits[0] & (1 << (n))) -#define FD_ZERO(fdp) ((fdp)->fds_bits[0] = 0) -#endif - /* * Loop indefinitely listening for RARP requests on the * interfaces in 'iflist'. */ -void +static void rarp_loop(void) { u_char *buf, *bp, *ep; @@ -576,22 +515,6 @@ rarp_loop(void) /* Don't choke when we get ptraced */ if ((cc == -1) && (errno == EINTR)) goto again; -#if defined(SUNOS3) || defined(SUNOS4) - /* - * Due to a SunOS bug, after 2^31 bytes, the - * file offset overflows and read fails with - * EINVAL. The lseek() to 0 will fix things. - */ - if (cc == -1) { - if (errno == EINVAL && - (long)(tell(fd) + bufsize) < 0) { - lseek(fd, 0, 0); - goto again; - } - logmsg(LOG_ERR, "read: %m"); - exit(1); - } -#endif /* Loop through the packet(s) */ #define bhp ((struct bpf_hdr *)bp) @@ -616,19 +539,15 @@ rarp_loop(void) * This check is made by looking in the tftp directory for the * configuration file. */ -int -rarp_bootable(u_long addr) +static int +rarp_bootable(in_addr_t addr) { -#ifdef HAVE_DIRENT_H struct dirent *dent; -#else - struct direct *dent; -#endif DIR *d; char ipname[9]; static DIR *dd = NULL; - sprintf(ipname, "%08lX", (u_long)ntohl(addr)); + sprintf(ipname, "%08X", (in_addr_t)ntohl(addr)); /* * If directory is already open, rewind it. Otherwise, open it. @@ -658,8 +577,8 @@ rarp_bootable(u_long addr) * is on network 'net'; 'netmask' is a mask indicating the network portion * of the address. */ -u_long -choose_ipaddr(u_long **alist, u_long net, u_long netmask) +static in_addr_t +choose_ipaddr(in_addr_t **alist, in_addr_t net, in_addr_t netmask) { for (; *alist; ++alist) if ((**alist & netmask) == net) @@ -671,12 +590,12 @@ choose_ipaddr(u_long **alist, u_long net, u_long netmask) * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has * already been checked for validity. The reply is overlaid on the request. */ -void +static void rarp_process(struct if_info *ii, u_char *pkt, u_int len) { struct ether_header *ep; struct hostent *hp; - u_long target_ipaddr; + in_addr_t target_ipaddr; char ename[256]; ep = (struct ether_header *)pkt; @@ -700,7 +619,7 @@ rarp_process(struct if_info *ii, u_char *pkt, u_int len) ename); return; } - target_ipaddr = choose_ipaddr((u_long **)hp->h_addr_list, + target_ipaddr = choose_ipaddr((in_addr_t **)hp->h_addr_list, ii->ii_ipaddr & ii->ii_netmask, ii->ii_netmask); if (target_ipaddr == 0) { @@ -723,7 +642,6 @@ rarp_process(struct if_info *ii, u_char *pkt, u_int len) * host (i.e. the guy running rarpd), won't try to ARP for the hardware * address of the guy being booted (he cannot answer the ARP). */ -#if BSD >= 199200 struct sockaddr_inarp sin_inarp = { sizeof(struct sockaddr_inarp), AF_INET, 0, {0}, @@ -739,8 +657,8 @@ struct { char rtspace[512]; } rtmsg; -void -update_arptab(u_char *ep, u_long ipaddr) +static void +update_arptab(u_char *ep, in_addr_t ipaddr) { int cc; struct sockaddr_inarp *ar, *ar2; @@ -794,7 +712,7 @@ update_arptab(u_char *ep, u_long ipaddr) * directly connected network (the family is AF_INET in * this case). */ - logmsg(LOG_ERR, "bogus link family (%d) wrong net for %08lX?\n", + logmsg(LOG_ERR, "bogus link family (%d) wrong net for %08X?\n", ll2->sdl_family, ipaddr); close(r); return; @@ -835,24 +753,6 @@ update_arptab(u_char *ep, u_long ipaddr) return; } } -#else -void -update_arptab(u_char *ep, u_long ipaddr) -{ - struct arpreq request; - struct sockaddr_in *sin; - - request.arp_flags = 0; - sin = (struct sockaddr_in *)&request.arp_pa; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ipaddr; - request.arp_ha.sa_family = AF_UNSPEC; - bcopy((char *)ep, (char *)request.arp_ha.sa_data, 6); - - if (ioctl(s, SIOCSARP, (caddr_t)&request) == -1) - logmsg(LOG_ERR, "SIOCSARP: %m"); -} -#endif /* * Build a reverse ARP packet and sent it out on the interface. @@ -887,8 +787,8 @@ update_arptab(u_char *ep, u_long ipaddr) * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent * ARP request. */ -void -rarp_reply(struct if_info *ii, struct ether_header *ep, u_long ipaddr, +static void +rarp_reply(struct if_info *ii, struct ether_header *ep, in_addr_t ipaddr, u_int len) { u_int n; @@ -928,8 +828,8 @@ rarp_reply(struct if_info *ii, struct ether_header *ep, u_long ipaddr, * Get the netmask of an IP address. This routine is used if * SIOCGIFNETMASK doesn't work. */ -u_long -ipaddrtonetmask(u_long addr) +static in_addr_t +ipaddrtonetmask(in_addr_t addr) { addr = ntohl(addr); if (IN_CLASSA(addr)) @@ -938,15 +838,15 @@ ipaddrtonetmask(u_long addr) return htonl(IN_CLASSB_NET); if (IN_CLASSC(addr)) return htonl(IN_CLASSC_NET); - logmsg(LOG_DEBUG, "unknown IP address class: %08lX", addr); + logmsg(LOG_DEBUG, "unknown IP address class: %08X", addr); return htonl(0xffffffff); } /* * A faster replacement for inet_ntoa(). */ -char * -intoa(u_long addr) +static char * +intoa(in_addr_t addr) { char *cp; u_int byte; @@ -974,7 +874,7 @@ intoa(u_long addr) return cp + 1; } -char * +static char * eatoa(u_char *ea) { static char buf[sizeof("xx:xx:xx:xx:xx:xx")]; @@ -984,7 +884,7 @@ eatoa(u_char *ea) return (buf); } -void +static void logmsg(int pri, const char *fmt, ...) { va_list v; @@ -1011,8 +911,9 @@ logmsg(int pri, const char *fmt, ...) va_end(v); } -int -expand_syslog_m(const char *fmt, char **newfmt) { +static int +expand_syslog_m(const char *fmt, char **newfmt) +{ const char *str, *m; char *p, *np;