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