1/*++ 2/* NAME 3/* inet_addr_local 3 4/* SUMMARY 5/* determine if IP address is local 6/* SYNOPSIS 7/* #include <inet_addr_local.h> 8/* 9/* int inet_addr_local(addr_list, mask_list, addr_family_list) 10/* INET_ADDR_LIST *addr_list; 11/* INET_ADDR_LIST *mask_list; 12/* unsigned *addr_family; 13/* DESCRIPTION 14/* inet_addr_local() determines all active IP interface addresses 15/* of the local system. Any address found is appended to the 16/* specified address list. The result value is the number of 17/* active interfaces found. 18/* 19/* The mask_list is either a null pointer, or it is a list that 20/* receives the netmasks of the interface addresses that were found. 21/* 22/* The addr_family_list specifies one or more of AF_INET or AF_INET6. 23/* DIAGNOSTICS 24/* Fatal errors: out of memory. 25/* SEE ALSO 26/* inet_addr_list(3) address list management 27/* LICENSE 28/* .ad 29/* .fi 30/* The Secure Mailer license must be distributed with this software. 31/* AUTHOR(S) 32/* Wietse Venema 33/* IBM T.J. Watson Research 34/* P.O. Box 704 35/* Yorktown Heights, NY 10598, USA 36/* 37/* Dean C. Strik 38/* Department ICT 39/* Eindhoven University of Technology 40/* P.O. Box 513 41/* 5600 MB Eindhoven, Netherlands 42/* E-mail: <dean@ipnet6.org> 43/*--*/ 44 45/* System library. */ 46 47#include <sys_defs.h> 48#include <sys/socket.h> 49#include <sys/time.h> 50#include <netinet/in.h> 51#include <net/if.h> 52#include <sys/ioctl.h> 53#include <arpa/inet.h> 54#include <unistd.h> 55#ifdef USE_SYS_SOCKIO_H 56#include <sys/sockio.h> 57#endif 58#include <errno.h> 59#include <string.h> 60#ifdef HAS_IPV6 /* Linux only? */ 61#include <netdb.h> 62#include <stdio.h> 63#endif 64#ifdef HAVE_GETIFADDRS 65#include <ifaddrs.h> 66#endif 67 68/* Utility library. */ 69 70#include <msg.h> 71#include <mymalloc.h> 72#include <vstring.h> 73#include <inet_addr_list.h> 74#include <inet_addr_local.h> 75#include <myaddrinfo.h> 76#include <sock_addr.h> 77#include <mask_addr.h> 78#include <hex_code.h> 79 80 /* 81 * Postfix needs its own interface address information to determine whether 82 * or not it is an MX host for some destination; without this information, 83 * mail would loop between MX hosts. Postfix also needs its interface 84 * addresses to figure out whether or not it is final destination for 85 * addresses of the form username@[ipaddress]. 86 * 87 * Postfix needs its own interface netmask information when no explicit 88 * mynetworks setting is given in main.cf, and "mynetworks_style = subnet". 89 * The mynetworks parameter controls, among others, what mail clients are 90 * allowed to relay mail through Postfix. 91 * 92 * Different systems have different ways to find out this information. We will 93 * therefore use OS dependent methods. An overview: 94 * 95 * - Use getifaddrs() when available. This supports both IPv4/IPv6 addresses. 96 * The implementation however is not present in all major operating systems. 97 * 98 * - Use SIOCGLIFCONF when available. This supports both IPv4/IPv6 addresses. 99 * With SIOCGLIFNETMASK we can obtain the netmask for either address family. 100 * Again, this is not present in all major operating systems. 101 * 102 * - On Linux, glibc's getifaddrs(3) has returned IPv4 information for some 103 * time, but IPv6 information was not returned until 2.3.3. With older Linux 104 * versions we get IPv4 interface information with SIOCGIFCONF, and read 105 * IPv6 address/prefix information from a file in the /proc filesystem. 106 * 107 * - On other systems we expect SIOCGIFCONF to return IPv6 addresses. Since 108 * SIOCGIFNETMASK does not work reliably for IPv6 addresses, we always set 109 * the prefix length to /128 (host), and expect the user to configure a more 110 * appropriate mynetworks setting if needed. 111 * 112 * XXX: Each lookup method is implemented by its own function, so we duplicate 113 * some code. In this case, I think this is better than really drowning in 114 * the #ifdefs... 115 * 116 * -- Dean Strik (dcs) 117 */ 118 119/* ial_socket - make socket for ioctl() operations */ 120 121static int ial_socket(int af) 122{ 123 const char *myname = "inet_addr_local[socket]"; 124 int sock; 125 126 /* 127 * The host may not be actually configured with IPv6. When IPv6 support 128 * is not actually in the kernel, don't consider failure to create an 129 * IPv6 socket as fatal. This could be tuned better though. For other 130 * families, the error is fatal. 131 * 132 * XXX Now that Postfix controls protocol support centrally with the 133 * inet_proto(3) module, this workaround should no longer be needed. 134 */ 135 if ((sock = socket(af, SOCK_DGRAM, 0)) < 0) { 136#ifdef HAS_IPV6 137 if (af == AF_INET6) { 138 if (msg_verbose) 139 msg_warn("%s: socket: %m", myname); 140 return (-1); 141 } 142#endif 143 msg_fatal("%s: socket: %m", myname); 144 } 145 return (sock); 146} 147 148#ifdef HAVE_GETIFADDRS 149 150/* 151 * The getifaddrs(3) function, introduced by BSD/OS, provides a 152 * platform-independent way of requesting interface addresses, 153 * including IPv6 addresses. The implementation however is not 154 * present in all major operating systems. 155 */ 156 157/* ial_getifaddrs - determine IP addresses using getifaddrs(3) */ 158 159static int ial_getifaddrs(INET_ADDR_LIST *addr_list, 160 INET_ADDR_LIST *mask_list, 161 int af) 162{ 163 const char *myname = "inet_addr_local[getifaddrs]"; 164 struct ifaddrs *ifap, *ifa; 165 struct sockaddr *sa, *sam; 166 167 if (getifaddrs(&ifap) < 0) 168 msg_fatal("%s: getifaddrs: %m", myname); 169 170 /* 171 * Get the address of each IP network interface. According to BIND we 172 * must include interfaces that are down because the machine may still 173 * receive packets for that address (yes, via some other interface). 174 * Having no way to verify this claim on every machine, I will give them 175 * the benefit of the doubt. 176 * 177 * FIX 200501: The IPv6 patch did not report NetBSD loopback interfaces; 178 * fixed by replacing IFF_RUNNING by IFF_UP. 179 * 180 * FIX 200501: The IPV6 patch did not skip wild-card interface addresses 181 * (tested on FreeBSD). 182 */ 183 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 184 if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_addr == 0) 185 continue; 186 sa = ifa->ifa_addr; 187 if (af != AF_UNSPEC && sa->sa_family != af) 188 continue; 189 sam = ifa->ifa_netmask; 190 if (sam == 0) { 191 /* XXX In mynetworks, a null netmask would match everyone. */ 192 msg_warn("ignoring interface with null netmask, address family %d", 193 sa->sa_family); 194 continue; 195 } 196 switch (sa->sa_family) { 197 case AF_INET: 198 if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY) 199 continue; 200 break; 201#ifdef HAS_IPV6 202 case AF_INET6: 203 if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa))) 204 continue; 205 break; 206#endif 207 default: 208 continue; 209 } 210 211 inet_addr_list_append(addr_list, sa); 212 if (mask_list != 0) { 213 214 /* 215 * Unfortunately, sa_len/sa_family may be broken in the netmask 216 * sockaddr structure. We must fix this manually to have correct 217 * addresses. --dcs 218 */ 219#ifdef HAS_SA_LEN 220 sam->sa_len = sa->sa_family == AF_INET6 ? 221 sizeof(struct sockaddr_in6) : 222 sizeof(struct sockaddr_in); 223#endif 224 sam->sa_family = sa->sa_family; 225 inet_addr_list_append(mask_list, sam); 226 } 227 } 228 freeifaddrs(ifap); 229 return (0); 230} 231 232#endif /* HAVE_GETIFADDRS */ 233 234#ifdef HAS_SIOCGLIF 235 236/* 237 * The SIOCLIF* ioctls are the successors of SIOCGIF* on the Solaris 238 * and HP/UX operating systems. The data is stored in sockaddr_storage 239 * structure. Both IPv4 and IPv6 addresses are returned though these 240 * calls. 241 */ 242#define NEXT_INTERFACE(lifr) (lifr + 1) 243#define LIFREQ_SIZE(lifr) sizeof(lifr[0]) 244 245/* ial_siocglif - determine IP addresses using ioctl(SIOCGLIF*) */ 246 247static int ial_siocglif(INET_ADDR_LIST *addr_list, 248 INET_ADDR_LIST *mask_list, 249 int af) 250{ 251 const char *myname = "inet_addr_local[siocglif]"; 252 struct lifconf lifc; 253 struct lifreq *lifr; 254 struct lifreq *lifr_mask; 255 struct lifreq *the_end; 256 struct sockaddr *sa; 257 int sock; 258 VSTRING *buf; 259 260 /* 261 * See also comments in ial_siocgif() 262 */ 263 if (af != AF_INET && af != AF_INET6) 264 msg_fatal("%s: address family was %d, must be AF_INET (%d) or " 265 "AF_INET6 (%d)", myname, af, AF_INET, AF_INET6); 266 sock = ial_socket(af); 267 if (sock < 0) 268 return (0); 269 buf = vstring_alloc(1024); 270 for (;;) { 271 memset(&lifc, 0, sizeof(lifc)); 272 lifc.lifc_family = AF_UNSPEC; /* XXX Why??? */ 273 lifc.lifc_len = vstring_avail(buf); 274 lifc.lifc_buf = vstring_str(buf); 275 if (ioctl(sock, SIOCGLIFCONF, (char *) &lifc) < 0) { 276 if (errno != EINVAL) 277 msg_fatal("%s: ioctl SIOCGLIFCONF: %m", myname); 278 } else if (lifc.lifc_len < vstring_avail(buf) / 2) 279 break; 280 VSTRING_SPACE(buf, vstring_avail(buf) * 2); 281 } 282 283 the_end = (struct lifreq *) (lifc.lifc_buf + lifc.lifc_len); 284 for (lifr = lifc.lifc_req; lifr < the_end;) { 285 sa = (struct sockaddr *) & lifr->lifr_addr; 286 if (sa->sa_family != af) { 287 lifr = NEXT_INTERFACE(lifr); 288 continue; 289 } 290 if (af == AF_INET) { 291 if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY) { 292 lifr = NEXT_INTERFACE(lifr); 293 continue; 294 } 295#ifdef HAS_IPV6 296 } else if (af == AF_INET6) { 297 if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa))) { 298 lifr = NEXT_INTERFACE(lifr); 299 continue; 300 } 301 } 302#endif 303 inet_addr_list_append(addr_list, sa); 304 if (mask_list) { 305 lifr_mask = (struct lifreq *) mymalloc(sizeof(struct lifreq)); 306 memcpy((char *) lifr_mask, (char *) lifr, sizeof(struct lifreq)); 307 if (ioctl(sock, SIOCGLIFNETMASK, lifr_mask) < 0) 308 msg_fatal("%s: ioctl(SIOCGLIFNETMASK): %m", myname); 309 /* XXX: Check whether sa_len/family are honoured --dcs */ 310 inet_addr_list_append(mask_list, 311 (struct sockaddr *) & lifr_mask->lifr_addr); 312 myfree((char *) lifr_mask); 313 } 314 lifr = NEXT_INTERFACE(lifr); 315 } 316 vstring_free(buf); 317 (void) close(sock); 318 return (0); 319} 320 321#else /* HAVE_SIOCGLIF */ 322 323/* 324 * The classic SIOCGIF* ioctls. Modern BSD operating systems will 325 * also return IPv6 addresses through these structure. Note however 326 * that recent versions of these operating systems have getifaddrs. 327 */ 328#if defined(_SIZEOF_ADDR_IFREQ) 329#define NEXT_INTERFACE(ifr) ((struct ifreq *) \ 330 ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr))) 331#define IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr) 332#elif defined(HAS_SA_LEN) 333#define NEXT_INTERFACE(ifr) ((struct ifreq *) \ 334 ((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)) 335#define IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len) 336#else 337#define NEXT_INTERFACE(ifr) (ifr + 1) 338#define IFREQ_SIZE(ifr) sizeof(ifr[0]) 339#endif 340 341/* ial_siocgif - determine IP addresses using ioctl(SIOCGIF*) */ 342 343static int ial_siocgif(INET_ADDR_LIST *addr_list, 344 INET_ADDR_LIST *mask_list, 345 int af) 346{ 347 const char *myname = "inet_addr_local[siocgif]"; 348 struct in_addr addr; 349 struct ifconf ifc; 350 struct ifreq *ifr; 351 struct ifreq *ifr_mask; 352 struct ifreq *the_end; 353 int sock; 354 VSTRING *buf; 355 356 /* 357 * Get the network interface list. XXX The socket API appears to have no 358 * function that returns the number of network interfaces, so we have to 359 * guess how much space is needed to store the result. 360 * 361 * On BSD-derived systems, ioctl SIOCGIFCONF returns as much information as 362 * possible, leaving it up to the application to repeat the request with 363 * a larger buffer if the result caused a tight fit. 364 * 365 * Other systems, such as Solaris 2.5, generate an EINVAL error when the 366 * buffer is too small for the entire result. Workaround: ignore EINVAL 367 * errors and repeat the request with a larger buffer. The downside is 368 * that the program can run out of memory due to a non-memory problem, 369 * making it more difficult than necessary to diagnose the real problem. 370 */ 371 sock = ial_socket(af); 372 if (sock < 0) 373 return (0); 374 buf = vstring_alloc(1024); 375 for (;;) { 376 ifc.ifc_len = vstring_avail(buf); 377 ifc.ifc_buf = vstring_str(buf); 378 if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) { 379 if (errno != EINVAL) 380 msg_fatal("%s: ioctl SIOCGIFCONF: %m", myname); 381 } else if (ifc.ifc_len < vstring_avail(buf) / 2) 382 break; 383 VSTRING_SPACE(buf, vstring_avail(buf) * 2); 384 } 385 386 the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 387 for (ifr = ifc.ifc_req; ifr < the_end;) { 388 if (ifr->ifr_addr.sa_family != af) { 389 ifr = NEXT_INTERFACE(ifr); 390 continue; 391 } 392 if (af == AF_INET) { 393 addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr; 394 if (addr.s_addr != INADDR_ANY) { 395 inet_addr_list_append(addr_list, &ifr->ifr_addr); 396 if (mask_list) { 397 ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr)); 398 memcpy((char *) ifr_mask, (char *) ifr, IFREQ_SIZE(ifr)); 399 if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0) 400 msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname); 401 402 /* 403 * Note that this SIOCGIFNETMASK has truly screwed up the 404 * contents of sa_len/sa_family. We must fix this 405 * manually to have correct addresses. --dcs 406 */ 407 ifr_mask->ifr_addr.sa_family = af; 408#ifdef HAS_SA_LEN 409 ifr_mask->ifr_addr.sa_len = sizeof(struct sockaddr_in); 410#endif 411 inet_addr_list_append(mask_list, &ifr_mask->ifr_addr); 412 myfree((char *) ifr_mask); 413 } 414 } 415 } 416#ifdef HAS_IPV6 417 else if (af == AF_INET6) { 418 struct sockaddr *sa; 419 420 sa = SOCK_ADDR_PTR(&ifr->ifr_addr); 421 if (!(IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))) { 422 inet_addr_list_append(addr_list, sa); 423 if (mask_list) { 424 /* XXX Assume /128 for everything */ 425 struct sockaddr_in6 mask6; 426 427 mask6 = *SOCK_ADDR_IN6_PTR(sa); 428 memset((char *) &mask6.sin6_addr, ~0, 429 sizeof(mask6.sin6_addr)); 430 inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask6)); 431 } 432 } 433 } 434#endif 435 ifr = NEXT_INTERFACE(ifr); 436 } 437 vstring_free(buf); 438 (void) close(sock); 439 return (0); 440} 441 442#endif /* HAVE_SIOCGLIF */ 443 444#ifdef HAS_PROCNET_IFINET6 445 446/* 447 * Older Linux versions lack proper calls to retrieve IPv6 interface 448 * addresses. Instead, the addresses can be read from a file in the 449 * /proc tree. The most important issue with this approach however 450 * is that the /proc tree may not always be available, for example 451 * in a chrooted environment or in "hardened" (sic) installations. 452 */ 453 454/* ial_procnet_ifinet6 - determine IPv6 addresses using /proc/net/if_inet6 */ 455 456static int ial_procnet_ifinet6(INET_ADDR_LIST *addr_list, 457 INET_ADDR_LIST *mask_list) 458{ 459 const char *myname = "inet_addr_local[procnet_ifinet6]"; 460 FILE *fp; 461 char buf[BUFSIZ]; 462 unsigned plen; 463 VSTRING *addrbuf; 464 struct sockaddr_in6 addr; 465 struct sockaddr_in6 mask; 466 467 /* 468 * Example: 00000000000000000000000000000001 01 80 10 80 lo 469 * 470 * Fields: address, interface index, prefix length, scope value 471 * (net/ipv6.h), interface flags (linux/rtnetlink.h), device name. 472 * 473 * FIX 200501 The IPv6 patch used fscanf(), which will hang on unexpected 474 * input. Use fgets() + sscanf() instead. 475 */ 476 if ((fp = fopen(_PATH_PROCNET_IFINET6, "r")) != 0) { 477 addrbuf = vstring_alloc(MAI_V6ADDR_BYTES + 1); 478 memset((char *) &addr, 0, sizeof(addr)); 479 addr.sin6_family = AF_INET6; 480#ifdef HAS_SA_LEN 481 addr.sin6_len = sizeof(addr); 482#endif 483 mask = addr; 484 while (fgets(buf, sizeof(buf), fp) != 0) { 485 /* 200501 hex_decode() is light-weight compared to getaddrinfo(). */ 486 if (hex_decode(addrbuf, buf, MAI_V6ADDR_BYTES * 2) == 0 487 || sscanf(buf + MAI_V6ADDR_BYTES * 2, " %*x %x", &plen) != 1 488 || plen > MAI_V6ADDR_BITS) { 489 msg_warn("unexpected data in %s - skipping IPv6 configuration", 490 _PATH_PROCNET_IFINET6); 491 break; 492 } 493 /* vstring_str(addrbuf) has worst-case alignment. */ 494 addr.sin6_addr = *(struct in6_addr *) vstring_str(addrbuf); 495 inet_addr_list_append(addr_list, SOCK_ADDR_PTR(&addr)); 496 497 memset((char *) &mask.sin6_addr, ~0, sizeof(mask.sin6_addr)); 498 mask_addr((unsigned char *) &mask.sin6_addr, 499 sizeof(mask.sin6_addr), plen); 500 inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask)); 501 } 502 vstring_free(addrbuf); 503 fclose(fp); /* FIX 200501 */ 504 } else { 505 msg_warn("can't open %s (%m) - skipping IPv6 configuration", 506 _PATH_PROCNET_IFINET6); 507 } 508 return (0); 509} 510 511#endif /* HAS_PROCNET_IFINET6 */ 512 513/* inet_addr_local - find all IP addresses for this host */ 514 515int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list, 516 unsigned *addr_family_list) 517{ 518 const char *myname = "inet_addr_local"; 519 int initial_count = addr_list->used; 520 unsigned family; 521 int count; 522 523 while ((family = *addr_family_list++) != 0) { 524 525 /* 526 * IP Version 4 527 */ 528 if (family == AF_INET) { 529 count = addr_list->used; 530#if defined(HAVE_GETIFADDRS) 531 ial_getifaddrs(addr_list, mask_list, AF_INET); 532#elif defined (HAS_SIOCGLIF) 533 ial_siocglif(addr_list, mask_list, AF_INET); 534#else 535 ial_siocgif(addr_list, mask_list, AF_INET); 536#endif 537 if (msg_verbose) 538 msg_info("%s: configured %d IPv4 addresses", 539 myname, addr_list->used - count); 540 } 541 542 /* 543 * IP Version 6 544 */ 545#ifdef HAS_IPV6 546 else if (family == AF_INET6) { 547 count = addr_list->used; 548#if defined(HAVE_GETIFADDRS) 549 ial_getifaddrs(addr_list, mask_list, AF_INET6); 550#elif defined(HAS_PROCNET_IFINET6) 551 ial_procnet_ifinet6(addr_list, mask_list); 552#elif defined(HAS_SIOCGLIF) 553 ial_siocglif(addr_list, mask_list, AF_INET6); 554#else 555 ial_siocgif(addr_list, mask_list, AF_INET6); 556#endif 557 if (msg_verbose) 558 msg_info("%s: configured %d IPv6 addresses", myname, 559 addr_list->used - count); 560 } 561#endif 562 563 /* 564 * Something's not right. 565 */ 566 else 567 msg_panic("%s: unknown address family %d", myname, family); 568 } 569 return (addr_list->used - initial_count); 570} 571 572#ifdef TEST 573 574#include <string.h> 575#include <vstream.h> 576#include <msg_vstream.h> 577#include <inet_proto.h> 578 579int main(int unused_argc, char **argv) 580{ 581 INET_ADDR_LIST addr_list; 582 INET_ADDR_LIST mask_list; 583 MAI_HOSTADDR_STR hostaddr; 584 MAI_HOSTADDR_STR hostmask; 585 struct sockaddr *sa; 586 int i; 587 INET_PROTO_INFO *proto_info; 588 589 msg_vstream_init(argv[0], VSTREAM_ERR); 590 msg_verbose = 1; 591 592 proto_info = inet_proto_init(argv[0], 593 argv[1] ? argv[1] : INET_PROTO_NAME_ALL); 594 inet_addr_list_init(&addr_list); 595 inet_addr_list_init(&mask_list); 596 inet_addr_local(&addr_list, &mask_list, proto_info->ai_family_list); 597 598 if (addr_list.used == 0) 599 msg_fatal("cannot find any active network interfaces"); 600 601 if (addr_list.used == 1) 602 msg_warn("found only one active network interface"); 603 604 for (i = 0; i < addr_list.used; i++) { 605 sa = SOCK_ADDR_PTR(addr_list.addrs + i); 606 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa), 607 &hostaddr, (MAI_SERVPORT_STR *) 0, 0); 608 sa = SOCK_ADDR_PTR(mask_list.addrs + i); 609 SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa), 610 &hostmask, (MAI_SERVPORT_STR *) 0, 0); 611 vstream_printf("%s/%s\n", hostaddr.buf, hostmask.buf); 612 vstream_fflush(VSTREAM_OUT); 613 } 614 inet_addr_list_free(&addr_list); 615 inet_addr_list_free(&mask_list); 616 return (0); 617} 618 619#endif 620