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(int s __unused, const struct ifaddrs *ifa) 105 { 106 struct sockaddr_in *sin, null_sin = {}; 107 108 sin = (struct sockaddr_in *)ifa->ifa_addr; 109 if (sin == NULL) 110 return; 111 112 print_addr(sin); 113 114 if (ifa->ifa_flags & IFF_POINTOPOINT) { 115 sin = (struct sockaddr_in *)ifa->ifa_dstaddr; 116 if (sin == NULL) 117 sin = &null_sin; 118 printf(" --> %s", inet_ntoa(sin->sin_addr)); 119 } 120 121 sin = (struct sockaddr_in *)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 = (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)); 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 struct sockaddr_in * 164 satosin(struct sockaddr *sa) 165 { 166 return ((struct sockaddr_in *)(void *)sa); 167 } 168 169 static void 170 in_status_nl(struct ifconfig_args *args __unused, struct io_handler *h, 171 if_link_t *link, if_addr_t *ifa) 172 { 173 struct sockaddr_in *sin = satosin(ifa->ifa_local); 174 int plen = ifa->ifa_prefixlen; 175 176 print_addr(sin); 177 178 if (link->ifi_flags & IFF_POINTOPOINT) { 179 struct sockaddr_in *dst = satosin(ifa->ifa_address); 180 181 printf(" --> %s", inet_ntoa(dst->sin_addr)); 182 } 183 if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { 184 printf("/%d", plen); 185 } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) 186 printf(" netmask %s", inet_ntoa(get_mask(plen))); 187 else 188 printf(" netmask 0x%lx", (unsigned long)ntohl(get_mask(plen).s_addr)); 189 190 if ((link->ifi_flags & IFF_BROADCAST) && plen != 0) { 191 struct sockaddr_in *brd = satosin(ifa->ifa_broadcast); 192 if (brd != NULL) 193 printf(" broadcast %s", inet_ntoa(brd->sin_addr)); 194 } 195 196 if (ifa->ifaf_vhid != 0) 197 printf(" vhid %d", ifa->ifaf_vhid); 198 199 putchar('\n'); 200 } 201 #endif 202 203 204 #ifdef WITHOUT_NETLINK 205 #define SIN(x) ((struct sockaddr_in *) &(x)) 206 static struct sockaddr_in *sintab[] = { 207 SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr), 208 SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr) 209 }; 210 211 static void 212 in_getaddr(const char *s, int which) 213 { 214 struct sockaddr_in *sin = sintab[which]; 215 struct hostent *hp; 216 struct netent *np; 217 218 sin->sin_len = sizeof(*sin); 219 sin->sin_family = AF_INET; 220 221 if (which == ADDR) { 222 char *p = NULL; 223 224 if((p = strrchr(s, '/')) != NULL) { 225 const char *errstr; 226 /* address is `name/masklen' */ 227 int masklen; 228 struct sockaddr_in *min = sintab[MASK]; 229 *p = '\0'; 230 if (!isdigit(*(p + 1))) 231 errstr = "invalid"; 232 else 233 masklen = (int)strtonum(p + 1, 0, 32, &errstr); 234 if (errstr != NULL) { 235 *p = '/'; 236 errx(1, "%s: bad value (width %s)", s, errstr); 237 } 238 min->sin_family = AF_INET; 239 min->sin_len = sizeof(*min); 240 min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & 241 0xffffffff); 242 } 243 } 244 245 if (inet_aton(s, &sin->sin_addr)) 246 return; 247 if ((hp = gethostbyname(s)) != NULL) 248 bcopy(hp->h_addr, (char *)&sin->sin_addr, 249 MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); 250 else if ((np = getnetbyname(s)) != NULL) 251 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 252 else 253 errx(1, "%s: bad value", s); 254 } 255 256 #else 257 258 static struct in_px *sintab_nl[] = { 259 &in_del.addr, /* RIDADDR */ 260 &in_add.addr, /* ADDR */ 261 NULL, /* MASK */ 262 &in_add.dst_addr, /* DSTADDR*/ 263 &in_add.brd_addr, /* BRDADDR*/ 264 }; 265 266 static void 267 in_getip(const char *addr_str, struct in_addr *ip) 268 { 269 struct hostent *hp; 270 struct netent *np; 271 272 if (inet_aton(addr_str, ip)) 273 return; 274 if ((hp = gethostbyname(addr_str)) != NULL) 275 bcopy(hp->h_addr, (char *)ip, 276 MIN((size_t)hp->h_length, sizeof(ip))); 277 else if ((np = getnetbyname(addr_str)) != NULL) 278 *ip = inet_makeaddr(np->n_net, INADDR_ANY); 279 else 280 errx(1, "%s: bad value", addr_str); 281 } 282 283 static void 284 in_getaddr(const char *s, int which) 285 { 286 struct in_px *px = sintab_nl[which]; 287 288 if (which == MASK) { 289 struct in_px *px_addr = sintab_nl[ADDR]; 290 struct in_addr mask = {}; 291 292 in_getip(s, &mask); 293 px_addr->plen = __bitcount32(mask.s_addr); 294 px_addr->maskset = true; 295 return; 296 } 297 298 if (which == ADDR) { 299 char *p = NULL; 300 301 if((p = strrchr(s, '/')) != NULL) { 302 const char *errstr; 303 /* address is `name/masklen' */ 304 int masklen; 305 *p = '\0'; 306 if (!isdigit(*(p + 1))) 307 errstr = "invalid"; 308 else 309 masklen = (int)strtonum(p + 1, 0, 32, &errstr); 310 if (errstr != NULL) { 311 *p = '/'; 312 errx(1, "%s: bad value (width %s)", s, errstr); 313 } 314 px->plen = masklen; 315 px->maskset = true; 316 } 317 } 318 319 in_getip(s, &px->addr); 320 px->addrset = true; 321 } 322 323 324 static int 325 in_exec_nl(struct io_handler *h, int action, void *data) 326 { 327 struct in_pdata *pdata = (struct in_pdata *)data; 328 struct snl_writer nw = {}; 329 330 snl_init_writer(h->ss, &nw); 331 struct nlmsghdr *hdr = snl_create_msg_request(&nw, action); 332 struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg); 333 334 ifahdr->ifa_family = AF_INET; 335 ifahdr->ifa_prefixlen = pdata->addr.plen; 336 ifahdr->ifa_index = if_nametoindex_nl(h->ss, name); 337 338 snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &pdata->addr.addr); 339 if (action == NL_RTM_NEWADDR && pdata->dst_addr.addrset) 340 snl_add_msg_attr_ip4(&nw, IFA_ADDRESS, &pdata->dst_addr.addr); 341 if (action == NL_RTM_NEWADDR && pdata->brd_addr.addrset) 342 snl_add_msg_attr_ip4(&nw, IFA_BROADCAST, &pdata->brd_addr.addr); 343 344 int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD); 345 snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags); 346 if (pdata->vhid != 0) 347 snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid); 348 snl_end_attr_nested(&nw, off); 349 350 if (!snl_finalize_msg(&nw) || !snl_send_message(h->ss, hdr)) 351 return (0); 352 353 struct snl_errmsg_data e = {}; 354 snl_read_reply_code(h->ss, hdr->nlmsg_seq, &e); 355 if (e.error_str != NULL) 356 warnx("%s(): %s", __func__, e.error_str); 357 358 return (e.error); 359 } 360 361 static void 362 in_setdefaultmask_nl(void) 363 { 364 struct in_px *px = sintab_nl[ADDR]; 365 366 in_addr_t i = ntohl(px->addr.s_addr); 367 368 /* 369 * If netmask isn't supplied, use historical default. 370 * This is deprecated for interfaces other than loopback 371 * or point-to-point; warn in other cases. In the future 372 * we should return an error rather than warning. 373 */ 374 if (IN_CLASSA(i)) 375 px->plen = IN_CLASSA_NSHIFT; 376 else if (IN_CLASSB(i)) 377 px->plen = IN_CLASSB_NSHIFT; 378 else 379 px->plen = IN_CLASSC_NSHIFT; 380 px->maskset = true; 381 } 382 #endif 383 384 static void 385 warn_nomask(int ifflags) 386 { 387 if ((ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { 388 warnx("WARNING: setting interface address without mask " 389 "is deprecated,\ndefault mask may not be correct."); 390 } 391 } 392 393 static void 394 in_postproc(int s, const struct afswtch *afp, int newaddr, int ifflags) 395 { 396 #ifdef WITHOUT_NETLINK 397 if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && newaddr) { 398 warn_nomask(ifflags); 399 } 400 #else 401 if (sintab_nl[ADDR]->addrset && !sintab_nl[ADDR]->maskset && newaddr) { 402 warn_nomask(ifflags); 403 in_setdefaultmask_nl(); 404 } 405 #endif 406 } 407 408 static void 409 in_status_tunnel(int s) 410 { 411 char src[NI_MAXHOST]; 412 char dst[NI_MAXHOST]; 413 struct ifreq ifr; 414 const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; 415 416 memset(&ifr, 0, sizeof(ifr)); 417 strlcpy(ifr.ifr_name, name, IFNAMSIZ); 418 419 if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) 420 return; 421 if (sa->sa_family != AF_INET) 422 return; 423 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) 424 src[0] = '\0'; 425 426 if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0) 427 return; 428 if (sa->sa_family != AF_INET) 429 return; 430 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) 431 dst[0] = '\0'; 432 433 printf("\ttunnel inet %s --> %s\n", src, dst); 434 } 435 436 static void 437 in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) 438 { 439 struct in_aliasreq addreq; 440 441 memset(&addreq, 0, sizeof(addreq)); 442 strlcpy(addreq.ifra_name, name, IFNAMSIZ); 443 memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); 444 memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); 445 446 if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) 447 warn("SIOCSIFPHYADDR"); 448 } 449 450 static void 451 in_set_vhid(int vhid) 452 { 453 #ifdef WITHOUT_NETLINK 454 in_addreq.ifra_vhid = vhid; 455 #else 456 in_add.vhid = (uint32_t)vhid; 457 #endif 458 } 459 460 static struct afswtch af_inet = { 461 .af_name = "inet", 462 .af_af = AF_INET, 463 #ifdef WITHOUT_NETLINK 464 .af_status = in_status, 465 #else 466 .af_status_nl = in_status_nl, 467 #endif 468 .af_getaddr = in_getaddr, 469 .af_postproc = in_postproc, 470 .af_status_tunnel = in_status_tunnel, 471 .af_settunnel = in_set_tunnel, 472 .af_setvhid = in_set_vhid, 473 #ifdef WITHOUT_NETLINK 474 .af_difaddr = SIOCDIFADDR, 475 .af_aifaddr = SIOCAIFADDR, 476 .af_ridreq = &in_ridreq, 477 .af_addreq = &in_addreq, 478 .af_exec = af_exec_ioctl, 479 #else 480 .af_difaddr = NL_RTM_DELADDR, 481 .af_aifaddr = NL_RTM_NEWADDR, 482 .af_ridreq = &in_del, 483 .af_addreq = &in_add, 484 .af_exec = in_exec_nl, 485 #endif 486 }; 487 488 static __constructor void 489 inet_ctor(void) 490 { 491 492 #ifndef RESCUE 493 if (!feature_present("inet")) 494 return; 495 #endif 496 af_register(&af_inet); 497 } 498