xref: /freebsd/usr.sbin/ppp/arp.c (revision 5106c67149438f0d50a1915bbcb75be1db7aae30)
153c9f6c0SAtsushi Murai /*
253c9f6c0SAtsushi Murai  * sys-bsd.c - System-dependent procedures for setting up
353c9f6c0SAtsushi Murai  * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
453c9f6c0SAtsushi Murai  *
553c9f6c0SAtsushi Murai  * Copyright (c) 1989 Carnegie Mellon University.
653c9f6c0SAtsushi Murai  * All rights reserved.
753c9f6c0SAtsushi Murai  *
853c9f6c0SAtsushi Murai  * Redistribution and use in source and binary forms are permitted
953c9f6c0SAtsushi Murai  * provided that the above copyright notice and this paragraph are
1053c9f6c0SAtsushi Murai  * duplicated in all such forms and that any documentation,
1153c9f6c0SAtsushi Murai  * advertising materials, and other materials related to such
1253c9f6c0SAtsushi Murai  * distribution and use acknowledge that the software was developed
1353c9f6c0SAtsushi Murai  * by Carnegie Mellon University.  The name of the
1453c9f6c0SAtsushi Murai  * University may not be used to endorse or promote products derived
1553c9f6c0SAtsushi Murai  * from this software without specific prior written permission.
1653c9f6c0SAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1753c9f6c0SAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1853c9f6c0SAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1953c9f6c0SAtsushi Murai  *
205106c671SBrian Somers  * $Id: arp.c,v 1.16 1997/10/26 01:02:03 brian Exp $
2153c9f6c0SAtsushi Murai  *
2253c9f6c0SAtsushi Murai  */
2353c9f6c0SAtsushi Murai 
2453c9f6c0SAtsushi Murai /*
2553c9f6c0SAtsushi Murai  * TODO:
2653c9f6c0SAtsushi Murai  */
2753c9f6c0SAtsushi Murai 
2853c9f6c0SAtsushi Murai #include <sys/types.h>
2953c9f6c0SAtsushi Murai #include <sys/time.h>
3075240ed1SBrian Somers #include <sys/socket.h>
3153c9f6c0SAtsushi Murai #include <net/if.h>
32702a1d01SGarrett Wollman #include <net/if_var.h>
3353c9f6c0SAtsushi Murai #include <net/route.h>
3453c9f6c0SAtsushi Murai #include <net/if_dl.h>
3553c9f6c0SAtsushi Murai #include <netinet/in.h>
3653c9f6c0SAtsushi Murai #include <net/if_types.h>
3753c9f6c0SAtsushi Murai #include <netinet/in_var.h>
3853c9f6c0SAtsushi Murai #include <netinet/if_ether.h>
3975240ed1SBrian Somers 
4075240ed1SBrian Somers #include <fcntl.h>
4175240ed1SBrian Somers #include <stdio.h>
4275240ed1SBrian Somers #include <string.h>
4375240ed1SBrian Somers #include <sys/errno.h>
4475240ed1SBrian Somers #include <sys/ioctl.h>
4575240ed1SBrian Somers #include <sys/uio.h>
4675240ed1SBrian Somers #include <unistd.h>
4775240ed1SBrian Somers 
4875240ed1SBrian Somers #include "mbuf.h"
4910a91a42SBrian Somers #include "log.h"
505106c671SBrian Somers #include "id.h"
5175240ed1SBrian Somers #include "arp.h"
5253c9f6c0SAtsushi Murai 
5353c9f6c0SAtsushi Murai static int rtm_seq;
5453c9f6c0SAtsushi Murai 
55927145beSBrian Somers static int get_ether_addr(int, u_long, struct sockaddr_dl *);
56ed6a16c1SPoul-Henning Kamp 
5753c9f6c0SAtsushi Murai /*
5853c9f6c0SAtsushi Murai  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
5953c9f6c0SAtsushi Murai  * if it exists.
6053c9f6c0SAtsushi Murai  */
6153c9f6c0SAtsushi Murai #define SET_SA_FAMILY(addr, family)		\
6275240ed1SBrian Somers     memset((char *) &(addr), '\0', sizeof(addr));	\
6353c9f6c0SAtsushi Murai     addr.sa_family = (family); 			\
6453c9f6c0SAtsushi Murai     addr.sa_len = sizeof(addr);
6553c9f6c0SAtsushi Murai 
6653c9f6c0SAtsushi Murai 
6753c9f6c0SAtsushi Murai #if RTM_VERSION >= 3
6853c9f6c0SAtsushi Murai 
6953c9f6c0SAtsushi Murai /*
7053c9f6c0SAtsushi Murai  * sifproxyarp - Make a proxy ARP entry for the peer.
7153c9f6c0SAtsushi Murai  */
7253c9f6c0SAtsushi Murai static struct {
7353c9f6c0SAtsushi Murai   struct rt_msghdr hdr;
7453c9f6c0SAtsushi Murai   struct sockaddr_inarp dst;
7553c9f6c0SAtsushi Murai   struct sockaddr_dl hwa;
7653c9f6c0SAtsushi Murai   char extra[128];
7753c9f6c0SAtsushi Murai } arpmsg;
7853c9f6c0SAtsushi Murai 
7953c9f6c0SAtsushi Murai static int arpmsg_valid;
8053c9f6c0SAtsushi Murai 
8153c9f6c0SAtsushi Murai int
82944f7098SBrian Somers sifproxyarp(int unit, u_long hisaddr)
8353c9f6c0SAtsushi Murai {
8453c9f6c0SAtsushi Murai   int routes;
8553c9f6c0SAtsushi Murai 
8653c9f6c0SAtsushi Murai   /*
87944f7098SBrian Somers    * Get the hardware address of an interface on the same subnet as our local
88944f7098SBrian Somers    * address.
8953c9f6c0SAtsushi Murai    */
9053c9f6c0SAtsushi Murai   memset(&arpmsg, 0, sizeof(arpmsg));
9153c9f6c0SAtsushi Murai   if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) {
92afc7fa2cSBrian Somers     LogPrintf(LogERROR, "Cannot determine ethernet address for proxy ARP\n");
9353c9f6c0SAtsushi Murai     return 0;
9453c9f6c0SAtsushi Murai   }
955106c671SBrian Somers   routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET);
965106c671SBrian Somers   if (routes < 0) {
97927145beSBrian Somers     LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n",
98927145beSBrian Somers 	      strerror(errno));
9953c9f6c0SAtsushi Murai     return 0;
10053c9f6c0SAtsushi Murai   }
10153c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_type = RTM_ADD;
10253c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
10353c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_version = RTM_VERSION;
10453c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_seq = ++rtm_seq;
10553c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
10653c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_inits = RTV_EXPIRE;
10753c9f6c0SAtsushi Murai   arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
10853c9f6c0SAtsushi Murai   arpmsg.dst.sin_family = AF_INET;
10953c9f6c0SAtsushi Murai   arpmsg.dst.sin_addr.s_addr = hisaddr;
11053c9f6c0SAtsushi Murai   arpmsg.dst.sin_other = SIN_PROXY;
11153c9f6c0SAtsushi Murai 
11253c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
11353c9f6c0SAtsushi Murai     + arpmsg.hwa.sdl_len;
11453c9f6c0SAtsushi Murai   if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
115927145beSBrian Somers     LogPrintf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno));
11653c9f6c0SAtsushi Murai     close(routes);
11753c9f6c0SAtsushi Murai     return 0;
11853c9f6c0SAtsushi Murai   }
11953c9f6c0SAtsushi Murai   close(routes);
12053c9f6c0SAtsushi Murai   arpmsg_valid = 1;
12153c9f6c0SAtsushi Murai   return 1;
12253c9f6c0SAtsushi Murai }
12353c9f6c0SAtsushi Murai 
12453c9f6c0SAtsushi Murai /*
12553c9f6c0SAtsushi Murai  * cifproxyarp - Delete the proxy ARP entry for the peer.
12653c9f6c0SAtsushi Murai  */
12753c9f6c0SAtsushi Murai int
128944f7098SBrian Somers cifproxyarp(int unit, u_long hisaddr)
12953c9f6c0SAtsushi Murai {
13053c9f6c0SAtsushi Murai   int routes;
13153c9f6c0SAtsushi Murai 
13253c9f6c0SAtsushi Murai   if (!arpmsg_valid)
13353c9f6c0SAtsushi Murai     return 0;
13453c9f6c0SAtsushi Murai   arpmsg_valid = 0;
13553c9f6c0SAtsushi Murai 
13653c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_type = RTM_DELETE;
13753c9f6c0SAtsushi Murai   arpmsg.hdr.rtm_seq = ++rtm_seq;
13853c9f6c0SAtsushi Murai 
1395106c671SBrian Somers   routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET);
1405106c671SBrian Somers   if (routes < 0) {
141927145beSBrian Somers     LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n",
142927145beSBrian Somers 	      strerror(errno));
14353c9f6c0SAtsushi Murai     return 0;
14453c9f6c0SAtsushi Murai   }
14553c9f6c0SAtsushi Murai   if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
146927145beSBrian Somers     LogPrintf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno));
14753c9f6c0SAtsushi Murai     close(routes);
14853c9f6c0SAtsushi Murai     return 0;
14953c9f6c0SAtsushi Murai   }
15053c9f6c0SAtsushi Murai   close(routes);
15153c9f6c0SAtsushi Murai   return 1;
15253c9f6c0SAtsushi Murai }
15353c9f6c0SAtsushi Murai 
15453c9f6c0SAtsushi Murai #else				/* RTM_VERSION */
15553c9f6c0SAtsushi Murai 
15653c9f6c0SAtsushi Murai /*
15753c9f6c0SAtsushi Murai  * sifproxyarp - Make a proxy ARP entry for the peer.
15853c9f6c0SAtsushi Murai  */
15953c9f6c0SAtsushi Murai int
160944f7098SBrian Somers sifproxyarp(int unit, u_long hisaddr)
16153c9f6c0SAtsushi Murai {
16253c9f6c0SAtsushi Murai   struct arpreq arpreq;
16353c9f6c0SAtsushi Murai   struct {
16453c9f6c0SAtsushi Murai     struct sockaddr_dl sdl;
16553c9f6c0SAtsushi Murai     char space[128];
16653c9f6c0SAtsushi Murai   }      dls;
16753c9f6c0SAtsushi Murai 
16875240ed1SBrian Somers   memset(&arpreq, '\0', sizeof(arpreq));
16953c9f6c0SAtsushi Murai 
17053c9f6c0SAtsushi Murai   /*
171944f7098SBrian Somers    * Get the hardware address of an interface on the same subnet as our local
172944f7098SBrian Somers    * address.
17353c9f6c0SAtsushi Murai    */
17453c9f6c0SAtsushi Murai   if (!get_ether_addr(unit, hisaddr, &dls.sdl)) {
1759c749ffbSPoul-Henning Kamp     LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n");
17653c9f6c0SAtsushi Murai     return 0;
17753c9f6c0SAtsushi Murai   }
17853c9f6c0SAtsushi Murai   arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
17953c9f6c0SAtsushi Murai   arpreq.arp_ha.sa_family = AF_UNSPEC;
18075240ed1SBrian Somers   memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen);
18153c9f6c0SAtsushi Murai   SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
18253c9f6c0SAtsushi Murai   ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
18353c9f6c0SAtsushi Murai   arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1845106c671SBrian Somers   if (ID0ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) {
185afc7fa2cSBrian Somers     LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): %s\n", strerror(errno));
18653c9f6c0SAtsushi Murai     return 0;
18753c9f6c0SAtsushi Murai   }
18853c9f6c0SAtsushi Murai   return 1;
18953c9f6c0SAtsushi Murai }
19053c9f6c0SAtsushi Murai 
19153c9f6c0SAtsushi Murai /*
19253c9f6c0SAtsushi Murai  * cifproxyarp - Delete the proxy ARP entry for the peer.
19353c9f6c0SAtsushi Murai  */
19453c9f6c0SAtsushi Murai int
195944f7098SBrian Somers cifproxyarp(int unit, u_long hisaddr)
19653c9f6c0SAtsushi Murai {
19753c9f6c0SAtsushi Murai   struct arpreq arpreq;
19853c9f6c0SAtsushi Murai 
19975240ed1SBrian Somers   memset(&arpreq, '\0', sizeof(arpreq));
20053c9f6c0SAtsushi Murai   SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
20153c9f6c0SAtsushi Murai   ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
2025106c671SBrian Somers   if (ID0ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) {
203afc7fa2cSBrian Somers     LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): %s\n", strerror(errno));
20453c9f6c0SAtsushi Murai     return 0;
20553c9f6c0SAtsushi Murai   }
20653c9f6c0SAtsushi Murai   return 1;
20753c9f6c0SAtsushi Murai }
208944f7098SBrian Somers 
20953c9f6c0SAtsushi Murai #endif				/* RTM_VERSION */
21053c9f6c0SAtsushi Murai 
21153c9f6c0SAtsushi Murai 
21253c9f6c0SAtsushi Murai /*
21353c9f6c0SAtsushi Murai  * get_ether_addr - get the hardware address of an interface on the
21453c9f6c0SAtsushi Murai  * the same subnet as ipaddr.
21553c9f6c0SAtsushi Murai  */
21653c9f6c0SAtsushi Murai #define MAX_IFS		32
21753c9f6c0SAtsushi Murai 
21875240ed1SBrian Somers static int
219944f7098SBrian Somers get_ether_addr(int s, u_long ipaddr, struct sockaddr_dl *hwaddr)
22053c9f6c0SAtsushi Murai {
22153c9f6c0SAtsushi Murai   struct ifreq *ifr, *ifend, *ifp;
22253c9f6c0SAtsushi Murai   u_long ina, mask;
22353c9f6c0SAtsushi Murai   struct sockaddr_dl *dla;
22453c9f6c0SAtsushi Murai   struct ifreq ifreq;
22553c9f6c0SAtsushi Murai   struct ifconf ifc;
22653c9f6c0SAtsushi Murai   struct ifreq ifs[MAX_IFS];
22753c9f6c0SAtsushi Murai 
22853c9f6c0SAtsushi Murai   ifc.ifc_len = sizeof(ifs);
22953c9f6c0SAtsushi Murai   ifc.ifc_req = ifs;
23053c9f6c0SAtsushi Murai   if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
231afc7fa2cSBrian Somers     LogPrintf(LogERROR, "get_ether_addr: ioctl(SIOCGIFCONF): %s\n",
232afc7fa2cSBrian Somers 	      strerror(errno));
23353c9f6c0SAtsushi Murai     return 0;
23453c9f6c0SAtsushi Murai   }
23553c9f6c0SAtsushi Murai 
23653c9f6c0SAtsushi Murai   /*
237944f7098SBrian Somers    * Scan through looking for an interface with an Internet address on the
238944f7098SBrian Somers    * same subnet as `ipaddr'.
23953c9f6c0SAtsushi Murai    */
24053c9f6c0SAtsushi Murai   ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
24153c9f6c0SAtsushi Murai   for (ifr = ifc.ifc_req; ifr < ifend;) {
24253c9f6c0SAtsushi Murai     if (ifr->ifr_addr.sa_family == AF_INET) {
24353c9f6c0SAtsushi Murai       ina = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr.s_addr;
24453c9f6c0SAtsushi Murai       strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
24599c02d39SWarner Losh       ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';
246944f7098SBrian Somers 
24753c9f6c0SAtsushi Murai       /*
248944f7098SBrian Somers        * Check that the interface is up, and not point-to-point or loopback.
24953c9f6c0SAtsushi Murai        */
25053c9f6c0SAtsushi Murai       if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
25153c9f6c0SAtsushi Murai 	continue;
25253c9f6c0SAtsushi Murai       if ((ifreq.ifr_flags &
25353c9f6c0SAtsushi Murai       (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP))
25453c9f6c0SAtsushi Murai 	  != (IFF_UP | IFF_BROADCAST))
25553c9f6c0SAtsushi Murai 	goto nextif;
256944f7098SBrian Somers 
25753c9f6c0SAtsushi Murai       /*
25853c9f6c0SAtsushi Murai        * Get its netmask and check that it's on the right subnet.
25953c9f6c0SAtsushi Murai        */
26053c9f6c0SAtsushi Murai       if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
26153c9f6c0SAtsushi Murai 	continue;
26253c9f6c0SAtsushi Murai       mask = ((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr.s_addr;
26353c9f6c0SAtsushi Murai       if ((ipaddr & mask) != (ina & mask))
26453c9f6c0SAtsushi Murai 	goto nextif;
26553c9f6c0SAtsushi Murai 
26653c9f6c0SAtsushi Murai       break;
26753c9f6c0SAtsushi Murai     }
26853c9f6c0SAtsushi Murai nextif:
26953c9f6c0SAtsushi Murai     ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len);
27053c9f6c0SAtsushi Murai   }
27153c9f6c0SAtsushi Murai 
27253c9f6c0SAtsushi Murai   if (ifr >= ifend)
27353c9f6c0SAtsushi Murai     return 0;
274927145beSBrian Somers   LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", ifr->ifr_name);
27553c9f6c0SAtsushi Murai 
27653c9f6c0SAtsushi Murai   /*
277944f7098SBrian Somers    * Now scan through again looking for a link-level address for this
278944f7098SBrian Somers    * interface.
27953c9f6c0SAtsushi Murai    */
28053c9f6c0SAtsushi Murai   ifp = ifr;
28153c9f6c0SAtsushi Murai   for (ifr = ifc.ifc_req; ifr < ifend;) {
28253c9f6c0SAtsushi Murai     if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
28353c9f6c0SAtsushi Murai 	&& ifr->ifr_addr.sa_family == AF_LINK) {
284944f7098SBrian Somers 
28553c9f6c0SAtsushi Murai       /*
28653c9f6c0SAtsushi Murai        * Found the link-level address - copy it out
28753c9f6c0SAtsushi Murai        */
28853c9f6c0SAtsushi Murai       dla = (struct sockaddr_dl *) & ifr->ifr_addr;
28975240ed1SBrian Somers       memcpy(hwaddr, dla, dla->sdl_len);
29053c9f6c0SAtsushi Murai       return 1;
29153c9f6c0SAtsushi Murai     }
29253c9f6c0SAtsushi Murai     ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len);
29353c9f6c0SAtsushi Murai   }
29453c9f6c0SAtsushi Murai 
29553c9f6c0SAtsushi Murai   return 0;
29653c9f6c0SAtsushi Murai }
29753c9f6c0SAtsushi Murai 
29853c9f6c0SAtsushi Murai 
29953c9f6c0SAtsushi Murai #ifdef DEBUG
30075240ed1SBrian Somers int
30153c9f6c0SAtsushi Murai main()
30253c9f6c0SAtsushi Murai {
30353c9f6c0SAtsushi Murai   u_long ipaddr;
30453c9f6c0SAtsushi Murai   int s;
30553c9f6c0SAtsushi Murai 
30653c9f6c0SAtsushi Murai   s = socket(AF_INET, SOCK_DGRAM, 0);
30753c9f6c0SAtsushi Murai   ipaddr = inet_addr("192.168.1.32");
30853c9f6c0SAtsushi Murai   sifproxyarp(s, ipaddr);
30953c9f6c0SAtsushi Murai   close(s);
31053c9f6c0SAtsushi Murai }
31153c9f6c0SAtsushi Murai #endif
312