Home | History | Annotate | Line # | Download | only in ifconfig
af_inet.c revision 1.5
      1 /*	$NetBSD: af_inet.c,v 1.5 2006/11/13 05:13:39 dyoung Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1993
      5  *      The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 __RCSID("$NetBSD: af_inet.c,v 1.5 2006/11/13 05:13:39 dyoung Exp $");
     35 #endif /* not lint */
     36 
     37 #include <sys/param.h>
     38 #include <sys/ioctl.h>
     39 #include <sys/socket.h>
     40 
     41 #include <net/if.h>
     42 #include <netinet/in.h>
     43 #include <netinet/in_var.h>
     44 
     45 #include <arpa/inet.h>
     46 
     47 #include <err.h>
     48 #include <errno.h>
     49 #include <ifaddrs.h>
     50 #include <netdb.h>
     51 #include <string.h>
     52 #include <stdlib.h>
     53 #include <stdio.h>
     54 #include <util.h>
     55 
     56 #include "extern.h"
     57 #include "af_inet.h"
     58 
     59 static void in_preference(const char *, const struct sockaddr *);
     60 
     61 struct in_aliasreq in_addreq;
     62 
     63 int	setipdst;
     64 
     65 void
     66 setifipdst(const char *addr, int d)
     67 {
     68 
     69 	in_getaddr(addr, DSTADDR);
     70 	setipdst++;
     71 	clearaddr = 0;
     72 	newaddr = 0;
     73 }
     74 
     75 void
     76 in_alias(struct ifreq *creq)
     77 {
     78 	struct sockaddr_in *iasin;
     79 	int alias;
     80 
     81 	if (lflag)
     82 		return;
     83 
     84 	alias = 1;
     85 
     86 	/* Get the non-alias address for this interface. */
     87 	getsock(AF_INET);
     88 	if (s < 0) {
     89 		if (errno == EAFNOSUPPORT)
     90 			return;
     91 		err(EXIT_FAILURE, "socket");
     92 	}
     93 	(void) memset(&ifr, 0, sizeof(ifr));
     94 	estrlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
     95 	if (ioctl(s, SIOCGIFADDR, &ifr) == -1) {
     96 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
     97 			return;
     98 		} else
     99 			warn("SIOCGIFADDR");
    100 	}
    101 	/* If creq and ifr are the same address, this is not an alias. */
    102 	if (memcmp(&ifr.ifr_addr, &creq->ifr_addr,
    103 		   sizeof(creq->ifr_addr)) == 0)
    104 		alias = 0;
    105 	(void) memset(&in_addreq, 0, sizeof(in_addreq));
    106 	estrlcpy(in_addreq.ifra_name, name, sizeof(in_addreq.ifra_name));
    107 	memcpy(&in_addreq.ifra_addr, &creq->ifr_addr,
    108 	    sizeof(in_addreq.ifra_addr));
    109 	if (ioctl(s, SIOCGIFALIAS, &in_addreq) == -1) {
    110 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
    111 			return;
    112 		} else
    113 			warn("SIOCGIFALIAS");
    114 	}
    115 
    116 	iasin = &in_addreq.ifra_addr;
    117 	printf("\tinet %s%s", alias ? "alias " : "", inet_ntoa(iasin->sin_addr));
    118 
    119 	if (flags & IFF_POINTOPOINT) {
    120 		iasin = &in_addreq.ifra_dstaddr;
    121 		printf(" -> %s", inet_ntoa(iasin->sin_addr));
    122 	}
    123 
    124 	iasin = &in_addreq.ifra_mask;
    125 	printf(" netmask 0x%x", ntohl(iasin->sin_addr.s_addr));
    126 
    127 	if (flags & IFF_BROADCAST) {
    128 		iasin = &in_addreq.ifra_broadaddr;
    129 		printf(" broadcast %s", inet_ntoa(iasin->sin_addr));
    130 	}
    131 }
    132 
    133 static uint16_t
    134 in_get_preference(const char *ifname, const struct sockaddr *sa)
    135 {
    136 	struct if_addrprefreq ifap;
    137 
    138 	getsock(AF_INET);
    139 	if (s < 0) {
    140 		if (errno == EPROTONOSUPPORT)
    141 			return 0;
    142 		err(EXIT_FAILURE, "socket");
    143 	}
    144 	(void)memset(&ifap, 0, sizeof(ifap));
    145 	(void)strncpy(ifap.ifap_name, name, sizeof(ifap.ifap_name));
    146 	(void)memcpy(&ifap.ifap_addr, sa,
    147 	    MIN(sizeof(ifap.ifap_addr), sa->sa_len));
    148 	if (ioctl(s, SIOCGIFADDRPREF, &ifap) == -1) {
    149 		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
    150 			return 0;
    151 		warn("SIOCGIFADDRPREF");
    152 	}
    153 	return ifap.ifap_preference;
    154 }
    155 
    156 static void
    157 in_preference(const char *ifname, const struct sockaddr *sa)
    158 {
    159 	uint16_t preference;
    160 
    161 	if (lflag)
    162 		return;
    163 
    164 	preference = in_get_preference(ifname, sa);
    165 	printf(" preference %" PRIu16, preference);
    166 }
    167 
    168 void
    169 in_status(int force)
    170 {
    171 	struct ifaddrs *ifap, *ifa;
    172 	struct ifreq isifr;
    173 	int printprefs = 0;
    174 
    175 	if (getifaddrs(&ifap) != 0)
    176 		err(EXIT_FAILURE, "getifaddrs");
    177 	/* Print address preference numbers if any address has a non-zero
    178 	 * preference assigned.
    179 	 */
    180 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    181 		if (strcmp(name, ifa->ifa_name) != 0)
    182 			continue;
    183 		if (ifa->ifa_addr->sa_family != AF_INET)
    184 			continue;
    185 		if (in_get_preference(ifa->ifa_name, ifa->ifa_addr) != 0) {
    186 			printprefs = 1;
    187 			break;
    188 		}
    189 	}
    190 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    191 		if (strcmp(name, ifa->ifa_name) != 0)
    192 			continue;
    193 		if (ifa->ifa_addr->sa_family != AF_INET)
    194 			continue;
    195 		if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len)
    196 			continue;
    197 
    198 		memset(&isifr, 0, sizeof(isifr));
    199 		estrlcpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name));
    200 		memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
    201 		in_alias(&isifr);
    202 		if (printprefs)
    203 			in_preference(ifa->ifa_name, ifa->ifa_addr);
    204 		printf("\n");
    205 	}
    206 	if (ifa != NULL) {
    207 		for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    208 			if (strcmp(name, ifa->ifa_name) != 0)
    209 				continue;
    210 			if (ifa->ifa_addr->sa_family != AF_INET)
    211 				continue;
    212 		}
    213 	}
    214 	freeifaddrs(ifap);
    215 }
    216 
    217 #define SIN(x) ((struct sockaddr_in *) &(x))
    218 struct sockaddr_in *sintab[] = {
    219     SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
    220     SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)};
    221 
    222 void
    223 in_getaddr(const char *str, int which)
    224 {
    225 	struct sockaddr_in *gasin = sintab[which];
    226 	struct hostent *hp;
    227 	struct netent *np;
    228 
    229 	gasin->sin_len = sizeof(*gasin);
    230 	if (which != MASK)
    231 		gasin->sin_family = AF_INET;
    232 
    233 	if (which == ADDR) {
    234 		char *p = NULL;
    235 		if ((p = strrchr(str, '/')) != NULL) {
    236 			*p = '\0';
    237 			in_getprefix(p + 1, MASK);
    238 		}
    239 	}
    240 
    241 	if (inet_aton(str, &gasin->sin_addr) == 0) {
    242 		if ((hp = gethostbyname(str)) != NULL)
    243 			(void) memcpy(&gasin->sin_addr, hp->h_addr, hp->h_length);
    244 		else if ((np = getnetbyname(str)) != NULL)
    245 			gasin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
    246 		else
    247 			errx(EXIT_FAILURE, "%s: bad value", str);
    248 	}
    249 }
    250 
    251 void
    252 in_getprefix(const char *plen, int which)
    253 {
    254 	struct sockaddr_in *igsin = sintab[which];
    255 	u_char *cp;
    256 	int len = strtol(plen, (char **)NULL, 10);
    257 
    258 	if ((len < 0) || (len > 32))
    259 		errx(EXIT_FAILURE, "%s: bad value", plen);
    260 	igsin->sin_len = sizeof(*igsin);
    261 	if (which != MASK)
    262 		igsin->sin_family = AF_INET;
    263 	if ((len == 0) || (len == 32)) {
    264 		memset(&igsin->sin_addr, 0xff, sizeof(struct in_addr));
    265 		return;
    266 	}
    267 	memset((void *)&igsin->sin_addr, 0x00, sizeof(igsin->sin_addr));
    268 	for (cp = (u_char *)&igsin->sin_addr; len > 7; len -= 8)
    269 		*cp++ = 0xff;
    270 	if (len)
    271 		*cp = 0xff << (8 - len);
    272 }
    273