xref: /freebsd/usr.sbin/ppp/iface.c (revision 152a439010a78a802130af6ed1f65e10bd210d8f)
18fa6ebe4SBrian Somers /*-
28fa6ebe4SBrian Somers  * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
38fa6ebe4SBrian Somers  * All rights reserved.
48fa6ebe4SBrian Somers  *
58fa6ebe4SBrian Somers  * Redistribution and use in source and binary forms, with or without
68fa6ebe4SBrian Somers  * modification, are permitted provided that the following conditions
78fa6ebe4SBrian Somers  * are met:
88fa6ebe4SBrian Somers  * 1. Redistributions of source code must retain the above copyright
98fa6ebe4SBrian Somers  *    notice, this list of conditions and the following disclaimer.
108fa6ebe4SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
118fa6ebe4SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
128fa6ebe4SBrian Somers  *    documentation and/or other materials provided with the distribution.
138fa6ebe4SBrian Somers  *
148fa6ebe4SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158fa6ebe4SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168fa6ebe4SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178fa6ebe4SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
188fa6ebe4SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198fa6ebe4SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
208fa6ebe4SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
218fa6ebe4SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228fa6ebe4SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
238fa6ebe4SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
248fa6ebe4SBrian Somers  * SUCH DAMAGE.
258fa6ebe4SBrian Somers  *
2697d92980SPeter Wemm  * $FreeBSD$
278fa6ebe4SBrian Somers  */
288fa6ebe4SBrian Somers 
29972a1bcfSBrian Somers #include <sys/param.h>
308fa6ebe4SBrian Somers #include <sys/socket.h>
318fa6ebe4SBrian Somers #include <netinet/in.h>
328fa6ebe4SBrian Somers #include <net/if.h>
338fa6ebe4SBrian Somers #include <net/if_dl.h>
348fa6ebe4SBrian Somers #include <net/route.h>
358fa6ebe4SBrian Somers #include <arpa/inet.h>
368fa6ebe4SBrian Somers #include <netinet/in_systm.h>
378fa6ebe4SBrian Somers #include <netinet/ip.h>
388fa6ebe4SBrian Somers #include <sys/un.h>
398fa6ebe4SBrian Somers 
40119386a3SBrian Somers #include <errno.h>
418fa6ebe4SBrian Somers #include <string.h>
428fa6ebe4SBrian Somers #include <stdio.h>
438fa6ebe4SBrian Somers #include <stdlib.h>
44119386a3SBrian Somers #include <sys/ioctl.h>
45119386a3SBrian Somers #include <sys/sysctl.h>
468fa6ebe4SBrian Somers #include <termios.h>
478fa6ebe4SBrian Somers #include <unistd.h>
488fa6ebe4SBrian Somers 
495d9e6103SBrian Somers #include "layer.h"
508fa6ebe4SBrian Somers #include "defs.h"
518fa6ebe4SBrian Somers #include "command.h"
528fa6ebe4SBrian Somers #include "mbuf.h"
538fa6ebe4SBrian Somers #include "log.h"
548fa6ebe4SBrian Somers #include "id.h"
558fa6ebe4SBrian Somers #include "timer.h"
568fa6ebe4SBrian Somers #include "fsm.h"
578fa6ebe4SBrian Somers #include "iplist.h"
588fa6ebe4SBrian Somers #include "lqr.h"
598fa6ebe4SBrian Somers #include "hdlc.h"
608fa6ebe4SBrian Somers #include "throughput.h"
618fa6ebe4SBrian Somers #include "slcompress.h"
628fa6ebe4SBrian Somers #include "descriptor.h"
638fa6ebe4SBrian Somers #include "ipcp.h"
641d1fc017SBrian Somers #include "filter.h"
658fa6ebe4SBrian Somers #include "lcp.h"
668fa6ebe4SBrian Somers #include "ccp.h"
678fa6ebe4SBrian Somers #include "link.h"
688fa6ebe4SBrian Somers #include "mp.h"
69972a1bcfSBrian Somers #ifndef NORADIUS
70972a1bcfSBrian Somers #include "radius.h"
71972a1bcfSBrian Somers #endif
728fa6ebe4SBrian Somers #include "bundle.h"
738fa6ebe4SBrian Somers #include "prompt.h"
748fa6ebe4SBrian Somers #include "iface.h"
758fa6ebe4SBrian Somers 
768fa6ebe4SBrian Somers 
778fa6ebe4SBrian Somers static int
788fa6ebe4SBrian Somers bitsinmask(struct in_addr mask)
798fa6ebe4SBrian Somers {
808fa6ebe4SBrian Somers   u_int32_t bitmask, maskaddr;
818fa6ebe4SBrian Somers   int bits;
828fa6ebe4SBrian Somers 
838fa6ebe4SBrian Somers   bitmask = 0xffffffff;
848fa6ebe4SBrian Somers   maskaddr = ntohl(mask.s_addr);
858fa6ebe4SBrian Somers   for (bits = 32; bits >= 0; bits--) {
868fa6ebe4SBrian Somers     if (maskaddr == bitmask)
878fa6ebe4SBrian Somers       break;
888fa6ebe4SBrian Somers     bitmask &= ~(1 << (32 - bits));
898fa6ebe4SBrian Somers   }
908fa6ebe4SBrian Somers 
918fa6ebe4SBrian Somers   return bits;
928fa6ebe4SBrian Somers }
938fa6ebe4SBrian Somers 
948fa6ebe4SBrian Somers struct iface *
958fa6ebe4SBrian Somers iface_Create(const char *name)
968fa6ebe4SBrian Somers {
97152a4390SBrian Somers   int mib[6], s, maxtries, err;
9858a57513SBrian Somers   size_t needed, namelen;
996b457978SBrian Somers   char *buf, *ptr, *end;
1008fa6ebe4SBrian Somers   struct if_msghdr *ifm;
1018fa6ebe4SBrian Somers   struct ifa_msghdr *ifam;
1028fa6ebe4SBrian Somers   struct sockaddr_dl *dl;
1036b457978SBrian Somers   struct sockaddr *sa[RTAX_MAX];
1048fa6ebe4SBrian Somers   struct iface *iface;
1058fa6ebe4SBrian Somers   struct iface_addr *addr;
1068fa6ebe4SBrian Somers 
1078fa6ebe4SBrian Somers   s = socket(AF_INET, SOCK_DGRAM, 0);
1088fa6ebe4SBrian Somers   if (s < 0) {
1098fa6ebe4SBrian Somers     fprintf(stderr, "iface_Create: socket(): %s\n", strerror(errno));
1108fa6ebe4SBrian Somers     return NULL;
1118fa6ebe4SBrian Somers   }
1128fa6ebe4SBrian Somers 
1138fa6ebe4SBrian Somers   mib[0] = CTL_NET;
1148fa6ebe4SBrian Somers   mib[1] = PF_ROUTE;
1158fa6ebe4SBrian Somers   mib[2] = 0;
1168fa6ebe4SBrian Somers   mib[3] = 0;
1178fa6ebe4SBrian Somers   mib[4] = NET_RT_IFLIST;
1188fa6ebe4SBrian Somers   mib[5] = 0;
1198fa6ebe4SBrian Somers 
120152a4390SBrian Somers   maxtries = 20;
121152a4390SBrian Somers   err = 0;
122152a4390SBrian Somers   do {
123152a4390SBrian Somers     if (maxtries-- == 0 || (err && err != ENOMEM)) {
124152a4390SBrian Somers       fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
125152a4390SBrian Somers       close(s);
126152a4390SBrian Somers       return NULL;
127152a4390SBrian Somers     }
128152a4390SBrian Somers 
1298fa6ebe4SBrian Somers     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
130c0593e34SBrian Somers       fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
1318fa6ebe4SBrian Somers                 strerror(errno));
1328fa6ebe4SBrian Somers       close(s);
1338fa6ebe4SBrian Somers       return NULL;
1348fa6ebe4SBrian Somers     }
1358fa6ebe4SBrian Somers 
1368fa6ebe4SBrian Somers     if ((buf = (char *)malloc(needed)) == NULL) {
137c0593e34SBrian Somers       fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
1388fa6ebe4SBrian Somers       close(s);
1398fa6ebe4SBrian Somers       return NULL;
1408fa6ebe4SBrian Somers     }
1418fa6ebe4SBrian Somers 
1428fa6ebe4SBrian Somers     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
143152a4390SBrian Somers       err = errno;
1448fa6ebe4SBrian Somers       free(buf);
145152a4390SBrian Somers       buf = NULL;
1468fa6ebe4SBrian Somers     }
147152a4390SBrian Somers   } while (buf == NULL);
1488fa6ebe4SBrian Somers 
1498fa6ebe4SBrian Somers   ptr = buf;
1508fa6ebe4SBrian Somers   end = buf + needed;
1518fa6ebe4SBrian Somers   iface = NULL;
15258a57513SBrian Somers   namelen = strlen(name);
1538fa6ebe4SBrian Somers 
1548fa6ebe4SBrian Somers   while (ptr < end && iface == NULL) {
1558fa6ebe4SBrian Somers     ifm = (struct if_msghdr *)ptr;			/* On if_msghdr */
1568fa6ebe4SBrian Somers     if (ifm->ifm_type != RTM_IFINFO)
1578fa6ebe4SBrian Somers       break;
1588fa6ebe4SBrian Somers     dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
15958a57513SBrian Somers     if (dl->sdl_nlen == namelen && !strncmp(name, dl->sdl_data, namelen)) {
1608fa6ebe4SBrian Somers       iface = (struct iface *)malloc(sizeof *iface);
1618fa6ebe4SBrian Somers       if (iface == NULL) {
1628fa6ebe4SBrian Somers         fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
1638fa6ebe4SBrian Somers         return NULL;
1648fa6ebe4SBrian Somers       }
1658fa6ebe4SBrian Somers       iface->name = strdup(name);
1668fa6ebe4SBrian Somers       iface->flags = ifm->ifm_flags;
1678fa6ebe4SBrian Somers       iface->index = ifm->ifm_index;
1688fa6ebe4SBrian Somers       iface->in_addrs = 0;
1698fa6ebe4SBrian Somers       iface->in_addr = NULL;
1708fa6ebe4SBrian Somers     }
1718fa6ebe4SBrian Somers     ptr += ifm->ifm_msglen;				/* First ifa_msghdr */
1728fa6ebe4SBrian Somers     for (; ptr < end; ptr += ifam->ifam_msglen) {
1738fa6ebe4SBrian Somers       ifam = (struct ifa_msghdr *)ptr;			/* Next if address */
1748fa6ebe4SBrian Somers 
1758fa6ebe4SBrian Somers       if (ifam->ifam_type != RTM_NEWADDR)		/* finished this if */
1768fa6ebe4SBrian Somers         break;
1778fa6ebe4SBrian Somers 
1786b457978SBrian Somers       if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
1796b457978SBrian Somers         /* Found a configured interface ! */
1806b457978SBrian Somers         iface_ParseHdr(ifam, sa);
1818fa6ebe4SBrian Somers 
1826b457978SBrian Somers         if (sa[RTAX_IFA] && sa[RTAX_IFA]->sa_family == AF_INET) {
1836b457978SBrian Somers           /* Record the address */
1848fa6ebe4SBrian Somers 
1858fa6ebe4SBrian Somers           addr = (struct iface_addr *)realloc
1868fa6ebe4SBrian Somers             (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
1878fa6ebe4SBrian Somers           if (addr == NULL)
1888fa6ebe4SBrian Somers             break;
1898fa6ebe4SBrian Somers           iface->in_addr = addr;
1908fa6ebe4SBrian Somers 
1918fa6ebe4SBrian Somers           addr += iface->in_addrs;
1928fa6ebe4SBrian Somers           iface->in_addrs++;
1938fa6ebe4SBrian Somers 
1946b457978SBrian Somers           addr->ifa = ((struct sockaddr_in *)sa[RTAX_IFA])->sin_addr;
1956b457978SBrian Somers 
1966b457978SBrian Somers           if (sa[RTAX_BRD])
1976b457978SBrian Somers             addr->brd = ((struct sockaddr_in *)sa[RTAX_BRD])->sin_addr;
1986b457978SBrian Somers           else
1996b457978SBrian Somers             addr->brd.s_addr = INADDR_ANY;
2006b457978SBrian Somers 
2016b457978SBrian Somers           if (sa[RTAX_NETMASK])
2026b457978SBrian Somers             addr->mask = ((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr;
2036b457978SBrian Somers           else
2046b457978SBrian Somers             addr->mask.s_addr = INADDR_ANY;
2058fa6ebe4SBrian Somers 
2068fa6ebe4SBrian Somers           addr->bits = bitsinmask(addr->mask);
2078fa6ebe4SBrian Somers         }
2088fa6ebe4SBrian Somers       }
2098fa6ebe4SBrian Somers     }
2108fa6ebe4SBrian Somers   }
2118fa6ebe4SBrian Somers 
2128fa6ebe4SBrian Somers   free(buf);
2138fa6ebe4SBrian Somers   close(s);
2148fa6ebe4SBrian Somers 
2158fa6ebe4SBrian Somers   return iface;
2168fa6ebe4SBrian Somers }
2178fa6ebe4SBrian Somers 
2188fa6ebe4SBrian Somers static void
2198fa6ebe4SBrian Somers iface_addr_Zap(const char *name, struct iface_addr *addr)
2208fa6ebe4SBrian Somers {
2218fa6ebe4SBrian Somers   struct ifaliasreq ifra;
2228fa6ebe4SBrian Somers   struct sockaddr_in *me, *peer;
2238fa6ebe4SBrian Somers   int s;
2248fa6ebe4SBrian Somers 
2258fa6ebe4SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
2268fa6ebe4SBrian Somers   if (s < 0)
2278fa6ebe4SBrian Somers     log_Printf(LogERROR, "iface_addr_Zap: socket(): %s\n", strerror(errno));
2288fa6ebe4SBrian Somers   else {
2298fa6ebe4SBrian Somers     memset(&ifra, '\0', sizeof ifra);
2308fa6ebe4SBrian Somers     strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
2318fa6ebe4SBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
2328fa6ebe4SBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
2338fa6ebe4SBrian Somers     me->sin_family = peer->sin_family = AF_INET;
2348fa6ebe4SBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
2358fa6ebe4SBrian Somers     me->sin_addr = addr->ifa;
2368fa6ebe4SBrian Somers     peer->sin_addr = addr->brd;
23717871c5fSBrian Somers     log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(addr->ifa));
2388fa6ebe4SBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
2398fa6ebe4SBrian Somers       log_Printf(LogWARN, "iface_addr_Zap: ioctl(SIOCDIFADDR, %s): %s\n",
2408fa6ebe4SBrian Somers                  inet_ntoa(addr->ifa), strerror(errno));
2418fa6ebe4SBrian Somers     close(s);
2428fa6ebe4SBrian Somers   }
2438fa6ebe4SBrian Somers }
2448fa6ebe4SBrian Somers 
2458fa6ebe4SBrian Somers void
2468fa6ebe4SBrian Somers iface_inClear(struct iface *iface, int how)
2478fa6ebe4SBrian Somers {
2488fa6ebe4SBrian Somers   int n, addrs;
2498fa6ebe4SBrian Somers 
250278657c3SBrian Somers   if (iface->in_addrs) {
2518fa6ebe4SBrian Somers     addrs = n = how == IFACE_CLEAR_ALL ? 0 : 1;
2528fa6ebe4SBrian Somers     for (; n < iface->in_addrs; n++)
2538fa6ebe4SBrian Somers       iface_addr_Zap(iface->name, iface->in_addr + n);
2548fa6ebe4SBrian Somers 
2558fa6ebe4SBrian Somers     iface->in_addrs = addrs;
2568fa6ebe4SBrian Somers     /* Don't bother realloc()ing - we have little to gain */
2578fa6ebe4SBrian Somers   }
258278657c3SBrian Somers }
2598fa6ebe4SBrian Somers 
2608fa6ebe4SBrian Somers int
2618fa6ebe4SBrian Somers iface_inAdd(struct iface *iface, struct in_addr ifa, struct in_addr mask,
2628fa6ebe4SBrian Somers             struct in_addr brd, int how)
2638fa6ebe4SBrian Somers {
26416004197SBrian Somers   int slot, s, chg, nochange;
2658fa6ebe4SBrian Somers   struct ifaliasreq ifra;
2668fa6ebe4SBrian Somers   struct sockaddr_in *me, *peer, *msk;
2678fa6ebe4SBrian Somers   struct iface_addr *addr;
2688fa6ebe4SBrian Somers 
2698fa6ebe4SBrian Somers   for (slot = 0; slot < iface->in_addrs; slot++)
2708fa6ebe4SBrian Somers     if (iface->in_addr[slot].ifa.s_addr == ifa.s_addr) {
2718fa6ebe4SBrian Somers       if (how & IFACE_FORCE_ADD)
2728fa6ebe4SBrian Somers         break;
2738fa6ebe4SBrian Somers       else
2748fa6ebe4SBrian Somers         /* errno = EEXIST; */
2758fa6ebe4SBrian Somers         return 0;
2768fa6ebe4SBrian Somers     }
2778fa6ebe4SBrian Somers 
2788fa6ebe4SBrian Somers   addr = (struct iface_addr *)realloc
2798fa6ebe4SBrian Somers     (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
2808fa6ebe4SBrian Somers   if (addr == NULL) {
2818fa6ebe4SBrian Somers     log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
2828fa6ebe4SBrian Somers     return 0;
2838fa6ebe4SBrian Somers   }
2848fa6ebe4SBrian Somers   iface->in_addr = addr;
2858fa6ebe4SBrian Somers 
28617871c5fSBrian Somers   /*
28717871c5fSBrian Somers    * We've gotta be careful here.  If we try to add an address with the
28817871c5fSBrian Somers    * same destination as an existing interface, nothing will work.
28917871c5fSBrian Somers    * Instead, we tweak all previous address entries that match the
29017871c5fSBrian Somers    * to-be-added destination to 255.255.255.255 (w/ a similar netmask).
29117871c5fSBrian Somers    * There *may* be more than one - if the user has ``iface add''ed
29217871c5fSBrian Somers    * stuff previously.
29317871c5fSBrian Somers    */
29416004197SBrian Somers   nochange = 0;
29516004197SBrian Somers   s = -1;
29617871c5fSBrian Somers   for (chg = 0; chg < iface->in_addrs; chg++) {
29717871c5fSBrian Somers     if ((iface->in_addr[chg].brd.s_addr == brd.s_addr &&
29817871c5fSBrian Somers          brd.s_addr != INADDR_BROADCAST) || chg == slot) {
29916004197SBrian Somers       /*
30016004197SBrian Somers        * If we've found an entry that exactly matches what we want to add,
30116004197SBrian Somers        * don't remove it and then add it again.  If we do, it's possible
30216004197SBrian Somers        * that the kernel will (correctly) ``tidy up'' any routes that use
30316004197SBrian Somers        * the IP number as a destination.
30416004197SBrian Somers        */
30516004197SBrian Somers       if (chg == slot && iface->in_addr[chg].mask.s_addr == mask.s_addr) {
30616004197SBrian Somers         nochange = 1;
30716004197SBrian Somers         continue;
30816004197SBrian Somers       }
30916004197SBrian Somers       if (s == -1 && (s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
31016004197SBrian Somers         log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
31116004197SBrian Somers         return 0;
31216004197SBrian Somers       }
31316004197SBrian Somers 
3148fa6ebe4SBrian Somers       memset(&ifra, '\0', sizeof ifra);
3158fa6ebe4SBrian Somers       strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
3168fa6ebe4SBrian Somers       me = (struct sockaddr_in *)&ifra.ifra_addr;
3178fa6ebe4SBrian Somers       msk = (struct sockaddr_in *)&ifra.ifra_mask;
3188fa6ebe4SBrian Somers       peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
3198fa6ebe4SBrian Somers       me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
3208fa6ebe4SBrian Somers       me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
32117871c5fSBrian Somers       me->sin_addr = iface->in_addr[chg].ifa;
32217871c5fSBrian Somers       msk->sin_addr = iface->in_addr[chg].mask;
32317871c5fSBrian Somers       peer->sin_addr = iface->in_addr[chg].brd;
32417871c5fSBrian Somers       log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(me->sin_addr));
32517871c5fSBrian Somers       ID0ioctl(s, SIOCDIFADDR, &ifra);	/* Don't care if it fails... */
32617871c5fSBrian Somers       if (chg != slot) {
32717871c5fSBrian Somers         peer->sin_addr.s_addr = iface->in_addr[chg].brd.s_addr =
32817871c5fSBrian Somers           msk->sin_addr.s_addr = iface->in_addr[chg].mask.s_addr =
32917871c5fSBrian Somers             INADDR_BROADCAST;
33017871c5fSBrian Somers         iface->in_addr[chg].bits = 32;
33117871c5fSBrian Somers         log_Printf(LogDEBUG, "Add %s -> 255.255.255.255\n",
33217871c5fSBrian Somers                    inet_ntoa(me->sin_addr));
33317871c5fSBrian Somers         if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && errno != EEXIST) {
33417871c5fSBrian Somers           /* Oops - that's bad(ish) news !  We've lost an alias ! */
33517871c5fSBrian Somers           log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
33617871c5fSBrian Somers                inet_ntoa(me->sin_addr), strerror(errno));
33717871c5fSBrian Somers           iface->in_addrs--;
33817871c5fSBrian Somers           bcopy(iface->in_addr + chg + 1, iface->in_addr + chg,
33917871c5fSBrian Somers                 (iface->in_addrs - chg) * sizeof iface->in_addr[0]);
34017871c5fSBrian Somers           if (slot > chg)
34117871c5fSBrian Somers             slot--;
34217871c5fSBrian Somers           chg--;
34317871c5fSBrian Somers         }
34417871c5fSBrian Somers       }
34517871c5fSBrian Somers     }
34617871c5fSBrian Somers   }
3478fa6ebe4SBrian Somers 
34816004197SBrian Somers   if (!nochange) {
34916004197SBrian Somers     if (s == -1 && (s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
35016004197SBrian Somers       log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
35116004197SBrian Somers       return 0;
35216004197SBrian Somers     }
35317871c5fSBrian Somers     memset(&ifra, '\0', sizeof ifra);
35417871c5fSBrian Somers     strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
35517871c5fSBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
35617871c5fSBrian Somers     msk = (struct sockaddr_in *)&ifra.ifra_mask;
35717871c5fSBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
35817871c5fSBrian Somers     me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
35917871c5fSBrian Somers     me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
3608fa6ebe4SBrian Somers     me->sin_addr = ifa;
3618fa6ebe4SBrian Somers     msk->sin_addr = mask;
3628fa6ebe4SBrian Somers     peer->sin_addr = brd;
3638fa6ebe4SBrian Somers 
36417871c5fSBrian Somers     if (log_IsKept(LogDEBUG)) {
36517871c5fSBrian Somers       char buf[16];
36617871c5fSBrian Somers 
36717871c5fSBrian Somers       strncpy(buf, inet_ntoa(brd), sizeof buf-1);
36817871c5fSBrian Somers       buf[sizeof buf - 1] = '\0';
36917871c5fSBrian Somers       log_Printf(LogDEBUG, "Add %s -> %s\n", inet_ntoa(ifa), buf);
37017871c5fSBrian Somers     }
37117871c5fSBrian Somers 
37217871c5fSBrian Somers     /* An EEXIST failure w/ brd == INADDR_BROADCAST is ok (and works!) */
37317871c5fSBrian Somers     if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 &&
37417871c5fSBrian Somers         (brd.s_addr != INADDR_BROADCAST || errno != EEXIST)) {
37517871c5fSBrian Somers       log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
37617871c5fSBrian Somers                  inet_ntoa(ifa), strerror(errno));
37717871c5fSBrian Somers       ID0ioctl(s, SIOCDIFADDR, &ifra);	/* EEXIST ? */
3788fa6ebe4SBrian Somers       close(s);
3798fa6ebe4SBrian Somers       return 0;
3808fa6ebe4SBrian Somers     }
38116004197SBrian Somers   }
38216004197SBrian Somers 
38316004197SBrian Somers   if (s != -1)
3848fa6ebe4SBrian Somers     close(s);
3858fa6ebe4SBrian Somers 
3868fa6ebe4SBrian Somers   if (slot == iface->in_addrs) {
3878fa6ebe4SBrian Somers     /* We're adding a new interface address */
3888fa6ebe4SBrian Somers 
3898fa6ebe4SBrian Somers     if (how & IFACE_ADD_FIRST) {
3908fa6ebe4SBrian Somers       /* Stuff it at the start of our list */
3918fa6ebe4SBrian Somers       slot = 0;
3928fa6ebe4SBrian Somers       bcopy(iface->in_addr, iface->in_addr + 1,
3938fa6ebe4SBrian Somers             iface->in_addrs * sizeof iface->in_addr[0]);
3948fa6ebe4SBrian Somers     }
3958fa6ebe4SBrian Somers 
3968fa6ebe4SBrian Somers     iface->in_addrs++;
3978fa6ebe4SBrian Somers   } else if (how & IFACE_ADD_FIRST) {
3988fa6ebe4SBrian Somers     /* Shift it up to the first slot */
3998fa6ebe4SBrian Somers     bcopy(iface->in_addr, iface->in_addr + 1, slot * sizeof iface->in_addr[0]);
4008fa6ebe4SBrian Somers     slot = 0;
4018fa6ebe4SBrian Somers   }
4028fa6ebe4SBrian Somers 
4038fa6ebe4SBrian Somers   iface->in_addr[slot].ifa = ifa;
4048fa6ebe4SBrian Somers   iface->in_addr[slot].mask = mask;
4058fa6ebe4SBrian Somers   iface->in_addr[slot].brd = brd;
4068fa6ebe4SBrian Somers   iface->in_addr[slot].bits = bitsinmask(iface->in_addr[slot].mask);
4078fa6ebe4SBrian Somers 
4088fa6ebe4SBrian Somers   return 1;
4098fa6ebe4SBrian Somers }
4108fa6ebe4SBrian Somers 
4118fa6ebe4SBrian Somers int
4128fa6ebe4SBrian Somers iface_inDelete(struct iface *iface, struct in_addr ip)
4138fa6ebe4SBrian Somers {
4148fa6ebe4SBrian Somers   int n;
4158fa6ebe4SBrian Somers 
4168fa6ebe4SBrian Somers   for (n = 0; n < iface->in_addrs; n++)
4178fa6ebe4SBrian Somers     if (iface->in_addr[n].ifa.s_addr == ip.s_addr) {
4188fa6ebe4SBrian Somers       iface_addr_Zap(iface->name, iface->in_addr + n);
4198fa6ebe4SBrian Somers       bcopy(iface->in_addr + n + 1, iface->in_addr + n,
4208fa6ebe4SBrian Somers             (iface->in_addrs - n - 1) * sizeof iface->in_addr[0]);
4218fa6ebe4SBrian Somers       iface->in_addrs--;
4228fa6ebe4SBrian Somers       return 1;
4238fa6ebe4SBrian Somers     }
4248fa6ebe4SBrian Somers 
4258fa6ebe4SBrian Somers   return 0;
4268fa6ebe4SBrian Somers }
4278fa6ebe4SBrian Somers 
4284e5196e9SBrian Somers #define IFACE_ADDFLAGS 1
4294e5196e9SBrian Somers #define IFACE_DELFLAGS 2
4304e5196e9SBrian Somers 
4314e5196e9SBrian Somers static int
432dc744e19SBrian Somers iface_ChangeFlags(const char *ifname, int flags, int how)
4334e5196e9SBrian Somers {
4344e5196e9SBrian Somers   struct ifreq ifrq;
4354e5196e9SBrian Somers   int s;
4364e5196e9SBrian Somers 
4374e5196e9SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
4384e5196e9SBrian Somers   if (s < 0) {
43953dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno));
4404e5196e9SBrian Somers     return 0;
4414e5196e9SBrian Somers   }
4424e5196e9SBrian Somers 
4434e5196e9SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
444dc744e19SBrian Somers   strncpy(ifrq.ifr_name, ifname, sizeof ifrq.ifr_name - 1);
4454e5196e9SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
4464e5196e9SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
44753dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
4484e5196e9SBrian Somers        strerror(errno));
4494e5196e9SBrian Somers     close(s);
4504e5196e9SBrian Somers     return 0;
4514e5196e9SBrian Somers   }
4524e5196e9SBrian Somers 
4534e5196e9SBrian Somers   if (how == IFACE_ADDFLAGS)
4544e5196e9SBrian Somers     ifrq.ifr_flags |= flags;
4554e5196e9SBrian Somers   else
4564e5196e9SBrian Somers     ifrq.ifr_flags &= ~flags;
4574e5196e9SBrian Somers 
4584e5196e9SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
45953dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
4604e5196e9SBrian Somers        strerror(errno));
4614e5196e9SBrian Somers     close(s);
4624e5196e9SBrian Somers     return 0;
4634e5196e9SBrian Somers   }
4644e5196e9SBrian Somers   close(s);
4654e5196e9SBrian Somers 
4664e5196e9SBrian Somers   return 1;	/* Success */
4674e5196e9SBrian Somers }
4684e5196e9SBrian Somers 
4694e5196e9SBrian Somers int
470dc744e19SBrian Somers iface_SetFlags(const char *ifname, int flags)
4714e5196e9SBrian Somers {
472dc744e19SBrian Somers   return iface_ChangeFlags(ifname, flags, IFACE_ADDFLAGS);
4734e5196e9SBrian Somers }
4744e5196e9SBrian Somers 
4754e5196e9SBrian Somers int
476dc744e19SBrian Somers iface_ClearFlags(const char *ifname, int flags)
4774e5196e9SBrian Somers {
478dc744e19SBrian Somers   return iface_ChangeFlags(ifname, flags, IFACE_DELFLAGS);
4794e5196e9SBrian Somers }
4804e5196e9SBrian Somers 
4818fa6ebe4SBrian Somers void
4828fa6ebe4SBrian Somers iface_Destroy(struct iface *iface)
4838fa6ebe4SBrian Somers {
4848fa6ebe4SBrian Somers   /*
4858fa6ebe4SBrian Somers    * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
4868fa6ebe4SBrian Somers    * if that's what the user wants.  It's better to leave the interface
4878fa6ebe4SBrian Somers    * allocated so that existing connections can continue to work.
4888fa6ebe4SBrian Somers    */
4898fa6ebe4SBrian Somers 
4908fa6ebe4SBrian Somers   if (iface != NULL) {
4918fa6ebe4SBrian Somers     free(iface->name);
4928fa6ebe4SBrian Somers     free(iface->in_addr);
4938fa6ebe4SBrian Somers     free(iface);
4948fa6ebe4SBrian Somers   }
4958fa6ebe4SBrian Somers }
4968fa6ebe4SBrian Somers 
4978fa6ebe4SBrian Somers #define if_entry(x) { IFF_##x, #x }
4988fa6ebe4SBrian Somers 
4998fa6ebe4SBrian Somers struct {
5008fa6ebe4SBrian Somers   int flag;
5018fa6ebe4SBrian Somers   const char *value;
5028fa6ebe4SBrian Somers } if_flags[] = {
5038fa6ebe4SBrian Somers   if_entry(UP),
5048fa6ebe4SBrian Somers   if_entry(BROADCAST),
5058fa6ebe4SBrian Somers   if_entry(DEBUG),
5068fa6ebe4SBrian Somers   if_entry(LOOPBACK),
5078fa6ebe4SBrian Somers   if_entry(POINTOPOINT),
5088fa6ebe4SBrian Somers   if_entry(RUNNING),
5098fa6ebe4SBrian Somers   if_entry(NOARP),
5108fa6ebe4SBrian Somers   if_entry(PROMISC),
5118fa6ebe4SBrian Somers   if_entry(ALLMULTI),
5128fa6ebe4SBrian Somers   if_entry(OACTIVE),
5138fa6ebe4SBrian Somers   if_entry(SIMPLEX),
5148fa6ebe4SBrian Somers   if_entry(LINK0),
5158fa6ebe4SBrian Somers   if_entry(LINK1),
5168fa6ebe4SBrian Somers   if_entry(LINK2),
5178fa6ebe4SBrian Somers   if_entry(MULTICAST),
5188fa6ebe4SBrian Somers   { 0, "???" }
5198fa6ebe4SBrian Somers };
5208fa6ebe4SBrian Somers 
5218fa6ebe4SBrian Somers int
5228fa6ebe4SBrian Somers iface_Show(struct cmdargs const *arg)
5238fa6ebe4SBrian Somers {
5248fa6ebe4SBrian Somers   struct iface *iface = arg->bundle->iface, *current;
5258fa6ebe4SBrian Somers   int f, flags;
5268fa6ebe4SBrian Somers 
5278fa6ebe4SBrian Somers   current = iface_Create(iface->name);
5288fa6ebe4SBrian Somers   flags = iface->flags = current->flags;
5298fa6ebe4SBrian Somers   iface_Destroy(current);
5308fa6ebe4SBrian Somers 
5318fa6ebe4SBrian Somers   prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
5328fa6ebe4SBrian Somers   for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
5338fa6ebe4SBrian Somers     if ((if_flags[f].flag & flags) || (!if_flags[f].flag && flags)) {
5348fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
5358fa6ebe4SBrian Somers                     if_flags[f].value);
5368fa6ebe4SBrian Somers       flags &= ~if_flags[f].flag;
5378fa6ebe4SBrian Somers     }
538723aebe8SBrian Somers   prompt_Printf(arg->prompt, "> mtu %d has %d address%s:\n", arg->bundle->mtu,
539723aebe8SBrian Somers                 iface->in_addrs, iface->in_addrs == 1 ? "" : "es");
5408fa6ebe4SBrian Somers 
5418fa6ebe4SBrian Somers   for (f = 0; f < iface->in_addrs; f++) {
5428fa6ebe4SBrian Somers     prompt_Printf(arg->prompt, "  %s", inet_ntoa(iface->in_addr[f].ifa));
5438fa6ebe4SBrian Somers     if (iface->in_addr[f].bits >= 0)
5448fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, "/%d", iface->in_addr[f].bits);
5458fa6ebe4SBrian Somers     if (iface->flags & IFF_POINTOPOINT)
5468fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, " -> %s", inet_ntoa(iface->in_addr[f].brd));
5478fa6ebe4SBrian Somers     else if (iface->flags & IFF_BROADCAST)
5488fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, " broadcast %s",
5498fa6ebe4SBrian Somers                     inet_ntoa(iface->in_addr[f].brd));
5508fa6ebe4SBrian Somers     if (iface->in_addr[f].bits < 0)
5518fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, " (mask %s)",
5528fa6ebe4SBrian Somers                     inet_ntoa(iface->in_addr[f].mask));
5538fa6ebe4SBrian Somers     prompt_Printf(arg->prompt, "\n");
5548fa6ebe4SBrian Somers   }
5558fa6ebe4SBrian Somers 
5568fa6ebe4SBrian Somers   return 0;
5578fa6ebe4SBrian Somers }
5586b457978SBrian Somers 
5596b457978SBrian Somers void
5606b457978SBrian Somers iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])
5616b457978SBrian Somers {
5626b457978SBrian Somers   char *wp;
5636b457978SBrian Somers   int rtax;
5646b457978SBrian Somers 
5656b457978SBrian Somers   wp = (char *)(ifam + 1);
5666b457978SBrian Somers 
5676b457978SBrian Somers   for (rtax = 0; rtax < RTAX_MAX; rtax++)
5686b457978SBrian Somers     if (ifam->ifam_addrs & (1 << rtax)) {
5696b457978SBrian Somers       sa[rtax] = (struct sockaddr *)wp;
5706b457978SBrian Somers       wp += ROUNDUP(sa[rtax]->sa_len);
5716b457978SBrian Somers     } else
5726b457978SBrian Somers       sa[rtax] = NULL;
5736b457978SBrian Somers }
574