1*90b80121SDavid van Moolenbroek /* $NetBSD: af_inet.c,v 1.17 2015/05/12 14:05:29 roy Exp $ */
2*90b80121SDavid van Moolenbroek
3*90b80121SDavid van Moolenbroek /*
4*90b80121SDavid van Moolenbroek * Copyright (c) 1983, 1993
5*90b80121SDavid van Moolenbroek * The Regents of the University of California. All rights reserved.
6*90b80121SDavid van Moolenbroek *
7*90b80121SDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
8*90b80121SDavid van Moolenbroek * modification, are permitted provided that the following conditions
9*90b80121SDavid van Moolenbroek * are met:
10*90b80121SDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
11*90b80121SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
12*90b80121SDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
13*90b80121SDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
14*90b80121SDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
15*90b80121SDavid van Moolenbroek * 3. Neither the name of the University nor the names of its contributors
16*90b80121SDavid van Moolenbroek * may be used to endorse or promote products derived from this software
17*90b80121SDavid van Moolenbroek * without specific prior written permission.
18*90b80121SDavid van Moolenbroek *
19*90b80121SDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*90b80121SDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*90b80121SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*90b80121SDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*90b80121SDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*90b80121SDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*90b80121SDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*90b80121SDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*90b80121SDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*90b80121SDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*90b80121SDavid van Moolenbroek * SUCH DAMAGE.
30*90b80121SDavid van Moolenbroek */
31*90b80121SDavid van Moolenbroek
32*90b80121SDavid van Moolenbroek #include <sys/cdefs.h>
33*90b80121SDavid van Moolenbroek #ifndef lint
34*90b80121SDavid van Moolenbroek __RCSID("$NetBSD: af_inet.c,v 1.17 2015/05/12 14:05:29 roy Exp $");
35*90b80121SDavid van Moolenbroek #endif /* not lint */
36*90b80121SDavid van Moolenbroek
37*90b80121SDavid van Moolenbroek #include <sys/param.h>
38*90b80121SDavid van Moolenbroek #include <sys/ioctl.h>
39*90b80121SDavid van Moolenbroek #include <sys/socket.h>
40*90b80121SDavid van Moolenbroek
41*90b80121SDavid van Moolenbroek #include <net/if.h>
42*90b80121SDavid van Moolenbroek #include <netinet/in.h>
43*90b80121SDavid van Moolenbroek #include <netinet/in_var.h>
44*90b80121SDavid van Moolenbroek
45*90b80121SDavid van Moolenbroek #include <arpa/inet.h>
46*90b80121SDavid van Moolenbroek
47*90b80121SDavid van Moolenbroek #include <assert.h>
48*90b80121SDavid van Moolenbroek #include <err.h>
49*90b80121SDavid van Moolenbroek #include <errno.h>
50*90b80121SDavid van Moolenbroek #include <ifaddrs.h>
51*90b80121SDavid van Moolenbroek #include <netdb.h>
52*90b80121SDavid van Moolenbroek #include <string.h>
53*90b80121SDavid van Moolenbroek #include <stdlib.h>
54*90b80121SDavid van Moolenbroek #include <stdio.h>
55*90b80121SDavid van Moolenbroek #include <util.h>
56*90b80121SDavid van Moolenbroek
57*90b80121SDavid van Moolenbroek #include "env.h"
58*90b80121SDavid van Moolenbroek #include "extern.h"
59*90b80121SDavid van Moolenbroek #include "af_inetany.h"
60*90b80121SDavid van Moolenbroek #include "prog_ops.h"
61*90b80121SDavid van Moolenbroek
62*90b80121SDavid van Moolenbroek static void in_constructor(void) __attribute__((constructor));
63*90b80121SDavid van Moolenbroek static void in_status(prop_dictionary_t, prop_dictionary_t, bool);
64*90b80121SDavid van Moolenbroek static void in_commit_address(prop_dictionary_t, prop_dictionary_t);
65*90b80121SDavid van Moolenbroek static bool in_addr_tentative(struct ifaddrs *ifa);
66*90b80121SDavid van Moolenbroek static void in_alias(const char *, prop_dictionary_t, prop_dictionary_t,
67*90b80121SDavid van Moolenbroek struct in_aliasreq *);
68*90b80121SDavid van Moolenbroek
69*90b80121SDavid van Moolenbroek static struct afswtch af = {
70*90b80121SDavid van Moolenbroek .af_name = "inet", .af_af = AF_INET, .af_status = in_status,
71*90b80121SDavid van Moolenbroek .af_addr_commit = in_commit_address,
72*90b80121SDavid van Moolenbroek .af_addr_tentative = in_addr_tentative
73*90b80121SDavid van Moolenbroek };
74*90b80121SDavid van Moolenbroek
75*90b80121SDavid van Moolenbroek static void
in_alias(const char * ifname,prop_dictionary_t env,prop_dictionary_t oenv,struct in_aliasreq * creq)76*90b80121SDavid van Moolenbroek in_alias(const char *ifname, prop_dictionary_t env, prop_dictionary_t oenv,
77*90b80121SDavid van Moolenbroek struct in_aliasreq *creq)
78*90b80121SDavid van Moolenbroek {
79*90b80121SDavid van Moolenbroek struct ifreq ifr;
80*90b80121SDavid van Moolenbroek bool alias;
81*90b80121SDavid van Moolenbroek int s;
82*90b80121SDavid van Moolenbroek unsigned short flags;
83*90b80121SDavid van Moolenbroek struct in_aliasreq in_addreq;
84*90b80121SDavid van Moolenbroek const struct sockaddr_in * const asin = &in_addreq.ifra_addr;
85*90b80121SDavid van Moolenbroek const struct sockaddr_in * const dsin = &in_addreq.ifra_dstaddr;
86*90b80121SDavid van Moolenbroek const struct sockaddr_in * const bsin = &in_addreq.ifra_broadaddr;
87*90b80121SDavid van Moolenbroek char hbuf[NI_MAXHOST];
88*90b80121SDavid van Moolenbroek const int niflag = Nflag ? 0 : NI_NUMERICHOST;
89*90b80121SDavid van Moolenbroek
90*90b80121SDavid van Moolenbroek if (lflag)
91*90b80121SDavid van Moolenbroek return;
92*90b80121SDavid van Moolenbroek
93*90b80121SDavid van Moolenbroek alias = true;
94*90b80121SDavid van Moolenbroek
95*90b80121SDavid van Moolenbroek /* Get the non-alias address for this interface. */
96*90b80121SDavid van Moolenbroek if ((s = getsock(AF_INET)) == -1) {
97*90b80121SDavid van Moolenbroek if (errno == EAFNOSUPPORT)
98*90b80121SDavid van Moolenbroek return;
99*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "socket");
100*90b80121SDavid van Moolenbroek }
101*90b80121SDavid van Moolenbroek memset(&ifr, 0, sizeof(ifr));
102*90b80121SDavid van Moolenbroek estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
103*90b80121SDavid van Moolenbroek if (prog_ioctl(s, SIOCGIFADDR, &ifr) == -1) {
104*90b80121SDavid van Moolenbroek if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
105*90b80121SDavid van Moolenbroek return;
106*90b80121SDavid van Moolenbroek warn("SIOCGIFADDR");
107*90b80121SDavid van Moolenbroek }
108*90b80121SDavid van Moolenbroek /* If creq and ifr are the same address, this is not an alias. */
109*90b80121SDavid van Moolenbroek if (memcmp(&ifr.ifr_addr, &creq->ifra_addr, sizeof(ifr.ifr_addr)) == 0)
110*90b80121SDavid van Moolenbroek alias = false;
111*90b80121SDavid van Moolenbroek in_addreq = *creq;
112*90b80121SDavid van Moolenbroek if (prog_ioctl(s, SIOCGIFALIAS, &in_addreq) == -1) {
113*90b80121SDavid van Moolenbroek if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
114*90b80121SDavid van Moolenbroek return;
115*90b80121SDavid van Moolenbroek } else
116*90b80121SDavid van Moolenbroek warn("SIOCGIFALIAS");
117*90b80121SDavid van Moolenbroek }
118*90b80121SDavid van Moolenbroek
119*90b80121SDavid van Moolenbroek if (getnameinfo((const struct sockaddr *)asin, asin->sin_len,
120*90b80121SDavid van Moolenbroek hbuf, sizeof(hbuf), NULL, 0, niflag))
121*90b80121SDavid van Moolenbroek strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
122*90b80121SDavid van Moolenbroek printf("\tinet %s%s", alias ? "alias " : "", hbuf);
123*90b80121SDavid van Moolenbroek
124*90b80121SDavid van Moolenbroek if (getifflags(env, oenv, &flags) == -1)
125*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "%s: getifflags", __func__);
126*90b80121SDavid van Moolenbroek
127*90b80121SDavid van Moolenbroek if (flags & IFF_POINTOPOINT) {
128*90b80121SDavid van Moolenbroek if (getnameinfo((const struct sockaddr *)dsin, dsin->sin_len,
129*90b80121SDavid van Moolenbroek hbuf, sizeof(hbuf), NULL, 0, niflag))
130*90b80121SDavid van Moolenbroek strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
131*90b80121SDavid van Moolenbroek printf(" -> %s", hbuf);
132*90b80121SDavid van Moolenbroek }
133*90b80121SDavid van Moolenbroek
134*90b80121SDavid van Moolenbroek printf(" netmask 0x%x", ntohl(in_addreq.ifra_mask.sin_addr.s_addr));
135*90b80121SDavid van Moolenbroek
136*90b80121SDavid van Moolenbroek if (flags & IFF_BROADCAST) {
137*90b80121SDavid van Moolenbroek if (getnameinfo((const struct sockaddr *)bsin, bsin->sin_len,
138*90b80121SDavid van Moolenbroek hbuf, sizeof(hbuf), NULL, 0, niflag))
139*90b80121SDavid van Moolenbroek strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
140*90b80121SDavid van Moolenbroek printf(" broadcast %s", hbuf);
141*90b80121SDavid van Moolenbroek }
142*90b80121SDavid van Moolenbroek
143*90b80121SDavid van Moolenbroek #ifdef IN_IFF_TENTATIVE
144*90b80121SDavid van Moolenbroek memcpy(&ifr.ifr_addr, &creq->ifra_addr, creq->ifra_addr.sin_len);
145*90b80121SDavid van Moolenbroek if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1) {
146*90b80121SDavid van Moolenbroek if (errno != EADDRNOTAVAIL)
147*90b80121SDavid van Moolenbroek warn("SIOCGIFAFLAG_IN");
148*90b80121SDavid van Moolenbroek } else {
149*90b80121SDavid van Moolenbroek if (ifr.ifr_addrflags & IN_IFF_TENTATIVE)
150*90b80121SDavid van Moolenbroek printf(" tentative");
151*90b80121SDavid van Moolenbroek if (ifr.ifr_addrflags & IN_IFF_DUPLICATED)
152*90b80121SDavid van Moolenbroek printf(" duplicated");
153*90b80121SDavid van Moolenbroek if (ifr.ifr_addrflags & IN_IFF_DETACHED)
154*90b80121SDavid van Moolenbroek printf(" detached");
155*90b80121SDavid van Moolenbroek }
156*90b80121SDavid van Moolenbroek #endif
157*90b80121SDavid van Moolenbroek }
158*90b80121SDavid van Moolenbroek
159*90b80121SDavid van Moolenbroek static void
in_status(prop_dictionary_t env,prop_dictionary_t oenv,bool force)160*90b80121SDavid van Moolenbroek in_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
161*90b80121SDavid van Moolenbroek {
162*90b80121SDavid van Moolenbroek struct ifaddrs *ifap, *ifa;
163*90b80121SDavid van Moolenbroek struct in_aliasreq ifra;
164*90b80121SDavid van Moolenbroek bool printprefs = false;
165*90b80121SDavid van Moolenbroek const char *ifname;
166*90b80121SDavid van Moolenbroek
167*90b80121SDavid van Moolenbroek if ((ifname = getifname(env)) == NULL)
168*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "%s: getifname", __func__);
169*90b80121SDavid van Moolenbroek
170*90b80121SDavid van Moolenbroek if (getifaddrs(&ifap) != 0)
171*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "getifaddrs");
172*90b80121SDavid van Moolenbroek
173*90b80121SDavid van Moolenbroek printprefs = ifa_any_preferences(ifname, ifap, AF_INET);
174*90b80121SDavid van Moolenbroek
175*90b80121SDavid van Moolenbroek for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
176*90b80121SDavid van Moolenbroek if (strcmp(ifname, ifa->ifa_name) != 0)
177*90b80121SDavid van Moolenbroek continue;
178*90b80121SDavid van Moolenbroek if (ifa->ifa_addr->sa_family != AF_INET)
179*90b80121SDavid van Moolenbroek continue;
180*90b80121SDavid van Moolenbroek if (sizeof(ifra.ifra_addr) < ifa->ifa_addr->sa_len)
181*90b80121SDavid van Moolenbroek continue;
182*90b80121SDavid van Moolenbroek
183*90b80121SDavid van Moolenbroek memset(&ifra, 0, sizeof(ifra));
184*90b80121SDavid van Moolenbroek estrlcpy(ifra.ifra_name, ifa->ifa_name, sizeof(ifra.ifra_name));
185*90b80121SDavid van Moolenbroek memcpy(&ifra.ifra_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
186*90b80121SDavid van Moolenbroek in_alias(ifa->ifa_name, env, oenv, &ifra);
187*90b80121SDavid van Moolenbroek if (printprefs)
188*90b80121SDavid van Moolenbroek ifa_print_preference(ifa->ifa_name, ifa->ifa_addr);
189*90b80121SDavid van Moolenbroek printf("\n");
190*90b80121SDavid van Moolenbroek }
191*90b80121SDavid van Moolenbroek freeifaddrs(ifap);
192*90b80121SDavid van Moolenbroek }
193*90b80121SDavid van Moolenbroek
194*90b80121SDavid van Moolenbroek static void
in_commit_address(prop_dictionary_t env,prop_dictionary_t oenv)195*90b80121SDavid van Moolenbroek in_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
196*90b80121SDavid van Moolenbroek {
197*90b80121SDavid van Moolenbroek struct ifreq in_ifr;
198*90b80121SDavid van Moolenbroek struct in_aliasreq in_ifra;
199*90b80121SDavid van Moolenbroek struct afparam inparam = {
200*90b80121SDavid van Moolenbroek .req = BUFPARAM(in_ifra)
201*90b80121SDavid van Moolenbroek , .dgreq = BUFPARAM(in_ifr)
202*90b80121SDavid van Moolenbroek , .name = {
203*90b80121SDavid van Moolenbroek {.buf = in_ifr.ifr_name,
204*90b80121SDavid van Moolenbroek .buflen = sizeof(in_ifr.ifr_name)}
205*90b80121SDavid van Moolenbroek , {.buf = in_ifra.ifra_name,
206*90b80121SDavid van Moolenbroek .buflen = sizeof(in_ifra.ifra_name)}
207*90b80121SDavid van Moolenbroek }
208*90b80121SDavid van Moolenbroek , .dgaddr = BUFPARAM(in_ifr.ifr_addr)
209*90b80121SDavid van Moolenbroek , .addr = BUFPARAM(in_ifra.ifra_addr)
210*90b80121SDavid van Moolenbroek , .dst = BUFPARAM(in_ifra.ifra_dstaddr)
211*90b80121SDavid van Moolenbroek , .brd = BUFPARAM(in_ifra.ifra_broadaddr)
212*90b80121SDavid van Moolenbroek , .mask = BUFPARAM(in_ifra.ifra_mask)
213*90b80121SDavid van Moolenbroek , .aifaddr = IFADDR_PARAM(SIOCAIFADDR)
214*90b80121SDavid van Moolenbroek , .difaddr = IFADDR_PARAM(SIOCDIFADDR)
215*90b80121SDavid van Moolenbroek , .gifaddr = IFADDR_PARAM(SIOCGIFADDR)
216*90b80121SDavid van Moolenbroek , .defmask = {.buf = NULL, .buflen = 0}
217*90b80121SDavid van Moolenbroek };
218*90b80121SDavid van Moolenbroek memset(&in_ifr, 0, sizeof(in_ifr));
219*90b80121SDavid van Moolenbroek memset(&in_ifra, 0, sizeof(in_ifra));
220*90b80121SDavid van Moolenbroek commit_address(env, oenv, &inparam);
221*90b80121SDavid van Moolenbroek }
222*90b80121SDavid van Moolenbroek
223*90b80121SDavid van Moolenbroek static bool
in_addr_tentative(struct ifaddrs * ifa)224*90b80121SDavid van Moolenbroek in_addr_tentative(struct ifaddrs *ifa)
225*90b80121SDavid van Moolenbroek {
226*90b80121SDavid van Moolenbroek #ifdef IN_IFF_TENTATIVE
227*90b80121SDavid van Moolenbroek int s;
228*90b80121SDavid van Moolenbroek struct ifreq ifr;
229*90b80121SDavid van Moolenbroek
230*90b80121SDavid van Moolenbroek memset(&ifr, 0, sizeof(ifr));
231*90b80121SDavid van Moolenbroek strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
232*90b80121SDavid van Moolenbroek ifr.ifr_addr = *ifa->ifa_addr;
233*90b80121SDavid van Moolenbroek if ((s = getsock(AF_INET)) == -1)
234*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "%s: getsock", __func__);
235*90b80121SDavid van Moolenbroek if (prog_ioctl(s, SIOCGIFAFLAG_IN, &ifr) == -1)
236*90b80121SDavid van Moolenbroek err(EXIT_FAILURE, "SIOCGIFAFLAG_IN");
237*90b80121SDavid van Moolenbroek return ifr.ifr_addrflags & IN_IFF_TENTATIVE ? true : false;
238*90b80121SDavid van Moolenbroek #else
239*90b80121SDavid van Moolenbroek return false;
240*90b80121SDavid van Moolenbroek #endif
241*90b80121SDavid van Moolenbroek }
242*90b80121SDavid van Moolenbroek
243*90b80121SDavid van Moolenbroek static void
in_constructor(void)244*90b80121SDavid van Moolenbroek in_constructor(void)
245*90b80121SDavid van Moolenbroek {
246*90b80121SDavid van Moolenbroek register_family(&af);
247*90b80121SDavid van Moolenbroek }
248