1 /* $NetBSD: af_inet.c,v 1.17 2015/05/12 14:05:29 roy Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: af_inet.c,v 1.17 2015/05/12 14:05:29 roy Exp $");
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netinet/in_var.h>
45 #include <arpa/inet.h>
59 #include "af_inetany.h"
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
*ifa
);
66 static void in_alias(const char *, prop_dictionary_t
, prop_dictionary_t
,
67 struct in_aliasreq
*);
69 static struct afswtch af
= {
70 .af_name
= "inet", .af_af
= AF_INET
, .af_status
= in_status
,
71 .af_addr_commit
= in_commit_address
,
72 .af_addr_tentative
= in_addr_tentative
76 in_alias(const char *ifname
, prop_dictionary_t env
, prop_dictionary_t oenv
,
77 struct in_aliasreq
*creq
)
83 struct in_aliasreq in_addreq
;
84 const struct sockaddr_in
* const asin
= &in_addreq
.ifra_addr
;
85 const struct sockaddr_in
* const dsin
= &in_addreq
.ifra_dstaddr
;
86 const struct sockaddr_in
* const bsin
= &in_addreq
.ifra_broadaddr
;
87 char hbuf
[NI_MAXHOST
];
88 const int niflag
= Nflag
? 0 : NI_NUMERICHOST
;
95 /* Get the non-alias address for this interface. */
96 if ((s
= getsock(AF_INET
)) == -1) {
97 if (errno
== EAFNOSUPPORT
)
99 err(EXIT_FAILURE
, "socket");
101 memset(&ifr
, 0, sizeof(ifr
));
102 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
103 if (prog_ioctl(s
, SIOCGIFADDR
, &ifr
) == -1) {
104 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
)
108 /* If creq and ifr are the same address, this is not an alias. */
109 if (memcmp(&ifr
.ifr_addr
, &creq
->ifra_addr
, sizeof(ifr
.ifr_addr
)) == 0)
112 if (prog_ioctl(s
, SIOCGIFALIAS
, &in_addreq
) == -1) {
113 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
) {
116 warn("SIOCGIFALIAS");
119 if (getnameinfo((const struct sockaddr
*)asin
, asin
->sin_len
,
120 hbuf
, sizeof(hbuf
), NULL
, 0, niflag
))
121 strlcpy(hbuf
, "", sizeof(hbuf
)); /* some message? */
122 printf("\tinet %s%s", alias
? "alias " : "", hbuf
);
124 if (getifflags(env
, oenv
, &flags
) == -1)
125 err(EXIT_FAILURE
, "%s: getifflags", __func__
);
127 if (flags
& IFF_POINTOPOINT
) {
128 if (getnameinfo((const struct sockaddr
*)dsin
, dsin
->sin_len
,
129 hbuf
, sizeof(hbuf
), NULL
, 0, niflag
))
130 strlcpy(hbuf
, "", sizeof(hbuf
)); /* some message? */
131 printf(" -> %s", hbuf
);
134 printf(" netmask 0x%x", ntohl(in_addreq
.ifra_mask
.sin_addr
.s_addr
));
136 if (flags
& IFF_BROADCAST
) {
137 if (getnameinfo((const struct sockaddr
*)bsin
, bsin
->sin_len
,
138 hbuf
, sizeof(hbuf
), NULL
, 0, niflag
))
139 strlcpy(hbuf
, "", sizeof(hbuf
)); /* some message? */
140 printf(" broadcast %s", hbuf
);
143 #ifdef IN_IFF_TENTATIVE
144 memcpy(&ifr
.ifr_addr
, &creq
->ifra_addr
, creq
->ifra_addr
.sin_len
);
145 if (prog_ioctl(s
, SIOCGIFAFLAG_IN
, &ifr
) == -1) {
146 if (errno
!= EADDRNOTAVAIL
)
147 warn("SIOCGIFAFLAG_IN");
149 if (ifr
.ifr_addrflags
& IN_IFF_TENTATIVE
)
150 printf(" tentative");
151 if (ifr
.ifr_addrflags
& IN_IFF_DUPLICATED
)
152 printf(" duplicated");
153 if (ifr
.ifr_addrflags
& IN_IFF_DETACHED
)
160 in_status(prop_dictionary_t env
, prop_dictionary_t oenv
, bool force
)
162 struct ifaddrs
*ifap
, *ifa
;
163 struct in_aliasreq ifra
;
164 bool printprefs
= false;
167 if ((ifname
= getifname(env
)) == NULL
)
168 err(EXIT_FAILURE
, "%s: getifname", __func__
);
170 if (getifaddrs(&ifap
) != 0)
171 err(EXIT_FAILURE
, "getifaddrs");
173 printprefs
= ifa_any_preferences(ifname
, ifap
, AF_INET
);
175 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
176 if (strcmp(ifname
, ifa
->ifa_name
) != 0)
178 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
180 if (sizeof(ifra
.ifra_addr
) < ifa
->ifa_addr
->sa_len
)
183 memset(&ifra
, 0, sizeof(ifra
));
184 estrlcpy(ifra
.ifra_name
, ifa
->ifa_name
, sizeof(ifra
.ifra_name
));
185 memcpy(&ifra
.ifra_addr
, ifa
->ifa_addr
, ifa
->ifa_addr
->sa_len
);
186 in_alias(ifa
->ifa_name
, env
, oenv
, &ifra
);
188 ifa_print_preference(ifa
->ifa_name
, ifa
->ifa_addr
);
195 in_commit_address(prop_dictionary_t env
, prop_dictionary_t oenv
)
198 struct in_aliasreq in_ifra
;
199 struct afparam inparam
= {
200 .req
= BUFPARAM(in_ifra
)
201 , .dgreq
= BUFPARAM(in_ifr
)
203 {.buf
= in_ifr
.ifr_name
,
204 .buflen
= sizeof(in_ifr
.ifr_name
)}
205 , {.buf
= in_ifra
.ifra_name
,
206 .buflen
= sizeof(in_ifra
.ifra_name
)}
208 , .dgaddr
= BUFPARAM(in_ifr
.ifr_addr
)
209 , .addr
= BUFPARAM(in_ifra
.ifra_addr
)
210 , .dst
= BUFPARAM(in_ifra
.ifra_dstaddr
)
211 , .brd
= BUFPARAM(in_ifra
.ifra_broadaddr
)
212 , .mask
= BUFPARAM(in_ifra
.ifra_mask
)
213 , .aifaddr
= IFADDR_PARAM(SIOCAIFADDR
)
214 , .difaddr
= IFADDR_PARAM(SIOCDIFADDR
)
215 , .gifaddr
= IFADDR_PARAM(SIOCGIFADDR
)
216 , .defmask
= {.buf
= NULL
, .buflen
= 0}
218 memset(&in_ifr
, 0, sizeof(in_ifr
));
219 memset(&in_ifra
, 0, sizeof(in_ifra
));
220 commit_address(env
, oenv
, &inparam
);
224 in_addr_tentative(struct ifaddrs
*ifa
)
226 #ifdef IN_IFF_TENTATIVE
230 memset(&ifr
, 0, sizeof(ifr
));
231 strncpy(ifr
.ifr_name
, ifa
->ifa_name
, sizeof(ifr
.ifr_name
));
232 ifr
.ifr_addr
= *ifa
->ifa_addr
;
233 if ((s
= getsock(AF_INET
)) == -1)
234 err(EXIT_FAILURE
, "%s: getsock", __func__
);
235 if (prog_ioctl(s
, SIOCGIFAFLAG_IN
, &ifr
) == -1)
236 err(EXIT_FAILURE
, "SIOCGIFAFLAG_IN");
237 return ifr
.ifr_addrflags
& IN_IFF_TENTATIVE
? true : false;
246 register_family(&af
);