masscan-mark-ii/src/rawsock-getip6.c

259 lines
6.6 KiB
C

/*
retrieve IPv4 address of the named network interface/adapter
like "eth0"
This works on:
- Windows
- Linux
- Apple
- FreeBSD
I think it'll work the same on any BSD system.
*/
#include "rawsock.h"
#include "util-safefunc.h"
#include "massip-parse.h"
/*****************************************************************************
*****************************************************************************/
#if defined(__linux__)
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
ipv6address
rawsock_get_adapter_ipv6(const char *ifname)
{
struct ifaddrs *list = NULL;
struct ifaddrs *ifa;
int err;
ipv6address result = {0,0};
/* Fetch the list of addresses */
err = getifaddrs(&list);
if (err == -1) {
fprintf(stderr, "[-] getifaddrs(): %s\n", strerror(errno));
return result;
}
for (ifa = list; ifa != NULL; ifa = ifa->ifa_next) {
ipv6address addr;
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_name == NULL)
continue;
if (strcmp(ifname, ifa->ifa_name) != 0)
continue;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
addr = ipv6address_from_bytes((const unsigned char *)&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr);
if (addr.hi>>56ULL >= 0xFC)
continue;
if (addr.hi>>32ULL == 0x20010db8)
continue;
result = addr;
break;
}
freeifaddrs(list);
return result;
}
/*****************************************************************************
*****************************************************************************/
#elif defined(WIN32)
/* From:
* https://stackoverflow.com/questions/10972794/undefined-reference-to-getadaptersaddresses20-but-i-included-liphlpapi
*/
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x501
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501
#endif
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <WS2tcpip.h>
#include <iphlpapi.h>
#ifdef _MSC_VER
#pragma comment(lib, "IPHLPAPI.lib")
#endif
ipv6address
rawsock_get_adapter_ipv6(const char *ifname)
{
ULONG err;
ipv6address result = {0,0};
IP_ADAPTER_ADDRESSES *adapters = NULL;
IP_ADAPTER_ADDRESSES *adapter;
IP_ADAPTER_UNICAST_ADDRESS *addr;
ULONG sizeof_addrs = 0;
ifname = rawsock_win_name(ifname);
again:
err = GetAdaptersAddresses(
AF_INET6, /* Get IPv6 addresses only */
0,
0,
adapters,
&sizeof_addrs);
if (err == ERROR_BUFFER_OVERFLOW) {
free(adapters);
adapters = malloc(sizeof_addrs);
if (adapters == NULL) {
fprintf(stderr, "GetAdaptersAddresses():malloc(): failed: out of memory\n");
return result;
}
goto again;
}
if (err != NO_ERROR) {
fprintf(stderr, "GetAdaptersAddresses(): failed: %u\n", (unsigned)err);
return result;
}
/*
* loop through all adapters looking for ours
*/
for (adapter = adapters; adapter != NULL; adapter = adapter->Next) {
if (rawsock_is_adapter_names_equal(adapter->AdapterName, ifname))
break;
}
/*
* If our adapter isn't found, print an error.
*/
if (adapters == NULL) {
fprintf(stderr, "GetAdaptersInfo: adapter not found: %s\n", ifname);
goto end;
}
/*
* Search through the list of returned addresses looking for the first
* that matches an IPv6 address.
*/
for (addr = adapter->FirstUnicastAddress; addr; addr = addr->Next) {
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)addr->Address.lpSockaddr;
//char buf[64];
ipv6address ipv6;
/* Ignore any address that isn't IPv6 */
if (sa->sin6_family != AF_INET6)
continue;
/* Ignore transient cluster addresses */
if (addr->Flags == IP_ADAPTER_ADDRESS_TRANSIENT)
continue;
/* Don't use operating-system function for this, because they aren't
* really portable or safe */
ipv6 = ipv6address_from_bytes((const unsigned char *)&sa->sin6_addr);
if (addr->PrefixOrigin == IpPrefixOriginWellKnown) {
/* This value applies to an IPv6 link-local address or an IPv6 loopback address */
continue;
}
if (addr->PrefixOrigin == IpPrefixOriginRouterAdvertisement && addr->SuffixOrigin == IpSuffixOriginRandom) {
/* This is a temporary IPv6 address
* See: http://technet.microsoft.com/en-us/ff568768(v=vs.60).aspx */
continue;
}
if (ipv6.hi>>56ULL >= 0xFC)
continue;
if (ipv6.hi>>32ULL == 0x20010db8)
continue;
result = ipv6;
}
end:
free(adapters);
return result;
}
/*****************************************************************************
*****************************************************************************/
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || 1
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#ifdef AF_LINK
# include <net/if_dl.h>
#endif
#ifdef AF_PACKET
# include <netpacket/packet.h>
#endif
ipv6address
rawsock_get_adapter_ipv6(const char *ifname)
{
struct ifaddrs *list = NULL;
struct ifaddrs *ifa;
int err;
ipv6address result = {0,0};
/* Fetch the list of addresses */
err = getifaddrs(&list);
if (err == -1) {
fprintf(stderr, "[-] getifaddrs(): %s\n", strerror(errno));
return result;
}
for (ifa = list; ifa != NULL; ifa = ifa->ifa_next) {
ipv6address addr;
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_name == NULL)
continue;
if (strcmp(ifname, ifa->ifa_name) != 0)
continue;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
addr = ipv6address_from_bytes((const unsigned char *)&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr);
if (addr.hi>>56ULL >= 0xFC)
continue;
if (addr.hi>>32ULL == 0x20010db8)
continue;
result = addr;
break;
}
freeifaddrs(list);
return result;
}
#endif