1 /* $NetBSD: wire.c,v 1.1.1.3 2015/01/17 16:34:18 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2014 Erez Zadok 5 * Copyright (c) 1990 Jan-Simon Pendry 6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Jan-Simon Pendry at Imperial College, London. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * 38 * File: am-utils/libamu/wire.c 39 * 40 */ 41 42 /* 43 * This function returns the subnet (address&netmask) for the primary network 44 * interface. If the resulting address has an entry in the hosts file, the 45 * corresponding name is returned, otherwise the address is returned in 46 * standard internet format. 47 * As a side-effect, a list of local IP/net address is recorded for use 48 * by the islocalnet() function. 49 * 50 * Derived from original by Paul Anderson (23/4/90) 51 * Updates from Dirk Grunwald (11/11/91) 52 */ 53 54 #ifdef HAVE_CONFIG_H 55 # include <config.h> 56 #endif /* HAVE_CONFIG_H */ 57 #include <am_defs.h> 58 #include <amu.h> 59 60 61 #ifdef HAVE_IFADDRS_H 62 #include <ifaddrs.h> 63 #endif /* HAVE_IFADDRS_H */ 64 65 #ifdef HAVE_IRS_H 66 # include <irs.h> 67 #endif /* HAVE_IRS_H */ 68 69 /* 70 * List of locally connected networks 71 */ 72 typedef struct addrlist addrlist; 73 struct addrlist { 74 addrlist *ip_next; 75 u_long ip_addr; /* address of network */ 76 u_long ip_mask; 77 char *ip_net_num; /* number of network */ 78 char *ip_net_name; /* name of network */ 79 }; 80 static addrlist *localnets = NULL; 81 82 #if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) 83 # define IFF_LOOPBACK IFF_LOCAL_LOOPBACK 84 #endif /* defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) */ 85 86 #define C(x) ((x) & 0xff) 87 #define GFBUFLEN 1024 88 #define S2IN(s) (((struct sockaddr_in *)(s))->sin_addr.s_addr) 89 90 91 /* return malloc'ed buffer. caller must free it */ 92 char * 93 print_wires(void) 94 { 95 addrlist *al; 96 char s[256]; 97 int i; 98 char *buf; 99 int bufcount = 0; 100 int buf_size = 1024; 101 102 buf = SALLOC(buf_size); /* initial allocation (may grow!) */ 103 if (!buf) 104 return NULL; 105 106 if (!localnets) { 107 xstrlcpy(buf, "No networks\n", buf_size); 108 return buf; 109 } 110 /* check if there's more than one network */ 111 if (!localnets->ip_next) { 112 /* use buf_size for sizeof(buf) because of the realloc() below */ 113 xsnprintf(buf, buf_size, 114 "Network: wire=\"%s\" (netnumber=%s).\n", 115 localnets->ip_net_name, localnets->ip_net_num); 116 return buf; 117 } 118 buf[0] = '\0'; /* null out buffer before appending */ 119 for (i = 1, al = localnets; al; al = al->ip_next, i++) { 120 xsnprintf(s, sizeof(s), "Network %d: wire=\"%s\" (netnumber=%s).\n", 121 i, al->ip_net_name, al->ip_net_num); 122 bufcount += strlen(s); 123 if (bufcount > buf_size) { 124 buf_size *= 2; 125 buf = xrealloc(buf, buf_size); 126 } 127 xstrlcat(buf, s, buf_size); 128 } 129 return buf; 130 } 131 132 133 static struct addrlist * 134 getwire_lookup(u_long address, u_long netmask, int ishost) 135 { 136 struct addrlist *al; 137 u_long subnet; 138 char netNumberBuf[64]; 139 char buf[GFBUFLEN], *s; 140 #ifdef HAVE_IRS_H 141 struct nwent *np; 142 #else /* not HAVE_IRS_H */ 143 struct netent *np; 144 #endif /* not HAVE_IRS_H */ 145 146 /* 147 * Add interface to local network singly linked list 148 */ 149 al = ALLOC(struct addrlist); 150 al->ip_addr = address; 151 al->ip_mask = netmask; 152 al->ip_net_name = NO_SUBNET; /* fill in a bit later */ 153 al->ip_net_num = "0.0.0.0"; /* fill in a bit later */ 154 al->ip_next = NULL; 155 156 subnet = ntohl(address) & ntohl(netmask); 157 158 if (ishost) 159 np = NULL; 160 else { 161 #ifdef HAVE_IRS_H 162 u_long mask = ntohl(netmask); 163 static struct irs_acc *irs_gen; 164 static struct irs_nw *irs_nw; 165 u_long net; 166 int maskbits; 167 u_char addr[4]; 168 169 if (irs_gen == NULL) 170 #ifdef irs_irp_acc 171 /* 172 * bsdi4 added another argument to this function, without changing 173 * its name. The irs_irp_acc is the one (hacky) distinguishing 174 * feature found in <irs.h> that can differentiate between bsdi3 and 175 * bsdi4. 176 */ 177 irs_gen = irs_gen_acc("", NULL); 178 #else /* not irs_irp_acc */ 179 irs_gen = irs_gen_acc(""); 180 #endif /* not irs_irp_acc */ 181 if (irs_gen && irs_nw == NULL) 182 irs_nw = (*irs_gen->nw_map)(irs_gen); 183 net = ntohl(address) & (mask = ntohl(netmask)); 184 addr[0] = (0xFF000000 & net) >> 24; 185 addr[1] = (0x00FF0000 & net) >> 16; 186 addr[2] = (0x0000FF00 & net) >> 8; 187 addr[3] = (0x000000FF & net); 188 for (maskbits = 32; !(mask & 1); mask >>= 1) 189 maskbits--; 190 np = (*irs_nw->byaddr)(irs_nw, addr, maskbits, AF_INET); 191 #else /* not HAVE_IRS_H */ 192 np = getnetbyaddr(subnet, AF_INET); 193 /* 194 * Some systems (IRIX 6.4) cannot getnetbyaddr on networks such as 195 * "128.59.16.0". Instead, they need to look for the short form of 196 * the network, "128.59.16". So if the first getnetbyaddr failed, we 197 * shift the subnet way from zeros and try again. 198 */ 199 if (!np) { 200 u_long short_subnet = subnet; 201 while (short_subnet && (short_subnet & 0x000000ff) == 0) 202 short_subnet >>= 8; 203 np = getnetbyaddr(short_subnet, AF_INET); 204 if (np) 205 plog(XLOG_WARNING, "getnetbyaddr failed on 0x%x, succeeded on 0x%x", 206 (u_int) subnet, (u_int) short_subnet); 207 } 208 #endif /* not HAVE_IRS_H */ 209 } 210 211 if ((subnet & 0xffffff) == 0) { 212 xsnprintf(netNumberBuf, sizeof(netNumberBuf), "%lu", C(subnet >> 24)); 213 } else if ((subnet & 0xffff) == 0) { 214 xsnprintf(netNumberBuf, sizeof(netNumberBuf), "%lu.%lu", 215 C(subnet >> 24), C(subnet >> 16)); 216 } else if ((subnet & 0xff) == 0) { 217 xsnprintf(netNumberBuf, sizeof(netNumberBuf), "%lu.%lu.%lu", 218 C(subnet >> 24), C(subnet >> 16), 219 C(subnet >> 8)); 220 } else { 221 xsnprintf(netNumberBuf, sizeof(netNumberBuf), "%lu.%lu.%lu.%lu", 222 C(subnet >> 24), C(subnet >> 16), 223 C(subnet >> 8), C(subnet)); 224 } 225 226 /* fill in network number (string) */ 227 al->ip_net_num = xstrdup(netNumberBuf); 228 229 if (np != NULL) 230 s = np->n_name; 231 else { 232 struct hostent *hp; 233 234 subnet = address & netmask; 235 hp = gethostbyaddr((char *) &subnet, 4, AF_INET); 236 if (hp != NULL) 237 s = (char *) hp->h_name; 238 else 239 s = inet_dquad(buf, sizeof(buf), subnet); 240 } 241 242 /* fill in network name (string) */ 243 al->ip_net_name = xstrdup(s); 244 /* Let's be cautious here about buffer overflows -Ion */ 245 if (strlen(s) > MAXHOSTNAMELEN) { 246 al->ip_net_name[MAXHOSTNAMELEN] = '\0'; 247 plog(XLOG_WARNING, "Long hostname %s truncated to %d characters", 248 s, MAXHOSTNAMELEN); 249 } 250 251 return (al); 252 } 253 254 255 /* 256 * Make a dotted quad from a 32bit IP address 257 * addr is in network byte order. 258 * sizeof(buf) needs to be at least 16. 259 */ 260 char * 261 inet_dquad(char *buf, size_t l, u_long addr) 262 { 263 addr = ntohl(addr); 264 xsnprintf(buf, l, "%ld.%ld.%ld.%ld", 265 ((addr >> 24) & 0xff), 266 ((addr >> 16) & 0xff), 267 ((addr >> 8) & 0xff), 268 ((addr >> 0) & 0xff)); 269 return buf; 270 } 271 272 273 /* 274 * Determine whether a network is on a local network 275 * (addr) is in network byte order. 276 */ 277 int 278 islocalnet(u_long addr) 279 { 280 addrlist *al; 281 282 for (al = localnets; al; al = al->ip_next) 283 if (((addr ^ al->ip_addr) & al->ip_mask) == 0) 284 return TRUE; 285 286 #ifdef DEBUG 287 { 288 char buf[16]; 289 plog(XLOG_INFO, "%s is on a remote network", 290 inet_dquad(buf, sizeof(buf), addr)); 291 } 292 #endif /* DEBUG */ 293 294 return FALSE; 295 } 296 297 298 /* 299 * Determine whether a network name is one of the local networks 300 * of a host. 301 */ 302 int 303 is_network_member(const char *net) 304 { 305 addrlist *al; 306 307 /* 308 * If the network name string does not contain a '/', use old behavior. 309 * If it does contain a '/' then interpret the string as a network/netmask 310 * pair. If "netmask" doesn't exist, use the interface's own netmask. 311 * Also support fully explicit netmasks such as 255.255.255.0 as well as 312 * bit-length netmask such as /24 (hex formats such 0xffffff00 work too). 313 */ 314 if (strchr(net, '/') == NULL) { 315 for (al = localnets; al; al = al->ip_next) 316 if (STREQ(net, al->ip_net_name) || STREQ(net, al->ip_net_num)) 317 return TRUE; 318 } else { 319 char *netstr = xstrdup(net), *maskstr; 320 u_long netnum, masknum = 0; 321 maskstr = strchr(netstr, '/'); 322 if (maskstr == NULL) { 323 plog(XLOG_ERROR, "%s: netstr %s does not have a `/'", __func__, netstr); 324 XFREE(netstr); 325 return FALSE; 326 } 327 maskstr[0] = '\0'; /* null terminate netstr */ 328 maskstr++; 329 if (*maskstr == '\0') /* if empty string, make it NULL */ 330 maskstr = NULL; 331 /* check if netmask uses a dotted-quad or bit-length, or not defined at all */ 332 if (maskstr) { 333 if (strchr(maskstr, '.')) { 334 /* XXX: inet_addr is obsolste, convert to inet_aton() */ 335 masknum = inet_addr(maskstr); 336 if (masknum == INADDR_NONE) /* can be invalid (-1) or all-1s */ 337 masknum = 0xffffffff; 338 } else if (NSTRCEQ(maskstr, "0x", 2)) { 339 masknum = strtoul(maskstr, NULL, 16); 340 } else { 341 int bits = atoi(maskstr); 342 if (bits < 0) 343 bits = 0; 344 if (bits > 32) 345 bits = 32; 346 masknum = 0xffffffff << (32-bits); 347 } 348 } 349 netnum = inet_addr(netstr); /* not checking return value, b/c -1 (0xffffffff) is valid */ 350 XFREE(netstr); /* netstr not needed any longer */ 351 352 /* now check against each local interface */ 353 for (al = localnets; al; al = al->ip_next) { 354 if ((al->ip_addr & (maskstr ? masknum : al->ip_mask)) == netnum) 355 return TRUE; 356 } 357 } 358 359 return FALSE; 360 } 361 362 363 /* 364 * Determine whether a IP address (netnum) is one of the local interfaces, 365 * returns TRUE/FALSE. 366 * Does not include the loopback interface: caller needs to check that. 367 */ 368 int 369 is_interface_local(u_long netnum) 370 { 371 addrlist *al; 372 373 for (al = localnets; al; al = al->ip_next) { 374 if (al->ip_addr == netnum) 375 return TRUE; 376 } 377 return FALSE; 378 } 379 380 381 #ifdef HAVE_GETIFADDRS 382 void 383 getwire(char **name1, char **number1) 384 { 385 addrlist *al = NULL, *tail = NULL; 386 struct ifaddrs *ifaddrs, *ifap; 387 #ifndef HAVE_STRUCT_IFADDRS_IFA_NEXT 388 int count = 0, i; 389 #endif /* not HAVE_STRUCT_IFADDRS_IFA_NEXT */ 390 391 ifaddrs = NULL; 392 #ifdef HAVE_STRUCT_IFADDRS_IFA_NEXT 393 if (getifaddrs(&ifaddrs) < 0) 394 goto out; 395 396 for (ifap = ifaddrs; ifap != NULL; ifap = ifap->ifa_next) { 397 #else /* not HAVE_STRUCT_IFADDRS_IFA_NEXT */ 398 if (getifaddrs(&ifaddrs, &count) < 0) 399 goto out; 400 401 for (i = 0,ifap = ifaddrs; i < count; ifap++, i++) { 402 #endif /* HAVE_STRUCT_IFADDRS_IFA_NEXT */ 403 404 if (!ifap || !ifap->ifa_addr || ifap->ifa_addr->sa_family != AF_INET) 405 continue; 406 407 /* 408 * If the interface is the loopback, or it's not running, 409 * then ignore it. 410 */ 411 if (S2IN(ifap->ifa_addr) == htonl(INADDR_LOOPBACK)) 412 continue; 413 if ((ifap->ifa_flags & IFF_RUNNING) == 0) 414 continue; 415 416 if ((ifap->ifa_flags & IFF_POINTOPOINT) == 0) 417 al = getwire_lookup(S2IN(ifap->ifa_addr), S2IN(ifap->ifa_netmask), 0); 418 else 419 al = getwire_lookup(S2IN(ifap->ifa_dstaddr), 0xffffffff, 1); 420 421 /* append to the end of the list */ 422 if (!localnets || tail == NULL) { 423 localnets = tail = al; 424 tail->ip_next = NULL; 425 } else { 426 tail->ip_next = al; 427 tail = al; 428 } 429 } 430 431 out: 432 if (ifaddrs) 433 XFREE(ifaddrs); 434 435 if (localnets) { 436 *name1 = localnets->ip_net_name; 437 *number1 = localnets->ip_net_num; 438 } else { 439 *name1 = NO_SUBNET; 440 *number1 = "0.0.0.0"; 441 } 442 } 443 444 #else /* not HAVE_GETIFADDRS */ 445 446 #if defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN) 447 # define SIZE(ifr) (MAX((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name)) 448 #else /* not defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN) */ 449 # define SIZE(ifr) sizeof(struct ifreq) 450 #endif /* not defined(HAVE_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_STRUCT_SOCKADDR_SA_LEN) */ 451 452 #define clist (ifc.ifc_ifcu.ifcu_req) 453 #define count (ifc.ifc_len/sizeof(struct ifreq)) 454 455 456 void 457 getwire(char **name1, char **number1) 458 { 459 struct ifconf ifc; 460 struct ifreq *ifr, ifrpool; 461 caddr_t cp, cplim; 462 int fd = -1; 463 u_long address; 464 addrlist *al = NULL, *tail = NULL; 465 char buf[GFBUFLEN]; 466 467 #ifndef SIOCGIFFLAGS 468 /* if cannot get interface flags, return nothing */ 469 plog(XLOG_ERROR, "getwire unable to get interface flags"); 470 localnets = NULL; 471 return; 472 #endif /* not SIOCGIFFLAGS */ 473 474 /* 475 * Get suitable socket 476 */ 477 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 478 goto out; 479 480 /* 481 * Fill in ifconf details 482 */ 483 memset(&buf[0], 0, GFBUFLEN); 484 ifc.ifc_len = sizeof(buf); 485 ifc.ifc_buf = buf; 486 487 /* 488 * Get network interface configurations 489 */ 490 if (ioctl(fd, SIOCGIFCONF, (caddr_t) & ifc) < 0) 491 goto out; 492 493 /* 494 * Upper bound on array 495 */ 496 cplim = buf + ifc.ifc_len; 497 498 /* 499 * This is some magic to cope with both "traditional" and the 500 * new 4.4BSD-style struct sockaddrs. The new structure has 501 * variable length and a size field to support longer addresses. 502 * AF_LINK is a new definition for 4.4BSD. 503 */ 504 505 /* 506 * Scan the list looking for a suitable interface 507 */ 508 for (cp = buf; cp < cplim; /* increment in the loop body */) { 509 memcpy(&ifrpool, cp, sizeof(ifrpool)); 510 ifr = &ifrpool; 511 cp += SIZE(ifr); 512 513 if (ifr->ifr_addr.sa_family != AF_INET) 514 continue; 515 516 address = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; 517 518 /* 519 * Get interface flags 520 */ 521 if (ioctl(fd, SIOCGIFFLAGS, (caddr_t) ifr) < 0) 522 continue; 523 524 /* 525 * If the interface is the loopback, or it's not running, 526 * then ignore it. 527 */ 528 if (address == htonl(INADDR_LOOPBACK)) 529 continue; 530 /* 531 * Fix for 0.0.0.0 loopback on SunOS 3.X which defines IFF_ROUTE 532 * instead of IFF_LOOPBACK. 533 */ 534 #ifdef IFF_ROUTE 535 if (ifr->ifr_flags == (IFF_UP|IFF_RUNNING)) 536 continue; 537 #endif /* IFF_ROUTE */ 538 539 /* if the interface is not UP or not RUNNING, skip it */ 540 if ((ifr->ifr_flags & IFF_RUNNING) == 0 || 541 (ifr->ifr_flags & IFF_UP) == 0) 542 continue; 543 544 if ((ifr->ifr_flags & IFF_POINTOPOINT) == 0) { 545 /* 546 * Get the netmask of this interface 547 */ 548 if (ioctl(fd, SIOCGIFNETMASK, (caddr_t) ifr) < 0) 549 continue; 550 551 al = getwire_lookup(address, S2IN(&ifr->ifr_addr), 0); 552 } else 553 al = getwire_lookup(address, 0xffffffff, 1); 554 555 /* append to the end of the list */ 556 if (!localnets) { 557 localnets = tail = al; 558 tail->ip_next = NULL; 559 } else { 560 tail->ip_next = al; 561 tail = al; 562 } 563 } 564 565 out: 566 if (fd >= 0) 567 close(fd); 568 if (localnets) { 569 *name1 = localnets->ip_net_name; 570 *number1 = localnets->ip_net_num; 571 } else { 572 *name1 = NO_SUBNET; 573 *number1 = "0.0.0.0"; 574 } 575 } 576 #endif /* not HAVE_GETIFADDRS */ 577