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