2 * SPDX-License-Identifier: BSD-3-Clause
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
33 static const char rcsid[] =
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <netinet/in_var.h>
52 #include <arpa/inet.h>
56 #include "ifconfig_netlink.h"
58 #ifdef WITHOUT_NETLINK
59 static struct in_aliasreq in_addreq;
60 static struct ifreq in_ridreq;
70 struct in_px dst_addr;
71 struct in_px brd_addr;
75 static struct in_pdata in_add, in_del;
78 static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/
79 extern char *f_inet, *f_addr;
82 print_addr(struct sockaddr_in *sin)
86 if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
88 else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
91 n_flags = NI_NUMERICHOST;
93 error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf,
94 sizeof(addr_buf), NULL, 0, n_flags);
97 inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf));
99 printf("\tinet %s", addr_buf);
102 #ifdef WITHOUT_NETLINK
104 in_status(if_ctx *ctx __unused, const struct ifaddrs *ifa)
106 struct sockaddr_in *sin, null_sin = {};
108 sin = (struct sockaddr_in *)ifa->ifa_addr;
114 if (ifa->ifa_flags & IFF_POINTOPOINT) {
115 sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
118 printf(" --> %s", inet_ntoa(sin->sin_addr));
121 sin = (struct sockaddr_in *)ifa->ifa_netmask;
124 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) {
128 smask = ntohl(sin->sin_addr.s_addr);
129 while ((smask & 1) == 0) {
136 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0)
137 printf(" netmask %s", inet_ntoa(sin->sin_addr));
139 printf(" netmask 0x%lx", (unsigned long)ntohl(sin->sin_addr.s_addr));
141 if (ifa->ifa_flags & IFF_BROADCAST) {
142 sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
143 if (sin != NULL && sin->sin_addr.s_addr != 0)
144 printf(" broadcast %s", inet_ntoa(sin->sin_addr));
147 print_vhid(ifa, " ");
153 static struct in_addr
158 a.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
164 in_status_nl(if_ctx *ctx __unused, if_link_t *link, if_addr_t *ifa)
166 struct sockaddr_in *sin = satosin(ifa->ifa_local);
167 int plen = ifa->ifa_prefixlen;
171 if (link->ifi_flags & IFF_POINTOPOINT) {
172 struct sockaddr_in *dst = satosin(ifa->ifa_address);
174 printf(" --> %s", inet_ntoa(dst->sin_addr));
176 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) {
178 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0)
179 printf(" netmask %s", inet_ntoa(get_mask(plen)));
181 printf(" netmask 0x%lx", (unsigned long)ntohl(get_mask(plen).s_addr));
183 if ((link->ifi_flags & IFF_BROADCAST) && plen != 0) {
184 struct sockaddr_in *brd = satosin(ifa->ifa_broadcast);
186 printf(" broadcast %s", inet_ntoa(brd->sin_addr));
189 if (ifa->ifaf_vhid != 0)
190 printf(" vhid %d", ifa->ifaf_vhid);
197 #ifdef WITHOUT_NETLINK
198 #define SIN(x) ((struct sockaddr_in *) &(x))
199 static struct sockaddr_in *sintab[] = {
200 SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
201 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
205 in_copyaddr(if_ctx *ctx, int to, int from)
207 memcpy(sintab[to], sintab[from], sizeof(struct sockaddr_in));
211 in_getaddr(const char *s, int which)
213 struct sockaddr_in *sin = sintab[which];
217 sin->sin_len = sizeof(*sin);
218 sin->sin_family = AF_INET;
223 if((p = strrchr(s, '/')) != NULL) {
225 /* address is `name/masklen' */
227 struct sockaddr_in *min = sintab[MASK];
229 if (!isdigit(*(p + 1)))
232 masklen = (int)strtonum(p + 1, 0, 32, &errstr);
233 if (errstr != NULL) {
235 errx(1, "%s: bad value (width %s)", s, errstr);
237 min->sin_family = AF_INET;
238 min->sin_len = sizeof(*min);
239 min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) &
244 if (inet_aton(s, &sin->sin_addr))
246 if ((hp = gethostbyname(s)) != NULL)
247 bcopy(hp->h_addr, (char *)&sin->sin_addr,
248 MIN((size_t)hp->h_length, sizeof(sin->sin_addr)));
249 else if ((np = getnetbyname(s)) != NULL)
250 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
252 errx(1, "%s: bad value", s);
257 static struct in_px *sintab_nl[] = {
258 &in_del.addr, /* RIDADDR */
259 &in_add.addr, /* ADDR */
261 &in_add.dst_addr, /* DSTADDR*/
262 &in_add.brd_addr, /* BRDADDR*/
266 in_copyaddr(if_ctx *ctx __unused, int to, int from)
268 sintab_nl[to]->addr = sintab_nl[from]->addr;
269 sintab_nl[to]->addrset = sintab_nl[from]->addrset;
273 in_getip(const char *addr_str, struct in_addr *ip)
278 if (inet_aton(addr_str, ip))
280 if ((hp = gethostbyname(addr_str)) != NULL)
281 bcopy(hp->h_addr, (char *)ip,
282 MIN((size_t)hp->h_length, sizeof(ip)));
283 else if ((np = getnetbyname(addr_str)) != NULL)
284 *ip = inet_makeaddr(np->n_net, INADDR_ANY);
286 errx(1, "%s: bad value", addr_str);
290 in_getaddr(const char *s, int which)
292 struct in_px *px = sintab_nl[which];
295 struct in_px *px_addr = sintab_nl[ADDR];
296 struct in_addr mask = {};
299 px_addr->plen = __bitcount32(mask.s_addr);
300 px_addr->maskset = true;
307 if((p = strrchr(s, '/')) != NULL) {
309 /* address is `name/masklen' */
312 if (!isdigit(*(p + 1)))
315 masklen = (int)strtonum(p + 1, 0, 32, &errstr);
316 if (errstr != NULL) {
318 errx(1, "%s: bad value (width %s)", s, errstr);
325 in_getip(s, &px->addr);
330 * Deletes the first found IPv4 interface address for the interface.
332 * This function provides SIOCDIFADDR semantics missing in Netlink.
333 * When no valid IPv4 address is specified (sin_family or sin_len is wrong) to
334 * the SIOCDIFADDR call, it deletes the first found IPv4 address on the interface.
335 * 'ifconfig IFNAME inet addr/prefix' relies on that behavior, as it
336 * executes empty SIOCDIFADDR before adding a new address.
339 in_delete_first_nl(if_ctx *ctx)
341 struct nlmsghdr *hdr;
342 struct ifaddrmsg *ifahdr;
345 struct snl_writer nw = {};
346 struct snl_errmsg_data e = {};
347 struct snl_state *ss = ctx->io_ss;
350 uint32_t ifindex = if_nametoindex_nl(ss, name);
352 /* No interface with the desired name, nothing to delete */
353 return (EADDRNOTAVAIL);
356 snl_init_writer(ss, &nw);
357 hdr = snl_create_msg_request(&nw, NL_RTM_GETADDR);
358 hdr->nlmsg_flags |= NLM_F_DUMP;
359 ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
360 ifahdr->ifa_family = AF_INET;
361 ifahdr->ifa_index = ifindex;
363 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr))
366 nlmsg_seq = hdr->nlmsg_seq;
367 while ((hdr = snl_read_reply_multi(ss, nlmsg_seq, &e)) != NULL) {
368 struct snl_parsed_addr attrs = {};
369 if (snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &attrs)) {
370 addr = satosin(attrs.ifa_local)->sin_addr;
371 ifindex = attrs.ifa_index;
378 if (e.error_str != NULL)
379 warnx("%s(): %s", __func__, e.error_str);
386 /* Try to delete the found address */
387 snl_init_writer(ss, &nw);
388 hdr = snl_create_msg_request(&nw, NL_RTM_DELADDR);
389 ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
390 ifahdr->ifa_family = AF_INET;
391 ifahdr->ifa_index = ifindex;
392 snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &addr);
394 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr))
396 memset(&e, 0, sizeof(e));
397 snl_read_reply_code(ss, hdr->nlmsg_seq, &e);
398 if (e.error_str != NULL)
399 warnx("%s(): %s", __func__, e.error_str);
406 in_exec_nl(if_ctx *ctx, unsigned long action, void *data)
408 struct in_pdata *pdata = (struct in_pdata *)data;
409 struct snl_writer nw = {};
411 if (action == NL_RTM_DELADDR && !pdata->addr.addrset)
412 return (in_delete_first_nl(ctx));
414 snl_init_writer(ctx->io_ss, &nw);
415 struct nlmsghdr *hdr = snl_create_msg_request(&nw, action);
416 struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
418 ifahdr->ifa_family = AF_INET;
419 ifahdr->ifa_prefixlen = pdata->addr.plen;
420 ifahdr->ifa_index = if_nametoindex_nl(ctx->io_ss, name);
422 snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &pdata->addr.addr);
423 if (action == NL_RTM_NEWADDR && pdata->dst_addr.addrset)
424 snl_add_msg_attr_ip4(&nw, IFA_ADDRESS, &pdata->dst_addr.addr);
425 if (action == NL_RTM_NEWADDR && pdata->brd_addr.addrset)
426 snl_add_msg_attr_ip4(&nw, IFA_BROADCAST, &pdata->brd_addr.addr);
428 int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
429 snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags);
430 if (pdata->vhid != 0)
431 snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid);
432 snl_end_attr_nested(&nw, off);
434 if (!snl_finalize_msg(&nw) || !snl_send_message(ctx->io_ss, hdr))
437 struct snl_errmsg_data e = {};
438 snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &e);
439 if (e.error_str != NULL)
440 warnx("%s(): %s", __func__, e.error_str);
446 in_setdefaultmask_nl(void)
448 struct in_px *px = sintab_nl[ADDR];
450 in_addr_t i = ntohl(px->addr.s_addr);
453 * If netmask isn't supplied, use historical default.
454 * This is deprecated for interfaces other than loopback
455 * or point-to-point; warn in other cases. In the future
456 * we should return an error rather than warning.
459 px->plen = IN_CLASSA_NSHIFT;
460 else if (IN_CLASSB(i))
461 px->plen = IN_CLASSB_NSHIFT;
463 px->plen = IN_CLASSC_NSHIFT;
469 warn_nomask(int ifflags)
471 if ((ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
472 warnx("WARNING: setting interface address without mask "
473 "is deprecated,\ndefault mask may not be correct.");
478 in_postproc(if_ctx *ctx __unused, int newaddr, int ifflags)
480 #ifdef WITHOUT_NETLINK
481 if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && newaddr) {
482 warn_nomask(ifflags);
485 if (sintab_nl[ADDR]->addrset && !sintab_nl[ADDR]->maskset && newaddr) {
486 warn_nomask(ifflags);
487 in_setdefaultmask_nl();
493 in_status_tunnel(int s)
495 char src[NI_MAXHOST];
496 char dst[NI_MAXHOST];
498 const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
500 memset(&ifr, 0, sizeof(ifr));
501 strlcpy(ifr.ifr_name, name, IFNAMSIZ);
503 if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
505 if (sa->sa_family != AF_INET)
507 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0)
510 if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0)
512 if (sa->sa_family != AF_INET)
514 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0)
517 printf("\ttunnel inet %s --> %s\n", src, dst);
521 in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
523 struct in_aliasreq addreq;
525 memset(&addreq, 0, sizeof(addreq));
526 strlcpy(addreq.ifra_name, name, IFNAMSIZ);
527 memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
528 memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
530 if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0)
531 warn("SIOCSIFPHYADDR");
535 in_set_vhid(int vhid)
537 #ifdef WITHOUT_NETLINK
538 in_addreq.ifra_vhid = vhid;
540 in_add.vhid = (uint32_t)vhid;
544 static struct afswtch af_inet = {
547 #ifdef WITHOUT_NETLINK
548 .af_status = in_status,
550 .af_status = in_status_nl,
552 .af_getaddr = in_getaddr,
553 .af_copyaddr = in_copyaddr,
554 .af_postproc = in_postproc,
555 .af_status_tunnel = in_status_tunnel,
556 .af_settunnel = in_set_tunnel,
557 .af_setvhid = in_set_vhid,
558 #ifdef WITHOUT_NETLINK
559 .af_difaddr = SIOCDIFADDR,
560 .af_aifaddr = SIOCAIFADDR,
561 .af_ridreq = &in_ridreq,
562 .af_addreq = &in_addreq,
563 .af_exec = af_exec_ioctl,
565 .af_difaddr = NL_RTM_DELADDR,
566 .af_aifaddr = NL_RTM_NEWADDR,
567 .af_ridreq = &in_del,
568 .af_addreq = &in_add,
569 .af_exec = in_exec_nl,
573 static __constructor void
578 if (!feature_present("inet"))
581 af_register(&af_inet);