af_inet.c revision 1.26 1 /* $NetBSD: af_inet.c,v 1.26 2019/08/16 10:33:17 msaitoh 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.26 2019/08/16 10:33:17 msaitoh 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 <assert.h>
48 #include <err.h>
49 #include <errno.h>
50 #include <ifaddrs.h>
51 #include <netdb.h>
52 #include <string.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <util.h>
56
57 #include "env.h"
58 #include "extern.h"
59 #include "af_inetany.h"
60 #include "prog_ops.h"
61
62 static void in_constructor(void) __attribute__((constructor));
63 static void in_status(prop_dictionary_t, prop_dictionary_t, bool);
64 static void in_commit_address(prop_dictionary_t, prop_dictionary_t);
65 static bool in_addr_tentative(struct ifaddrs *);
66 static bool in_addr_tentative_or_detached(struct ifaddrs *);
67 static in_addr_t in_netmask(struct sockaddr *);;
68 static int in_prefixlen(struct sockaddr *);
69 static void in_alias(struct ifaddrs *, prop_dictionary_t, prop_dictionary_t);
70
71 static struct afswtch af = {
72 .af_name = "inet", .af_af = AF_INET, .af_status = in_status,
73 .af_addr_commit = in_commit_address,
74 .af_addr_tentative = in_addr_tentative,
75 .af_addr_tentative_or_detached = in_addr_tentative_or_detached
76 };
77
78 static in_addr_t
79 in_netmask(struct sockaddr *sa)
80 {
81 struct sockaddr_in sin;
82
83 memset(&sin, 0, sizeof(sin));
84 memcpy(&sin, sa, sa->sa_len);
85 return ntohl(sin.sin_addr.s_addr);
86 }
87
88 static int
89 in_prefixlen(struct sockaddr *sa)
90 {
91 in_addr_t mask;
92 int cidr;
93
94 mask = in_netmask(sa);
95 if (mask == 0) /* mask 0 ==> /0 */
96 return 0;
97
98 cidr = 33 - ffs(mask); /* 33 - (1 .. 32) -> 32 .. 1 */
99
100 if (cidr < 32) { /* more than 1 bit in mask */
101 /* check for non-contig netmask */
102 if ((mask ^ (((1U << cidr) - 1) << (32 - cidr))) != 0)
103 return -1; /* noncontig, no pfxlen */
104 }
105
106 return cidr;
107 }
108
109 static void
110 in_alias(struct ifaddrs *ifa, prop_dictionary_t env, prop_dictionary_t oenv)
111 {
112 char hbuf[NI_MAXHOST];
113 const int niflag = Nflag ? 0 : NI_NUMERICHOST;
114 int pfxlen;
115 char fbuf[1024];
116
117 if (lflag)
118 return;
119
120 if (getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
121 hbuf, sizeof(hbuf), NULL, 0, niflag))
122 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
123 printf("\tinet %s", hbuf);
124 pfxlen = in_prefixlen(ifa->ifa_netmask);
125 if (pfxlen >= 0)
126 printf("/%d", pfxlen);
127
128 if (ifa->ifa_flags & IFF_POINTOPOINT) {
129 if (getnameinfo(ifa->ifa_dstaddr, ifa->ifa_dstaddr->sa_len,
130 hbuf, sizeof(hbuf), NULL, 0, niflag))
131 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
132 printf(" -> %s", hbuf);
133 }
134
135 if (pfxlen < 0)
136 printf(" netmask %#x", in_netmask(ifa->ifa_netmask));
137
138 if (ifa->ifa_flags & IFF_BROADCAST) {
139 if (getnameinfo(ifa->ifa_broadaddr, ifa->ifa_broadaddr->sa_len,
140 hbuf, sizeof(hbuf), NULL, 0, niflag))
141 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
142 printf(" broadcast %s", hbuf);
143 }
144
145 (void)snprintb(fbuf, sizeof(fbuf), IN_IFFBITS, ifa->ifa_addrflags);
146 printf(" flags %s", fbuf);
147 }
148
149 static void
150 in_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
151 {
152 struct ifaddrs *ifap, *ifa;
153 bool printprefs = false;
154 const char *ifname;
155
156 if ((ifname = getifname(env)) == NULL)
157 err(EXIT_FAILURE, "%s: getifname", __func__);
158
159 if (getifaddrs(&ifap) != 0)
160 err(EXIT_FAILURE, "getifaddrs");
161
162 printprefs = ifa_any_preferences(ifname, ifap, AF_INET);
163
164 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
165 if (strcmp(ifname, ifa->ifa_name) != 0)
166 continue;
167 if (ifa->ifa_addr->sa_family != AF_INET)
168 continue;
169 /* The first address is not an alias. */
170 in_alias(ifa, env, oenv);
171 if (printprefs)
172 ifa_print_preference(ifa->ifa_name, ifa->ifa_addr);
173 printf("\n");
174 }
175 freeifaddrs(ifap);
176 }
177
178 static void
179 in_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
180 {
181 struct ifreq in_ifr;
182 struct in_aliasreq in_ifra;
183 struct afparam inparam = {
184 .req = BUFPARAM(in_ifra)
185 , .dgreq = BUFPARAM(in_ifr)
186 , .name = {
187 {.buf = in_ifr.ifr_name,
188 .buflen = sizeof(in_ifr.ifr_name)}
189 , {.buf = in_ifra.ifra_name,
190 .buflen = sizeof(in_ifra.ifra_name)}
191 }
192 , .dgaddr = BUFPARAM(in_ifr.ifr_addr)
193 , .addr = BUFPARAM(in_ifra.ifra_addr)
194 , .dst = BUFPARAM(in_ifra.ifra_dstaddr)
195 , .brd = BUFPARAM(in_ifra.ifra_broadaddr)
196 , .mask = BUFPARAM(in_ifra.ifra_mask)
197 , .aifaddr = IFADDR_PARAM(SIOCAIFADDR)
198 , .difaddr = IFADDR_PARAM(SIOCDIFADDR)
199 , .gifaddr = IFADDR_PARAM(SIOCGIFADDR)
200 , .defmask = {.buf = NULL, .buflen = 0}
201 };
202 memset(&in_ifr, 0, sizeof(in_ifr));
203 memset(&in_ifra, 0, sizeof(in_ifra));
204 commit_address(env, oenv, &inparam);
205 }
206
207 #ifdef SIOCGIFAFLAG_IN
208 static bool
209 in_addr_flags(struct ifaddrs *ifa, int flags)
210 {
211 int s;
212 struct ifreq ifr;
213
214 memset(&ifr, 0, sizeof(ifr));
215 estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
216 ifr.ifr_addr = *ifa->ifa_addr;
217 if ((s = getsock(AF_INET)) == -1)
218 err(EXIT_FAILURE, "%s: getsock", __func__);
219 if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1)
220 err(EXIT_FAILURE, "SIOCGIFAFLAG_IN");
221 return ifr.ifr_addrflags & flags ? true : false;
222 return false;
223 }
224 #endif
225
226 static bool
227 in_addr_tentative(struct ifaddrs *ifa)
228 {
229
230 #ifdef SIOCGIFAFLAG_IN
231 return in_addr_flags(ifa, IN_IFF_TENTATIVE);
232 #else
233 return false;
234 #endif
235 }
236
237 static bool
238 in_addr_tentative_or_detached(struct ifaddrs *ifa)
239 {
240
241 #ifdef SIOCGIFAFLAG_IN
242 return in_addr_flags(ifa, IN_IFF_TENTATIVE | IN_IFF_DETACHED);
243 #else
244 return false;
245 #endif
246 }
247
248 static void
249 in_constructor(void)
250 {
251 register_family(&af);
252 }
253