1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 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 #ifndef lint 33 static const char rcsid[] = 34 "$FreeBSD$"; 35 #endif /* not lint */ 36 37 #include <sys/param.h> 38 #include <sys/ioctl.h> 39 #include <sys/socket.h> 40 #include <net/if.h> 41 42 #include <ctype.h> 43 #include <err.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <ifaddrs.h> 49 50 #include <netinet/in.h> 51 #include <netinet/in_var.h> 52 #include <arpa/inet.h> 53 #include <netdb.h> 54 55 #include "ifconfig.h" 56 #include "ifconfig_netlink.h" 57 58 #ifdef WITHOUT_NETLINK 59 static struct in_aliasreq in_addreq; 60 static struct ifreq in_ridreq; 61 #else 62 struct in_px { 63 struct in_addr addr; 64 int plen; 65 bool addrset; 66 bool maskset; 67 }; 68 struct in_pdata { 69 struct in_px addr; 70 struct in_px dst_addr; 71 struct in_px brd_addr; 72 uint32_t flags; 73 uint32_t vhid; 74 }; 75 static struct in_pdata in_add, in_del; 76 #endif 77 78 static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/ 79 extern char *f_inet, *f_addr; 80 81 static void 82 print_addr(struct sockaddr_in *sin) 83 { 84 int error, n_flags; 85 86 if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0) 87 n_flags = 0; 88 else if (f_addr != NULL && strcmp(f_addr, "host") == 0) 89 n_flags = NI_NOFQDN; 90 else 91 n_flags = NI_NUMERICHOST; 92 93 error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf, 94 sizeof(addr_buf), NULL, 0, n_flags); 95 96 if (error) 97 inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf)); 98 99 printf("\tinet %s", addr_buf); 100 } 101 102 #ifdef WITHOUT_NETLINK 103 static void 104 in_status(if_ctx *ctx __unused, const struct ifaddrs *ifa) 105 { 106 struct sockaddr_in *sin, null_sin = {}; 107 108 sin = satosin(ifa->ifa_addr); 109 if (sin == NULL) 110 return; 111 112 print_addr(sin); 113 114 if (ifa->ifa_flags & IFF_POINTOPOINT) { 115 sin = satosin(ifa->ifa_dstaddr); 116 if (sin == NULL) 117 sin = &null_sin; 118 printf(" --> %s", inet_ntoa(sin->sin_addr)); 119 } 120 121 sin = satosin(ifa->ifa_netmask); 122 if (sin == NULL) 123 sin = &null_sin; 124 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { 125 int cidr = 32; 126 unsigned long smask; 127 128 smask = ntohl(sin->sin_addr.s_addr); 129 while ((smask & 1) == 0) { 130 smask = smask >> 1; 131 cidr--; 132 if (cidr == 0) 133 break; 134 } 135 printf("/%d", cidr); 136 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) 137 printf(" netmask %s", inet_ntoa(sin->sin_addr)); 138 else 139 printf(" netmask 0x%lx", (unsigned long)ntohl(sin->sin_addr.s_addr)); 140 141 if (ifa->ifa_flags & IFF_BROADCAST) { 142 sin = satosin(ifa->ifa_broadaddr); 143 if (sin != NULL && sin->sin_addr.s_addr != 0) 144 printf(" broadcast %s", inet_ntoa(sin->sin_addr)); 145 } 146 147 print_vhid(ifa); 148 149 putchar('\n'); 150 } 151 152 #else 153 static struct in_addr 154 get_mask(int plen) 155 { 156 struct in_addr a; 157 158 a.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0); 159 160 return (a); 161 } 162 163 static void 164 in_status_nl(if_ctx *ctx __unused, if_link_t *link, if_addr_t *ifa) 165 { 166 struct sockaddr_in *sin = satosin(ifa->ifa_local); 167 int plen = ifa->ifa_prefixlen; 168 169 print_addr(sin); 170 171 if (link->ifi_flags & IFF_POINTOPOINT) { 172 struct sockaddr_in *dst = satosin(ifa->ifa_address); 173 174 printf(" --> %s", inet_ntoa(dst->sin_addr)); 175 } 176 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { 177 printf("/%d", plen); 178 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) 179 printf(" netmask %s", inet_ntoa(get_mask(plen))); 180 else 181 printf(" netmask 0x%lx", (unsigned long)ntohl(get_mask(plen).s_addr)); 182 183 if ((link->ifi_flags & IFF_BROADCAST) && plen != 0) { 184 struct sockaddr_in *brd = satosin(ifa->ifa_broadcast); 185 if (brd != NULL) 186 printf(" broadcast %s", inet_ntoa(brd->sin_addr)); 187 } 188 189 if (ifa->ifaf_vhid != 0) 190 printf(" vhid %d", ifa->ifaf_vhid); 191 192 putchar('\n'); 193 } 194 #endif 195 196 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) 202 }; 203 204 static void 205 in_copyaddr(if_ctx *ctx __unused, int to, int from) 206 { 207 memcpy(sintab[to], sintab[from], sizeof(struct sockaddr_in)); 208 } 209 210 static void 211 in_getaddr(const char *s, int which) 212 { 213 struct sockaddr_in *sin = sintab[which]; 214 struct hostent *hp; 215 struct netent *np; 216 217 sin->sin_len = sizeof(*sin); 218 sin->sin_family = AF_INET; 219 220 if (which == ADDR) { 221 char *p = NULL; 222 223 if((p = strrchr(s, '/')) != NULL) { 224 const char *errstr; 225 /* address is `name/masklen' */ 226 int masklen = 0; 227 struct sockaddr_in *min = sintab[MASK]; 228 *p = '\0'; 229 if (!isdigit(*(p + 1))) 230 errstr = "invalid"; 231 else 232 masklen = (int)strtonum(p + 1, 0, 32, &errstr); 233 if (errstr != NULL) { 234 *p = '/'; 235 errx(1, "%s: bad value (width %s)", s, errstr); 236 } 237 min->sin_family = AF_INET; 238 min->sin_len = sizeof(*min); 239 min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 240 0xffffffff); 241 } 242 } 243 244 if (inet_aton(s, &sin->sin_addr)) 245 return; 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); 251 else 252 errx(1, "%s: bad value", s); 253 } 254 255 #else 256 257 static struct in_px *sintab_nl[] = { 258 &in_del.addr, /* RIDADDR */ 259 &in_add.addr, /* ADDR */ 260 NULL, /* MASK */ 261 &in_add.dst_addr, /* DSTADDR*/ 262 &in_add.brd_addr, /* BRDADDR*/ 263 }; 264 265 static void 266 in_copyaddr(if_ctx *ctx __unused, int to, int from) 267 { 268 sintab_nl[to]->addr = sintab_nl[from]->addr; 269 sintab_nl[to]->addrset = sintab_nl[from]->addrset; 270 } 271 272 static void 273 in_getip(const char *addr_str, struct in_addr *ip) 274 { 275 struct hostent *hp; 276 struct netent *np; 277 278 if (inet_aton(addr_str, ip)) 279 return; 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); 285 else 286 errx(1, "%s: bad value", addr_str); 287 } 288 289 static void 290 in_getaddr(const char *s, int which) 291 { 292 struct in_px *px = sintab_nl[which]; 293 294 if (which == MASK) { 295 struct in_px *px_addr = sintab_nl[ADDR]; 296 struct in_addr mask = {}; 297 298 in_getip(s, &mask); 299 px_addr->plen = __bitcount32(mask.s_addr); 300 px_addr->maskset = true; 301 return; 302 } 303 304 if (which == ADDR) { 305 char *p = NULL; 306 307 if((p = strrchr(s, '/')) != NULL) { 308 const char *errstr; 309 /* address is `name/masklen' */ 310 int masklen; 311 *p = '\0'; 312 if (!isdigit(*(p + 1))) 313 errstr = "invalid"; 314 else 315 masklen = (int)strtonum(p + 1, 0, 32, &errstr); 316 if (errstr != NULL) { 317 *p = '/'; 318 errx(1, "%s: bad value (width %s)", s, errstr); 319 } 320 px->plen = masklen; 321 px->maskset = true; 322 } 323 } 324 325 in_getip(s, &px->addr); 326 px->addrset = true; 327 } 328 329 /* 330 * Deletes the first found IPv4 interface address for the interface. 331 * 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. 337 */ 338 static int 339 in_delete_first_nl(if_ctx *ctx) 340 { 341 struct nlmsghdr *hdr; 342 struct ifaddrmsg *ifahdr; 343 uint32_t nlmsg_seq; 344 struct in_addr addr; 345 struct snl_writer nw = {}; 346 struct snl_errmsg_data e = {}; 347 struct snl_state *ss = ctx->io_ss; 348 bool found = false; 349 350 uint32_t ifindex = if_nametoindex_nl(ss, ctx->ifname); 351 if (ifindex == 0) { 352 /* No interface with the desired name, nothing to delete */ 353 return (EADDRNOTAVAIL); 354 } 355 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; 362 363 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 364 return (EINVAL); 365 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; 372 found = true; 373 break; 374 } else 375 return (EINVAL); 376 } 377 if (e.error != 0) { 378 if (e.error_str != NULL) 379 warnx("%s(): %s", __func__, e.error_str); 380 return (e.error); 381 } 382 383 if (!found) 384 return (0); 385 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); 393 394 if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr)) 395 return (EINVAL); 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); 400 401 return (e.error); 402 } 403 404 405 static int 406 in_exec_nl(if_ctx *ctx, unsigned long action, void *data) 407 { 408 struct in_pdata *pdata = (struct in_pdata *)data; 409 struct snl_writer nw = {}; 410 411 if (action == NL_RTM_DELADDR && !pdata->addr.addrset) 412 return (in_delete_first_nl(ctx)); 413 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); 417 418 ifahdr->ifa_family = AF_INET; 419 ifahdr->ifa_prefixlen = pdata->addr.plen; 420 ifahdr->ifa_index = if_nametoindex_nl(ctx->io_ss, ctx->ifname); 421 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); 427 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); 433 434 if (!snl_finalize_msg(&nw) || !snl_send_message(ctx->io_ss, hdr)) 435 return (0); 436 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); 441 442 return (e.error); 443 } 444 445 static void 446 in_setdefaultmask_nl(void) 447 { 448 struct in_px *px = sintab_nl[ADDR]; 449 450 in_addr_t i = ntohl(px->addr.s_addr); 451 452 /* 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. 457 */ 458 if (IN_CLASSA(i)) 459 px->plen = IN_CLASSA_NSHIFT; 460 else if (IN_CLASSB(i)) 461 px->plen = IN_CLASSB_NSHIFT; 462 else 463 px->plen = IN_CLASSC_NSHIFT; 464 px->maskset = true; 465 } 466 #endif 467 468 static void 469 warn_nomask(int ifflags) 470 { 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."); 474 } 475 } 476 477 static void 478 in_postproc(if_ctx *ctx __unused, int newaddr, int ifflags) 479 { 480 #ifdef WITHOUT_NETLINK 481 if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && newaddr) { 482 warn_nomask(ifflags); 483 } 484 #else 485 if (sintab_nl[ADDR]->addrset && !sintab_nl[ADDR]->maskset && newaddr) { 486 warn_nomask(ifflags); 487 in_setdefaultmask_nl(); 488 } 489 #endif 490 } 491 492 static void 493 in_status_tunnel(if_ctx *ctx) 494 { 495 char src[NI_MAXHOST]; 496 char dst[NI_MAXHOST]; 497 struct ifreq ifr; 498 const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; 499 500 memset(&ifr, 0, sizeof(ifr)); 501 strlcpy(ifr.ifr_name, ctx->ifname, IFNAMSIZ); 502 503 if (ioctl_ctx(ctx, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) 504 return; 505 if (sa->sa_family != AF_INET) 506 return; 507 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) 508 src[0] = '\0'; 509 510 if (ioctl_ctx(ctx, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0) 511 return; 512 if (sa->sa_family != AF_INET) 513 return; 514 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) 515 dst[0] = '\0'; 516 517 printf("\ttunnel inet %s --> %s\n", src, dst); 518 } 519 520 static void 521 in_set_tunnel(if_ctx *ctx, struct addrinfo *srcres, struct addrinfo *dstres) 522 { 523 struct in_aliasreq addreq; 524 525 memset(&addreq, 0, sizeof(addreq)); 526 strlcpy(addreq.ifra_name, ctx->ifname, 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); 529 530 if (ioctl_ctx(ctx, SIOCSIFPHYADDR, &addreq) < 0) 531 warn("SIOCSIFPHYADDR"); 532 } 533 534 static void 535 in_set_vhid(int vhid) 536 { 537 #ifdef WITHOUT_NETLINK 538 in_addreq.ifra_vhid = vhid; 539 #else 540 in_add.vhid = (uint32_t)vhid; 541 #endif 542 } 543 544 static struct afswtch af_inet = { 545 .af_name = "inet", 546 .af_af = AF_INET, 547 #ifdef WITHOUT_NETLINK 548 .af_status = in_status, 549 #else 550 .af_status = in_status_nl, 551 #endif 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, 564 #else 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, 570 #endif 571 }; 572 573 static __constructor void 574 inet_ctor(void) 575 { 576 577 #ifndef RESCUE 578 if (!feature_present("inet")) 579 return; 580 #endif 581 af_register(&af_inet); 582 } 583