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