/libnetutil/netutil.cc
C++ | 4671 lines | 3245 code | 641 blank | 785 comment | 1020 complexity | 317df23bea9b4a37bd50dc77d57fada7 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /***************************************************************************
- * netutil.cc *
- * *
- ***********************IMPORTANT NMAP LICENSE TERMS************************
- * *
- * The Nmap Security Scanner is (C) 1996-2013 Insecure.Com LLC. Nmap is *
- * also a registered trademark of Insecure.Com LLC. This program is free *
- * software; you may redistribute and/or modify it under the terms of the *
- * GNU General Public License as published by the Free Software *
- * Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE CLARIFICATIONS *
- * AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your right to use, *
- * modify, and redistribute this software under certain conditions. If *
- * you wish to embed Nmap technology into proprietary software, we sell *
- * alternative licenses (contact sales@nmap.com). Dozens of software *
- * vendors already license Nmap technology such as host discovery, port *
- * scanning, OS detection, version detection, and the Nmap Scripting *
- * Engine. *
- * *
- * Note that the GPL places important restrictions on "derivative works", *
- * yet it does not provide a detailed definition of that term. To avoid *
- * misunderstandings, we interpret that term as broadly as copyright law *
- * allows. For example, we consider an application to constitute a *
- * derivative work for the purpose of this license if it does any of the *
- * following with any software or content covered by this license *
- * ("Covered Software"): *
- * *
- * o Integrates source code from Covered Software. *
- * *
- * o Reads or includes copyrighted data files, such as Nmap's nmap-os-db *
- * or nmap-service-probes. *
- * *
- * o Is designed specifically to execute Covered Software and parse the *
- * results (as opposed to typical shell or execution-menu apps, which will *
- * execute anything you tell them to). *
- * *
- * o Includes Covered Software in a proprietary executable installer. The *
- * installers produced by InstallShield are an example of this. Including *
- * Nmap with other software in compressed or archival form does not *
- * trigger this provision, provided appropriate open source decompression *
- * or de-archiving software is widely available for no charge. For the *
- * purposes of this license, an installer is considered to include Covered *
- * Software even if it actually retrieves a copy of Covered Software from *
- * another source during runtime (such as by downloading it from the *
- * Internet). *
- * *
- * o Links (statically or dynamically) to a library which does any of the *
- * above. *
- * *
- * o Executes a helper program, module, or script to do any of the above. *
- * *
- * This list is not exclusive, but is meant to clarify our interpretation *
- * of derived works with some common examples. Other people may interpret *
- * the plain GPL differently, so we consider this a special exception to *
- * the GPL that we apply to Covered Software. Works which meet any of *
- * these conditions must conform to all of the terms of this license, *
- * particularly including the GPL Section 3 requirements of providing *
- * source code and allowing free redistribution of the work as a whole. *
- * *
- * As another special exception to the GPL terms, Insecure.Com LLC grants *
- * permission to link the code of this program with any version of the *
- * OpenSSL library which is distributed under a license identical to that *
- * listed in the included docs/licenses/OpenSSL.txt file, and distribute *
- * linked combinations including the two. *
- * *
- * Any redistribution of Covered Software, including any derived works, *
- * must obey and carry forward all of the terms of this license, including *
- * obeying all GPL rules and restrictions. For example, source code of *
- * the whole work must be provided and free redistribution must be *
- * allowed. All GPL references to "this License", are to be treated as *
- * including the terms and conditions of this license text as well. *
- * *
- * Because this license imposes special exceptions to the GPL, Covered *
- * Work may not be combined (even as part of a larger work) with plain GPL *
- * software. The terms, conditions, and exceptions of this license must *
- * be included as well. This license is incompatible with some other open *
- * source licenses as well. In some cases we can relicense portions of *
- * Nmap or grant special permissions to use it in other open source *
- * software. Please contact fyodor@nmap.org with any such requests. *
- * Similarly, we don't incorporate incompatible open source software into *
- * Covered Software without special permission from the copyright holders. *
- * *
- * If you have any questions about the licensing restrictions on using *
- * Nmap in other works, are happy to help. As mentioned above, we also *
- * offer alternative license to integrate Nmap into proprietary *
- * applications and appliances. These contracts have been sold to dozens *
- * of software vendors, and generally include a perpetual license as well *
- * as providing for priority support and updates. They also fund the *
- * continued development of Nmap. Please email sales@nmap.com for further *
- * information. *
- * *
- * If you have received a written license agreement or contract for *
- * Covered Software stating terms other than these, you may choose to use *
- * and redistribute Covered Software under those terms instead of these. *
- * *
- * Source is provided to this software because we believe users have a *
- * right to know exactly what a program is going to do before they run it. *
- * This also allows you to audit the software for security holes (none *
- * have been found so far). *
- * *
- * Source code also allows you to port Nmap to new platforms, fix bugs, *
- * and add new features. You are highly encouraged to send your changes *
- * to the dev@nmap.org mailing list for possible incorporation into the *
- * main distribution. By sending these changes to Fyodor or one of the *
- * Insecure.Org development mailing lists, or checking them into the Nmap *
- * source code repository, it is understood (unless you specify otherwise) *
- * that you are offering the Nmap Project (Insecure.Com LLC) the *
- * unlimited, non-exclusive right to reuse, modify, and relicense the *
- * code. Nmap will always be available Open Source, but this is important *
- * because the inability to relicense code has caused devastating problems *
- * for other Free Software projects (such as KDE and NASM). We also *
- * occasionally relicense the code to third parties as discussed above. *
- * If you wish to specify special license conditions of your *
- * contributions, just say so when you send them. *
- * *
- * This program is distributed in the hope that it will be useful, but *
- * WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Nmap *
- * license file for more details (it's in a COPYING file included with *
- * Nmap, and also available from https://svn.nmap.org/nmap/COPYING *
- * *
- ***************************************************************************/
- /* Since OS X 10.7, we must declare whether we expect RFC 2292 or RFC 3542
- behavior from <netinet6/in6.h>. */
- #define __APPLE_USE_RFC_3542
- #if HAVE_CONFIG_H
- #include "../nmap_config.h"
- #endif
- #include "nbase.h"
- #ifdef WIN32
- #include "mswin32/winclude.h"
- #include "pcap-int.h"
- #else
- #include <sys/ioctl.h>
- #endif
- #include <assert.h>
- #include <errno.h>
- #include <sys/types.h>
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif
- #if HAVE_SYS_SOCKIO_H
- #include <sys/sockio.h> /* SIOCGIFCONF for Solaris */
- #endif
- /* Define CMSG_* symbols for Solaris 9 and earlier. See
- http://wiki.opencsw.org/porting-faq#toc10. */
- #if defined(__sun) || defined(__sun__)
- # ifndef CMSG_ALIGN
- # ifdef __sun__
- # define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len)
- # else
- /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */
- # define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & ~(sizeof (long) - 1))
- # endif
- # endif
- # ifndef CMSG_SPACE
- # define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + CMSG_ALIGN (len))
- # endif
- # ifndef CMSG_LEN
- # define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
- # endif
- #endif /* Solaris */
- #if HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif
- #ifdef HAVE_LINUX_RTNETLINK_H
- #include <linux/rtnetlink.h>
- #endif
- #ifndef NETINET_IN_SYSTM_H /* This guarding is needed for at least some versions of OpenBSD */
- #include <netinet/in_systm.h>
- #define NETINET_IN_SYSTM_H
- #endif
- #include "netutil.h"
- #if HAVE_NET_IF_H
- #ifndef NET_IF_H /* This guarding is needed for at least some versions of OpenBSD */
- #include <net/if.h>
- #define NET_IF_H
- #endif
- #endif
- #ifndef NETINET_IP_H /* This guarding is needed for at least some versions of OpenBSD */
- #include <netinet/ip.h>
- #define NETINET_IP_H
- #endif
- #include <net/if_arp.h>
- #if HAVE_SYS_RESOURCE_H
- #include <sys/resource.h>
- #endif
- #define NBASE_MAX_ERR_STR_LEN 1024 /* Max length of an error message */
- /** Print fatal error messages to stderr and then exits. A newline
- character is printed automatically after the supplied text.
- * @warning This function does not return because it calls exit() */
- void netutil_fatal(const char *str, ...){
- va_list list;
- char errstr[NBASE_MAX_ERR_STR_LEN];
- memset(errstr,0, NBASE_MAX_ERR_STR_LEN);
- va_start(list, str);
- fflush(stdout);
- /* Print error msg to strerr */
- vfprintf(stderr, str, list);
- fprintf(stderr,"\n");
- va_end(list);
- exit(EXIT_FAILURE);
- } /* End of fatal() */
- /** Print error messages to stderr and then return. A newline
- character is printed automatically after the supplied text.*/
- int netutil_error(const char *str, ...){
- va_list list;
- char errstr[NBASE_MAX_ERR_STR_LEN];
- memset(errstr,0, NBASE_MAX_ERR_STR_LEN);
- va_start(list, str);
- fflush(stdout);
- /* Print error msg to strerr */
- vfprintf(stderr, str, list);
- fprintf(stderr,"\n");
- va_end(list);
- return 0;
- } /* End of error() */
- /* This function converts zero-terminated 'txt' string to binary 'data'.
- It is used to parse user input for ip options. Some examples of possible input
- strings and results:
- '\x01*2\xA2' -> [0x01,0x01,0xA2] // with 'x' number is parsed in hex
- '\01\01\255' -> [0x01,0x01,0xFF] // without 'x' its in decimal
- '\x01\x00*2' -> [0x01,0x00,0x00] // '*' is copying char
- 'R' -> Record Route with 9 slots
- 'S 192.168.0.1 172.16.0.1' -> Strict Route with 2 slots
- 'L 192.168.0.1 172.16.0.1' -> Loose Route with 2 slots
- 'T' -> Record Timestamp with 9 slots
- 'U' -> Record Timestamp and Ip Address with 4 slots
- On success, the function returns the length of the final binary
- options stored in "data". In case of error, OP_FAILURE is returned
- and the "errstr" buffer is filled with an error message
- (unless it's NULL). Note that the returned error message does NOT
- contain a newline character at the end. */
- int parse_ip_options(const char *txt, u8 *data, int datalen, int* firsthopoff, int* lasthopoff, char *errstr, size_t errstrlen){
- enum{
- NONE = 0,
- SLASH = 1,
- MUL = 2,
- RR = 3,
- TIME = 4,
- } s = NONE;
- char *n, lc;
- const char *c = txt;
- u8 *d = data;
- int i,j;
- int base = 10;
- u8 *dataend = &data[datalen];
- u8 *len = NULL;
- char buf[32];
- memset(data, 0, datalen);
- int sourcerouting = 0;
- long strtolbyte = 0; // used to check strtol() return boundaries
- for(;*c;c++){
- switch(s){
- case SLASH:
- // parse \x00 string
- if(*c == 'x'){// just ignore this char
- base = 16;
- break;
- }
- if(isxdigit(*c)){
- strtolbyte = strtol(c, &n, base);
- if((strtolbyte < 0) || (strtolbyte > 255)){
- if(errstr) Snprintf(errstr, errstrlen, "invalid ipv4 address format");
- return OP_FAILURE;
- }
- *d++ = (u8) strtolbyte;
- c = n-1;
- }else{
- if(errstr) Snprintf(errstr, errstrlen, "not a digit after '\\'");
- return OP_FAILURE;
- }
- s = NONE;
- break;
- case MUL:
- if(d==data){
- if(errstr) Snprintf(errstr, errstrlen, "nothing before '*' char");
- return OP_FAILURE;
- }
- i = strtol(c, &n, 10);
- if(i<2){
- if(errstr) Snprintf(errstr, errstrlen, "bad number after '*'");
- return OP_FAILURE;
- }
- c = n-1; // move current txt pointer
- lc = *(d-1); // last char, we'll copy this
- for(j=1; j<i; j++){
- *d++ = lc;
- if(d == dataend) // check for overflow
- goto after;
- }
- s = NONE;
- break;
- case RR:
- if(*c==' ' || *c==',')
- break;
- n = buf;
- while((*c=='.' || (*c>='0' && *c<='9')) && n-buf <= ((int)sizeof(buf)-1))
- *n++ = *c++;
- *n = '\0'; c--;
- if(d+4>=dataend){
- if(errstr) Snprintf(errstr, errstrlen, "Buffer too small. Or input data too big :)");
- return OP_FAILURE;
- }
- i = inet_pton(AF_INET, buf, d);
- if(i<1){
- if(errstr) Snprintf(errstr, errstrlen, "Not a valid ipv4 address '%s'",buf);
- return OP_FAILURE;
- }
- // remember offset of first hop
- if(sourcerouting && !*firsthopoff)
- *firsthopoff = d - data;
- d+=4;
- if(*len<37)
- *len += 4;
- break;
- case TIME:
- if(errstr) Snprintf(errstr, errstrlen, "No more arguments allowed!");
- return OP_FAILURE;
- default:
- switch(*c){
- case '\\':s = SLASH;base=10;break;
- case '*':s = MUL;break;
- case 'R':
- case 'S':
- case 'L':
- if(d != data){
- if(errstr) Snprintf(errstr, errstrlen, "This option can't be used in that way");
- return OP_FAILURE;
- }
- *d++ = '\x01';//NOP
- switch(*c){
- case 'R':*d++ = 7;break;
- case 'S':*d++ = 137; sourcerouting=1; break;
- case 'L':*d++ = 131; sourcerouting=1; break;
- }
- len = d;
- *d++ = (*c=='R')? 39 : 3; // length: 3+4*9 bytes
- *d++ = 4; //pointer
- s = RR;
- break;
- case 'T':
- case 'U':
- if(d != data){
- if(errstr) Snprintf(errstr, errstrlen, "This option can't be used in that way");
- return OP_FAILURE;
- }
- *d++ = 68; // option type
- len = d;
- *d++ = (*c=='U') ? 36 : 40; // length: 3+4*9 bytes or 4+4*9 bytes
- *d++ = 5; // pointer
- *d++ = (*c=='U') ? 1 : 0; // flag: address and Time fields
- s = TIME;
- break;
- default://*d++ = *c;
- if(errstr) Snprintf(errstr, errstrlen, "Bad character in ip option '%c'",*c);
- return OP_FAILURE;
- }
- }
- if(d == dataend)
- break;
- assert(d<dataend);
- }
- if(sourcerouting){
- if(*len<37){
- *len+=4;
- *lasthopoff = d - data;
- *d++ = 0;*d++ = 0;*d++ = 0;*d++ = 0;
- }else{
- if(errstr) Snprintf(errstr, errstrlen, "When using source routing you must leave at least one slot for target's ip.");
- return OP_FAILURE;
- }
- }
- if(s == RR)
- return(*len+1); // because we inject NOP before
- if(s == TIME)
- return(*len);
- after:
- return(d - data);
- }
- /* Internal helper for resolve and resolve_numeric. addl_flags is ored into
- hints.ai_flags, so you can add AI_NUMERICHOST. */
- static int resolve_internal(const char *hostname, unsigned short port,
- struct sockaddr_storage *ss, size_t *sslen, int af, int addl_flags) {
- struct addrinfo hints;
- struct addrinfo *result;
- char portbuf[16];
- int rc;
- assert(hostname);
- assert(ss);
- assert(sslen);
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = af;
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags |= addl_flags;
- /* Make the port number a string to give to getaddrinfo. */
- rc = Snprintf(portbuf, sizeof(portbuf), "%hu", port);
- assert(rc >= 0 && (size_t) rc < sizeof(portbuf));
- rc = getaddrinfo(hostname, portbuf, &hints, &result);
- if (rc != 0)
- return rc;
- if (result == NULL)
- return EAI_NONAME;
- assert(result->ai_addrlen > 0 && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage));
- *sslen = result->ai_addrlen;
- memcpy(ss, result->ai_addr, *sslen);
- freeaddrinfo(result);
- return 0;
- }
- /* Resolves the given hostname or IP address with getaddrinfo, and stores the
- first result (if any) in *ss and *sslen. The value of port will be set in the
- appropriate place in *ss; set to 0 if you don't care. af may be AF_UNSPEC, in
- which case getaddrinfo may return e.g. both IPv4 and IPv6 results; which one
- is first depends on the system configuration. Returns 0 on success, or a
- getaddrinfo return code (suitable for passing to gai_strerror) on failure.
- *ss and *sslen are always defined when this function returns 0. */
- int resolve(const char *hostname, unsigned short port,
- struct sockaddr_storage *ss, size_t *sslen, int af) {
- return resolve_internal(hostname, port, ss, sslen, af, 0);
- }
- /* As resolve, but do not do DNS resolution of hostnames; the first argument
- must be the string representation of a numeric IP address. */
- int resolve_numeric(const char *ip, unsigned short port,
- struct sockaddr_storage *ss, size_t *sslen, int af) {
- return resolve_internal(ip, port, ss, sslen, af, AI_NUMERICHOST);
- }
- /*
- * Returns 1 if this is a reserved IP address, where "reserved" means
- * either a private address, non-routable address, or even a non-reserved
- * but unassigned address which has an extremely high probability of being
- * black-holed.
- *
- * We try to optimize speed when ordering the tests. This optimization
- * assumes that all byte values are equally likely in the input.
- *
- * Check
- * <http://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.txt>
- * for the most recent assigments and
- * <http://www.cymru.com/Documents/bogon-bn-nonagg.txt> for bogon
- * netblocks.
- */
- int ip_is_reserved(struct in_addr *ip)
- {
- char *ipc = (char *) &(ip->s_addr);
- unsigned char i1 = ipc[0], i2 = ipc[1], i3 = ipc[2]; /* i4 not currently used - , i4 = ipc[3]; */
- /* do all the /7's and /8's with a big switch statement, hopefully the
- * compiler will be able to optimize this a little better using a jump table
- * or what have you
- */
- switch (i1)
- {
- case 0: /* 000/8 is IANA reserved */
- case 6: /* USA Army ISC */
- case 7: /* used for BGP protocol */
- case 10: /* the infamous 10.0.0.0/8 */
- case 55: /* misc. U.S.A. Armed forces */
- case 127: /* 127/8 is reserved for loopback */
- return 1;
- default:
- break;
- }
- /* 172.16.0.0/12 is reserved for private nets by RFC1819 */
- if (i1 == 172 && i2 >= 16 && i2 <= 31)
- return 1;
- /* 192.0.2.0/24 is reserved for documentation and examples (RFC5737) */
- /* 192.88.99.0/24 is used as 6to4 Relay anycast prefix by RFC3068 */
- /* 192.168.0.0/16 is reserved for private nets by RFC1819 */
- if (i1 == 192) {
- if (i2 == 0 && i3 == 2)
- return 1;
- if (i2 == 88 && i3 == 99)
- return 1;
- if (i2 == 168)
- return 1;
- }
- /* 198.18.0.0/15 is used for benchmark tests by RFC2544 */
- /* 198.51.100.0/24 is reserved for documentation (RFC5737) */
- if (i1 == 198) {
- if (i2 == 18 || i2 == 19)
- return 1;
- if (i2 == 51 && i3 == 100)
- return 1;
- }
- /* 169.254.0.0/16 is reserved for DHCP clients seeking addresses */
- if (i1 == 169 && i2 == 254)
- return 1;
-
- /* 203.0.113.0/24 is reserved for documentation (RFC5737) */
- if (i1 == 203 && i2 == 0 && i3 == 113)
- return 1;
- /* 224-239/8 is all multicast stuff */
- /* 240-255/8 is IANA reserved */
- if (i1 >= 224)
- return 1;
- return 0;
- }
- /* A trivial functon that maintains a cache of IP to MAC Address
- entries. If the command is MACCACHE_GET, this func looks for the
- IPv4 address in ss and fills in the 'mac' parameter and returns
- true if it is found. Otherwise (not found), the function returns
- false. If the command is MACCACHE_SET, the function adds an entry
- with the given ip (ss) and mac address. An existing entry for the
- IP ss will be overwritten with the new MAC address. true is always
- returned for the set command. */
- #define MACCACHE_GET 1
- #define MACCACHE_SET 2
- static int do_mac_cache(int command, const struct sockaddr_storage *ss, u8 *mac) {
- struct MacCache {
- struct sockaddr_storage ip;
- u8 mac[6];
- };
- static struct MacCache *Cache = NULL;
- static int MacCapacity = 0;
- static int MacCacheSz = 0;
- int i;
- if (command == MACCACHE_GET) {
- for (i = 0; i < MacCacheSz; i++) {
- if (sockaddr_storage_cmp(&Cache[i].ip, ss) == 0) {
- memcpy(mac, Cache[i].mac, 6);
- return 1;
- }
- }
- return 0;
- }
- assert(command == MACCACHE_SET);
- if (MacCacheSz == MacCapacity) {
- if (MacCapacity == 0)
- MacCapacity = 32;
- else
- MacCapacity <<= 2;
- Cache = (struct MacCache *) safe_realloc(Cache, MacCapacity * sizeof(struct MacCache));
- }
- /* Ensure that it isn't already there ... */
- for (i = 0; i < MacCacheSz; i++) {
- if (sockaddr_storage_cmp(&Cache[i].ip, ss) == 0) {
- memcpy(Cache[i].mac, mac, 6);
- return 1;
- }
- }
- /* Add it to the end of the list */
- memcpy(&Cache[i].ip, ss, sizeof(struct sockaddr_storage));
- memcpy(Cache[i].mac, mac, 6);
- MacCacheSz++;
- return 1;
- }
- /* A couple of trivial functions that maintain a cache of IP to MAC
- * Address entries. Function mac_cache_get() looks for the IPv4 address
- * in ss and fills in the 'mac' parameter and returns true if it is
- * found. Otherwise (not found), the function returns false.
- * Function mac_cache_set() adds an entry with the given ip (ss) and
- * mac address. An existing entry for the IP ss will be overwritten
- * with the new MAC address. mac_cache_set() always returns true.
- * WARNING: The caller must ensure that the supplied "ss" is of family
- * AF_INET. Otherwise the function will return 0 and there would be
- * no way for the caller to tell tell the difference between an error
- * or a cache miss.*/
- int mac_cache_get(const struct sockaddr_storage *ss, u8 *mac){
- return do_mac_cache(MACCACHE_GET, ss, mac);
- }
- int mac_cache_set(const struct sockaddr_storage *ss, u8 *mac){
- return do_mac_cache(MACCACHE_SET, ss, mac);
- }
- /* Standard BSD internet checksum routine. Uses libdnet helper functions. */
- unsigned short in_cksum(u16 *ptr,int nbytes) {
- int sum;
- sum = ip_cksum_add(ptr, nbytes, 0);
- return ip_cksum_carry(sum);
- return 0;
- }
- /* Return true iff this Next Header type is an extension header we must skip to
- get to the upper-layer header. Types for which neither this function nor
- ipv6_is_upperlayer return true are unknown and could be either. */
- static int ipv6_is_extension_header(u8 type)
- {
- switch (type) {
- case IP_PROTO_HOPOPTS:
- case IP_PROTO_DSTOPTS:
- case IP_PROTO_ROUTING:
- case IP_PROTO_FRAGMENT:
- /*
- case IP_PROTO_ESP:
- case IP_PROTO_AH:
- */
- return 1;
- default:
- return 0;
- }
- }
- /* Return true iff this Next Header type is a known upper-layer protocol, one
- that isn't followed by any more headers. Types for which neither this
- function nor ipv6_is_upperlayer return true are unknown and could be
- either. */
- static int ipv6_is_upperlayer(u8 type)
- {
- switch (type) {
- case IP_PROTO_NONE:
- case IP_PROTO_TCP:
- case IP_PROTO_UDP:
- case IP_PROTO_ICMP:
- case IP_PROTO_ICMPV6:
- case IP_PROTO_SCTP:
- return 1;
- default:
- return 0;
- }
- }
- /* upperlayer_only controls whether we require a known upper-layer protocol at
- the end of the chain, or return the last readable header even if it is not an
- upper-layer protocol (may even be another extension header). */
- static const void *ipv6_get_data_primitive(const struct ip6_hdr *ip6,
- unsigned int *len, u8 *nxt, bool upperlayer_only)
- {
- const unsigned char *p, *end;
- if (*len < sizeof(*ip6))
- return NULL;
- p = (unsigned char *) ip6;
- end = p + *len;
- *nxt = ip6->ip6_nxt;
- p += sizeof(*ip6);
- while (p < end && ipv6_is_extension_header(*nxt)) {
- if (p + 2 > end)
- return NULL;
- *nxt = *p;
- p += (*(p + 1) + 1) * 8;
- }
- *len = end - p;
- if (upperlayer_only && !ipv6_is_upperlayer(*nxt))
- return NULL;
- return (char *) p;
- }
- static const void *ip_get_data_primitive(const void *packet, unsigned int *len,
- struct abstract_ip_hdr *hdr, bool upperlayer_only) {
- const struct ip *ip;
- ip = (struct ip *) packet;
- if (*len >= 20 && ip->ip_v == 4) {
- struct sockaddr_in *sin;
- hdr->version = 4;
- sin = (struct sockaddr_in *) &hdr->src;
- memset(&hdr->src, 0, sizeof(hdr->src));
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = ip->ip_src.s_addr;
- sin = (struct sockaddr_in *) &hdr->dst;
- memset(&hdr->dst, 0, sizeof(hdr->dst));
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = ip->ip_dst.s_addr;
- hdr->proto = ip->ip_p;
- hdr->ttl = ip->ip_ttl;
- hdr->ipid = ntohs(ip->ip_id);
- return ipv4_get_data(ip, len);
- } else if (*len >= 40 && ip->ip_v == 6) {
- const struct ip6_hdr *ip6 = (struct ip6_hdr *) ip;
- struct sockaddr_in6 *sin6;
- hdr->version = 6;
- sin6 = (struct sockaddr_in6 *) &hdr->src;
- memset(&hdr->src, 0, sizeof(hdr->src));
- sin6->sin6_family = AF_INET6;
- memcpy(&sin6->sin6_addr, &ip6->ip6_src, IP6_ADDR_LEN);
- sin6 = (struct sockaddr_in6 *) &hdr->dst;
- memset(&hdr->dst, 0, sizeof(hdr->dst));
- sin6->sin6_family = AF_INET6;
- memcpy(&sin6->sin6_addr, &ip6->ip6_dst, IP6_ADDR_LEN);
- hdr->ttl = ip6->ip6_hlim;
- /* abstract_hdr.ipid is limited to 16 bits. */
- hdr->ipid = (u16) ntohl(ip6->ip6_flow & IP6_FLOWLABEL_MASK);
- return ipv6_get_data_primitive(ip6, len, &hdr->proto, upperlayer_only);
- }
- return NULL;
- }
- /* Find the beginning of the data payload in the IP packet beginning at packet.
- Returns the beginning of the payload, updates *len to be the length of the
- payload, and fills in hdr if successful. Otherwise returns NULL and *hdr is
- undefined. */
- const void *ip_get_data(const void *packet, unsigned int *len,
- struct abstract_ip_hdr *hdr) {
- return ip_get_data_primitive(packet, len, hdr, true);
- }
- /* As ip_get_data, except that it doesn't insist that the payload be a known
- upper-layer protocol. This can matter in IPv6 where the last element of a nh
- chain may be a protocol we don't know about. */
- const void *ip_get_data_any(const void *packet, unsigned int *len,
- struct abstract_ip_hdr *hdr) {
- return ip_get_data_primitive(packet, len, hdr, false);
- }
- /* Get the upper-layer protocol from an IPv4 packet. */
- const void *ipv4_get_data(const struct ip *ip, unsigned int *len)
- {
- unsigned int header_len;
- if (*len < 20)
- return NULL;
- header_len = ip->ip_hl * 4;
- if (header_len < sizeof(*ip))
- return NULL;
- if (header_len > *len)
- return NULL;
- *len -= header_len;
- return (char *) ip + header_len;
- }
- /* Get the upper-layer protocol from an IPv6 packet. This skips over known
- extension headers. The length of the upper-layer payload is stored in *len.
- The protocol is stored in *nxt. Returns NULL in case of error. */
- const void *ipv6_get_data(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt)
- {
- return ipv6_get_data_primitive(ip6, len, nxt, true);
- }
- /* Get the protocol payload from an IPv6 packet. This skips over known extension
- headers. It differs from ipv6_get_data in that it will return a result even
- if the final header is not a known upper-layer protocol. */
- const void *ipv6_get_data_any(const struct ip6_hdr *ip6, unsigned int *len, u8 *nxt)
- {
- return ipv6_get_data_primitive(ip6, len, nxt, false);
- }
- const void *icmp_get_data(const struct icmp_hdr *icmp, unsigned int *len)
- {
- unsigned int header_len;
- if (icmp->icmp_type == ICMP_TIMEXCEED || icmp->icmp_type == ICMP_UNREACH)
- header_len = 8;
- else
- netutil_fatal("%s passed ICMP packet with unhandled type %d", __func__, icmp->icmp_type);
- if (header_len > *len)
- return NULL;
- *len -= header_len;
- return (char *) icmp + header_len;
- }
- const void *icmpv6_get_data(const struct icmpv6_hdr *icmpv6, unsigned int *len)
- {
- unsigned int header_len;
- if (icmpv6->icmpv6_type == ICMPV6_TIMEXCEED || icmpv6->icmpv6_type == ICMPV6_UNREACH)
- header_len = 8;
- else
- netutil_fatal("%s passed ICMPv6 packet with unhandled type %d", __func__, icmpv6->icmpv6_type);
- if (header_len > *len)
- return NULL;
- *len -= header_len;
- return (char *) icmpv6 + header_len;
- }
- /* Calculate the Internet checksum of some given data concatentated with the
- IPv4 pseudo-header. See RFC 1071 and TCP/IP Illustrated sections 3.2, 11.3,
- and 17.3. */
- unsigned short ipv4_pseudoheader_cksum(const struct in_addr *src,
- const struct in_addr *dst, u8 proto, u16 len, const void *hstart) {
- struct pseudo {
- struct in_addr src;
- struct in_addr dst;
- u8 zero;
- u8 proto;
- u16 length;
- } hdr;
- int sum;
- hdr.src = *src;
- hdr.dst = *dst;
- hdr.zero = 0;
- hdr.proto = proto;
- hdr.length = htons(len);
- /* Get the ones'-complement sum of the pseudo-header. */
- sum = ip_cksum_add(&hdr, sizeof(hdr), 0);
- /* Add it to the sum of the packet. */
- sum = ip_cksum_add(hstart, len, sum);
- /* Fold in the carry, take the complement, and return. */
- return ip_cksum_carry(sum);
- }
- /* Calculate the Internet checksum of some given data concatenated with the
- IPv6 pseudo-header. See RFC 2460 section 8.1. */
- u16 ipv6_pseudoheader_cksum(const struct in6_addr *src,
- const struct in6_addr *dst, u8 nxt, u32 len, const void *hstart) {
- struct {
- struct in6_addr src;
- struct in6_addr dst;
- u32 length;
- u8 z0, z1, z2;
- u8 nxt;
- } hdr;
- int sum;
- hdr.src = *src;
- hdr.dst = *dst;
- hdr.z0 = hdr.z1 = hdr.z2 = 0;
- hdr.length = htonl(len);
- hdr.nxt = nxt;
- sum = ip_cksum_add(&hdr, sizeof(hdr), 0);
- sum = ip_cksum_add(hstart, len, sum);
- /* RFC 2460: "Unlike IPv4, when UDP packets are originated by an IPv6 node,
- the UDP checksum is not optional. That is, whenever originating a UDP
- packet, an IPv6 node must compute a UDP checksum over the packet and the
- pseudo-header, and, if that computation yields a result of zero, it must be
- changed to hex FFFF for placement in the UDP header." */
- if (nxt == IP_PROTO_UDP && sum == 0)
- sum = 0xFFFF;
- return ip_cksum_carry(sum);
- }
- void sethdrinclude(int sd) {
- #ifdef IP_HDRINCL
- int one = 1;
- setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (const char *) &one, sizeof(one));
- #endif
- }
- void set_ipoptions(int sd, void *opts, size_t optslen) {
- #ifdef IP_OPTIONS
- if (sd == -1)
- return;
- setsockopt(sd, IPPROTO_IP, IP_OPTIONS, (const char *) opts, optslen);
- #endif
- }
- void set_ttl(int sd, int ttl) {
- #ifdef IP_TTL
- if (sd == -1)
- return;
- setsockopt(sd, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof ttl);
- #endif
- }
- /* Other than WIN32, what these systems have in common is that they use BPF for
- packet capture. (Solaris 10 and earlier used DLPI and had valid selectable
- fds.) */
- #if defined(WIN32) || defined(MACOSX) || (defined(FREEBSD) && (__FreeBSD_version < 500000) || defined(SOLARIS_BPF_PCAP_CAPTURE))
- /* Returns whether the system supports pcap_get_selectable_fd() properly */
- int pcap_selectable_fd_valid() {
- return 0;
- }
- /* Call this instead of pcap_get_selectable_fd directly (or your code
- won't compile on Windows). On systems which don't seem to support
- the pcap_get_selectable_fd() function properly, returns -1,
- otherwise simply calls pcap_selectable_fd and returns the
- results. If you just want to test whether the function is supported,
- use pcap_selectable_fd_valid() instead. */
- int my_pcap_get_selectable_fd(pcap_t *p) {
- return -1;
- }
- #else
- int pcap_selectable_fd_valid() {
- return 1;
- }
- int my_pcap_get_selectable_fd(pcap_t *p) {
- return pcap_get_selectable_fd(p);
- }
- #endif
- /* Are we guaranteed to be able to read exactly one frame for each time the pcap
- fd is selectable? If not, it's possible for the fd to become selectable, then
- for pcap_dispatch to buffer two or more frames, and return only the first one
- Because select doesn't know about pcap's buffer, the fd does not become
- selectable again, even though another pcap_next would succeed. On these
- platforms, we must do a non-blocking read from the fd before doing a select
- on the fd.
- It is guaranteed that if pcap_selectable_fd_valid() is false, then so is the
- return value of this function. */
- int pcap_selectable_fd_one_to_one() {
- #ifdef SOLARIS
- return 0;
- #endif
- return pcap_selectable_fd_valid();
- }
- /* returns -1 if we can't use select() on the pcap device, 0 for timeout, and
- * >0 for success. If select() fails we bail out because it couldn't work with
- * the file descriptor we got from my_pcap_get_selectable_fd()
- */
- int pcap_select(pcap_t *p, struct timeval *timeout) {
- int fd, ret;
- fd_set rfds;
- if ((fd = my_pcap_get_selectable_fd(p)) == -1)
- return -1;
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- do {
- errno = 0;
- ret = select(fd + 1, &rfds, NULL, NULL, timeout);
- if (ret == -1) {
- if (errno == EINTR)
- netutil_error("%s: %s", __func__, strerror(errno));
- else
- netutil_fatal("Your system does not support select()ing on pcap devices (%s). PLEASE REPORT THIS ALONG WITH DETAILED SYSTEM INFORMATION TO THE nmap-dev MAILING LIST!", strerror(errno));
- }
- } while (ret == -1);
- return ret;
- }
- int pcap_select(pcap_t *p, long usecs) {
- struct timeval tv;
- tv.tv_sec = usecs / 1000000;
- tv.tv_usec = usecs % 1000000;
- return pcap_select(p, &tv);
- }
- /* These two are for eth_open_cached() and eth_close_cached() */
- static char etht_cache_device_name[64];
- static eth_t *etht_cache_device = NULL;
- /* A simple function that caches the eth_t from dnet for one device,
- to avoid opening, closing, and re-opening it thousands of tims. If
- you give a different device, this function will close the first
- one. Thus this should never be used by programs that need to deal
- with multiple devices at once. In addition, you MUST NEVER
- eth_close() A DEVICE OBTAINED FROM THIS FUNCTION. Instead, you can
- call eth_close_cached() to close whichever device (if any) is
- cached. Returns NULL if it fails to open the device. */
- eth_t *eth_open_cached(const char *device) {
- if (!device)
- netutil_fatal("%s() called with NULL device name!", __func__);
- if (!*device)
- netutil_fatal("%s() called with empty device name!", __func__);
- if (strcmp(device, etht_cache_device_name) == 0) {
- /* Yay, we have it cached. */
- return etht_cache_device;
- }
- if (*etht_cache_device_name) {
- eth_close(etht_cache_device);
- etht_cache_device_name[0] = '\0';
- etht_cache_device = NULL;
- }
- etht_cache_device = eth_open(device);
- if (etht_cache_device)
- Strncpy(etht_cache_device_name, device,
- sizeof(etht_cache_device_name));
- return etht_cache_device;
- }
- /* See the description for eth_open_cached */
- void eth_close_cached() {
- if (etht_cache_device) {
- eth_close(etht_cache_device);
- etht_cache_device = NULL;
- etht_cache_device_name[0] = '\0';
- }
- return;
- }
- /* Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, IPPROTO_IP,
- * etc, and returns an ASCII representation (or the string "unknown" if
- * it doesn't recognize the number). If uppercase is non zero, the
- * returned value will be in uppercase letters, otherwise it'll be
- * in lowercase */
- const char *proto2ascii_case(u8 proto, int uppercase) {
- switch (proto) {
- case IPPROTO_TCP:
- return uppercase ? "TCP" : "tcp";
- break;
- case IPPROTO_UDP:
- return uppercase ? "UDP" : "udp";
- break;
- case IPPROTO_SCTP:
- return uppercase ? "SCTP" : "sctp";
- break;
- case IPPROTO_IP:
- return uppercase ? "IP" : "ip";
- break;
- #ifdef IPPROTO_ICMP
- case IPPROTO_ICMP:
- return uppercase ? "ICMP" : "icmp";
- break;
- #endif
- #ifdef IPPROTO_IPV6
- case IPPROTO_IPV6:
- return uppercase ? "IPv6" : "ipv6";
- break;
- #endif
- #ifdef IPPROTO_ICMPV6
- case IPPROTO_ICMPV6:
- return uppercase ? "ICMPv6" : "icmpv6";
- break;
- #endif
- #ifdef IPPROTO_GRE
- case IPPROTO_GRE: // Generic Routing Encapsulation
- return uppercase ? "GRE" : "gre";
- break;
- #endif
- #ifdef IPPROTO_ESP
- case IPPROTO_ESP: // Encapsulating Security Payload (IPSec)
- return uppercase ? "IPSec/ESP" : "ipsec/esp";
- break;
- #endif
- #ifdef IPPROTO_AH
- case IPPROTO_AH: // Authentication Header (IPSec)
- return uppercase ? "IPSec/AH" : "ipsec/ah";
- break;
- #endif
- default:
- return uppercase ? "UNKNOWN" : "unknown";
- }
- return NULL; // Unreached
- }
- const char *proto2ascii_lowercase(u8 proto) {
- return proto2ascii_case(proto, 0);
- }
- const char *proto2ascii_uppercase(u8 proto) {
- return proto2ascii_case(proto, 1);
- }
- /* Get an ASCII information about a tcp option which is pointed by
- optp, with a length of len. The result is stored in the result
- buffer. The result may look like "<mss 1452,sackOK,timestamp
- 45848914 0,nop,wscale 7>" */
- void tcppacketoptinfo(u8 *optp, int len, char *result, int bufsize) {
- assert(optp);
- assert(result);
- char *p, ch;
- u8 *q;
- int opcode;
- u16 tmpshort;
- u32 tmpword1, tmpword2;
- unsigned int i=0;
- p = result;
- *p = '\0';
- q = optp;
- ch = '<';
- while (len > 0 && bufsize > 2) {
- Snprintf(p, bufsize, "%c", ch);
- bufsize--;
- p++;
- opcode = *q++;
- if (!opcode) { /* End of List */
- Snprintf(p, bufsize, "eol");
- bufsize -= strlen(p);
- p += strlen(p);
- len--;
- } else if (opcode == 1) { /* No Op */
- Snprintf(p, bufsize, "nop");
- bufsize -= strlen(p);
- p += strlen(p);
- len--;
- } else if (opcode == 2) { /* MSS */
- if (len < 4)
- break; /* MSS has 4 bytes */
- q++;
- memcpy(&tmpshort, q, 2);
- Snprintf(p, bufsize, "mss %hu", (unsigned short) ntohs(tmpshort));
- bufsize -= strlen(p);
- p += strlen(p);
- q += 2;
- len -= 4;
- } else if (opcode == 3) { /* Window Scale */
- if (len < 3)
- break; /* Window Scale option has 3 bytes */
- q++;
- Snprintf(p, bufsize, "wscale %u", *q);
- bufsize -= strlen(p);
- p += strlen(p);
- q++;
- len -= 3;
- } else if (opcode == 4) { /* SACK permitted */
- if (len < 2)
- break; /* SACK permitted option has 2 bytes */
- Snprintf(p, bufsize, "sackOK");
- bufsize -= strlen(p);
- p += strlen(p);
- q++;
- len -= 2;
- } else if (opcode == 5) { /* SACK */
- unsigned sackoptlen = *q;
- if ((unsigned) len < sackoptlen)
- break;
- /* This would break parsing, so it's best to just give up */
- if (sackoptlen < 2)
- break;
- q++;
- if ((sackoptlen - 2) == 0 || ((sackoptlen - 2) % 8 != 0)) {
- Snprintf(p, bufsize, "malformed sack");
- bufsize -= strlen(p);
- p += strlen(p);
- } else {
- Snprintf(p, bufsize, "sack %d ", (sackoptlen - 2) / 8);
- bufsize -= strlen(p);
- p += strlen(p);
- for (i = 0; i < sackoptlen - 2; i += 8) {
- memcpy(&tmpword1, q + i, 4);
- memcpy(&tmpword2, q + i + 4, 4);
- Snprintf(p, bufsize, "{%u:%u}", tmpword1, tmpword2);
- bufsize -= strlen(p);
- p += strlen(p);
- }
- }
- q += sackoptlen - 2;
- len -= sackoptlen;
- } else if (opcode == 8) { /* Timestamp */
- if (len < 10)
- break; /* Timestamp option has 10 bytes */
- q++;
- memcpy(&tmpword1, q, 4);
- memcpy(&tmpword2, q + 4, 4);
- Snprintf(p, bufsize, "timestamp %lu %lu", (unsigned long) ntohl(tmpword1),
- (unsigned long) ntohl(tmpword2));
- bufsize -= strlen(p);
- p += strlen(p);
- q += 8;
- len -= 10;
- }
- ch = ',';
- }
- if (len > 0) {
- *result = '\0';
- return;
- }
- Snprintf(p, bufsize, ">");
- }
- /* A trivial function used with qsort to sort the routes by netmask and metric */
- static int routecmp(const void *a, const void *b) {
- struct sys_route *r1 = (struct sys_route *) a;
- struct sys_route *r2 = (struct sys_route *) b;
- if (r1->dest.ss_family < r2->dest.ss_family)
- return -1;
- else if (r1->dest.ss_family > r2->dest.ss_family)
- return 1;
- if (r1->netmask_bits < r2->netmask_bits)
- return 1;
- else if (r1->netmask_bits > r2->netmask_bits)
- return -1;
- if (r1->metric < r2->metric)
- return -1;
- else if (r1->metric > r2->metric)
- return 1;
- /* Compare addresses of equal elements to make the sort stable, as suggested
- by the Glibc manual. */
- if (a < b)
- return -1;
- else if (a > b)
- return 1;
- else
- return 0;
- }
- /* Convert an address to a string and back again. The first parsing step
- eliminates magical OS-specific syntax, for example on OS X, fe80:4::X:X:X:X
- becomes "fe80::X:X:X:X" (the "4" in this case is another way of writing the
- zone ID, like "%en0"; i.e., in this case en0 is interface number 4). This
- must be done before e.g. comparing addresses by netmask. */
- static int canonicalize_address(const struct sockaddr_storage *ss,
- struct sockaddr_storage *output) {
- char canonical_ip_string[NI_MAXHOST];
- struct addrinfo hints;
- struct addrinfo *ai;
- int rc;
- /* Convert address to string. */
- rc = getnameinfo((struct sockaddr *) ss, sizeof(*ss),
- canonical_ip_string, sizeof(canonical_ip_string), NULL, 0, NI_NUMERICHOST);
- if (rc != 0) {
- /* Don't care. */
- *output = *ss;
- return 0;
- }
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = ss->ss_family;
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags |= AI_NUMERICHOST;
- rc = getaddrinfo(canonical_ip_string, NULL, &hints, &ai);
- if (rc != 0 || ai == NULL)
- return -1;
- assert(ai->ai_addrlen > 0 && ai->ai_addrlen <= (int) sizeof(*output));
- memcpy(output, ai->ai_addr, ai->ai_addrlen);
- freeaddrinfo(ai);
- return 0;
- }
- static int collect_dnet_interfaces(const struct intf_entry *entry, void *arg) {
- struct dnet_collector_route_nfo *dcrn = (struct dnet_collector_route_nfo *) arg;
- bool primary_done;
- unsigned int num_aliases_done;
- struct sockaddr_storage tmpss;
- int rc;
- primary_done = false;
- num_aliases_done = 0;
- while (!primary_done || num_aliases_done < entry->intf_alias_num) {
- /* Make sure we have room for the new route */
- if (dcrn->numifaces >= dcrn->capacity) {
- dcrn->capacity <<= 2;
- dcrn->ifaces = (struct interface_info *) safe_realloc(dcrn->ifaces,
- dcrn->capacity * sizeof(struct interface_info));
- }
- /* The first time through the loop we add the primary interface record.
- After that we add the aliases one at a time. */
- if (!primary_done) {
- if (addr_ntos(&entry->intf_addr, (struct sockaddr *) &tmpss) == -1) {
- dcrn->ifaces[dcrn->numifaces].addr.ss_family = 0;
- } else {
- rc = canonicalize_address(&tmpss, &dcrn->ifaces[dcrn->numifaces].addr);
- assert(rc == 0);
- }
- dcrn->ifaces[dcrn->numifaces].netmask_bits = entry->intf_addr.addr_bits;
- primary_done = true;
- } else if (num_aliases_done < entry->intf_alias_num) {
- if (addr_ntos(&entry->intf_alias_addrs[num_aliases_done], (struct sockaddr *) &tmpss) == -1) {
- dcrn->ifaces[dcrn->numifaces].addr.ss_family = 0;
- } else {
- rc = canonicalize_address(&tmpss, &dcrn->ifaces[dcrn->numifaces].addr);
- assert(rc == 0);
- }
- dcrn->ifaces[dcrn->numifaces].netmask_bits = entry->intf_alias_addrs[num_aliases_done].addr_bits;
- num_aliases_done++;
- }
- /* OK, address/netmask found. Let's get the name */
- Strncpy(dcrn->ifaces[dcrn->numifaces].devname, entry->intf_name,
- sizeof(dcrn->ifaces[dcrn->numifaces].devname));
- Strncpy(dcrn->ifaces[dcrn->numifaces].devfullname, entry->intf_name,
- sizeof(dcrn->ifaces[dcrn->numifaces].devfullname));
- /* Interface type */
- if (entry->intf_type == INTF_TYPE_ETH && (entry->intf_flags & INTF_FLAG_NOARP) == 0) {
- dcrn->ifaces[dcrn->numifaces].device_type = devt_ethernet;
- /* Collect the MAC address since this is ethernet */
- memcpy(dcrn->ifaces[dcrn->numifaces].mac, &entry->intf_link_addr.addr_eth.data, 6);
- } else if (entry->intf_type == INTF_TYPE_LOOPBACK) {
- dcrn->ifaces[dcrn->numifaces].device_type = devt_loopback;
- } else if (entry->intf_type == INTF_TYPE_TUN) {
- dcrn->ifaces[dcrn->numifaces].device_type = devt_p2p;
- } else {
- dcrn->ifaces[dcrn->numifaces].device_type = devt_other;
- }
- dcrn->ifaces[dcrn->numifaces].ifindex = entry->intf_index;
- dcrn->ifaces[dcrn->numifaces].mtu = entry->intf_mtu;
- /* Is the interface up and running? */
- dcrn->ifaces[dcrn->numifaces].device_up = (entry->intf_flags & INTF_FLAG_UP) ? true : false;
- /* For the rest of the information, we must open the interface directly ... */
- dcrn->numifaces++;
- }
- return 0;
- }
- /* Get a list of interfaces using dnet and intf_loop. */
- static struct interface_info *getinterfaces_dnet(int *howmany, char *errstr, size_t errstrlen) {
- struct dnet_collector_route_nfo dcrn;
- intf_t *it;
- dcrn.routes = NULL;
- dcrn.numroutes = 0;
- dcrn.numifaces = 0;
- assert(howmany);
- /* Initialize the interface array. */
- dcrn.capacity = 16;
- dcrn.ifaces = (struct interface_info *) safe_zalloc(sizeof(struct interface_info) * dcrn.capacity);
- it = intf_open();
- if (!it){
- if(errstr) Snprintf(errstr, errstrlen, "%s: intf_open() failed", __func__);
- *howmany=-1;
- return NULL;
- }
- if (intf_loop(it, collect_dnet_interfaces, &dcrn) != 0){
- if(errstr) Snprintf(errstr, errstrlen, "%s: intf_loop() failed", __func__);
- *howmany=-1;
- return NULL;
- }
- intf_close(it);
- *howmany = dcrn.numifaces;
- return dcrn.ifaces;
- }
- /* Returns an allocated array of struct interface_info representing the
- available interfaces. The number of interfaces is returned in *howmany. This
- function just does caching of results; the real work is done in
- getinterfaces_dnet().
- On error, NULL is returned, howmany is set to -1 and the supplied
- error buffer "errstr", if not NULL, will contain an error message. */
- struct interface_info *getinterfaces(int *howmany, char *errstr, size_t errstrlen) {
- static int initialized = 0;
- static struct interface_info *mydevs;
- static int numifaces = 0;
- if (!initialized) {
- mydevs = getinterfaces_dnet(&numifaces, errstr, errstrlen);
- initialized = 1;
- }
- /* These will propagate any error produced in getinterfaces_xxxx() to
- * the caller. */
- if (howmany)
- *howmany = numifaces;
- return mydevs;
- }
- /* The 'dev' passed in must be at least 32 bytes long. Returns 0 on success. */
- int ipaddr2devname(char *dev, const struct sockaddr_storage *addr) {
- struct interface_info *ifaces;
- int numifaces;
- int i;
- ifaces = getinterfaces(&numifaces, NULL, 0);
- if (ifaces == NULL)
- return -1;
- for (i = 0; i < numifaces; i++) {
- if (sockaddr_storage_cmp(&ifaces[i].addr, addr) == 0) {
- Strncpy(dev, ifaces[i].devname, 32);
- return 0;
- }
- }
- return -1;
- }
- int devname2ipaddr(char *dev, struct sockaddr_storage *addr) {
- struct interface_info *mydevs;
- int numdevs;
- int i;
- mydevs = getinterfaces(&numdevs, NULL, 0);
- if (!mydevs)
- return -1;
- for (i = 0; i < numdevs; i++) {
- if (!strcmp(dev, mydevs[i].devfullname)) {
- *addr = mydevs[i].addr;
- return 0;
- }
- }
- return -1;
- }
- /* Looks for an interface with the given name (iname) and address
- family type, and returns the corresponding interface_info if found.
- Will accept a match of devname or devfullname. Returns NULL if
- none found */
- struct interface_info *getInterfaceByName(const char *iname, int af) {
- struct interface_info *ifaces;
- int numifaces = 0;
- int ifnum;
- ifaces = getinterfaces(&numifaces, NULL, 0);
- for (ifnum = 0; ifnum < numifaces; ifnum++) {
- if ((strcmp(ifaces[ifnum].devfullname, iname) == 0 ||
- strcm…
Large files files are truncated, but you can click here to view the full file