masscan-mark-ii/src/massip-addr.h

199 lines
5.8 KiB
C

/*
Simple module for handling addresses (IPv6, IPv4, MAC).
Also implements a 128-bit type for dealing with addresses.
This is the module that almost all the other code depends
upon, because everything else deals with the IP address
types defined here.
*/
#ifndef MASSIP_ADDR_H
#define MASSIP_ADDR_H
#include <stdint.h>
#include <stddef.h>
#if defined(_MSC_VER) && !defined(inline)
#define inline __inline
#endif
#if defined(_MSC_VER)
#pragma warning(disable: 4201)
#endif
/**
* An IPv6 address is represented as two 64-bit integers instead of a single
* 128-bit integer. This is because currently (year 2020) most compilers
* do not support the `uint128_t` type, but all relevant ones do support
* the `uint64_t` type.
*/
struct ipv6address {uint64_t hi; uint64_t lo;};
typedef struct ipv6address ipv6address;
typedef struct ipv6address ipv6address_t;
/**
* IPv4 addresses are represented simply with an integer.
*/
typedef unsigned ipv4address;
typedef ipv4address ipv4address_t;
/**
* MAC address (layer 2). Since we have canonical types for IPv4/IPv6
* addresses, we may as well have a canonical type for MAC addresses,
* too.
*/
struct macaddress_t {unsigned char addr[6];};
typedef struct macaddress_t macaddress_t;
/**
* In many cases we need to do arithmetic on IPv6 addresses, treating
* them as a large 128-bit integer. Thus, we declare our own 128-bit
* integer type (and some accompanying math functions). But it's
* still just the same as a 128-bit integer.
*/
typedef ipv6address massint128_t;
/**
* Most of the code in this project is agnostic to the version of IP
* addresses (IPv4 or IPv6). Therefore, we represent them as a union
* distinguished by a version number. The `version` is an integer
* with a value of either 4 or 6.
*/
struct ipaddress {
union {
unsigned ipv4;
ipv6address ipv6;
};
unsigned char version;
};
typedef struct ipaddress ipaddress;
/** @return true if the IPv6 address is zero [::] */
static inline int ipv6address_is_zero(ipv6address_t a) {
return a.hi == 0 && a.lo == 0;
}
#define massint128_is_zero ipv6address_is_zero
/** The IPv6 address [FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]
* is invalid */
static inline int ipv6address_is_invalid(ipv6address_t a) {
return a.hi == ~0ULL && a.lo == ~0ULL;
}
/** Compare two IPv6 addresses */
static inline int ipv6address_is_equal(ipv6address_t a, ipv6address_t b) {
return a.hi == b.hi && a.lo == b.lo;
}
static inline int ipaddress_is_equal(ipaddress a, ipaddress b) {
if (a.version != b.version)
return 0;
if (a.version == 4) {
return a.ipv4 == b.ipv4;
} else if (a.version == 6) {
return ipv6address_is_equal(a.ipv6, b.ipv6);
} else
return 0;
}
/** Compare two IPv6 addresses, to see which one comes frist. This is used
* in sorting the addresses
* @return true if a < b, false otherwise */
static inline int ipv6address_is_lessthan(ipv6address_t a, ipv6address_t b) {
return (a.hi == b.hi)?(a.lo < b.lo):(a.hi < b.hi);
}
/**
* Mask the lower bits of each address and test if the upper bits are equal
*/
int ipv6address_is_equal_prefixed(ipv6address_t lhs, ipv6address_t rhs, unsigned prefix);
ipv6address_t ipv6address_add_uint64(ipv6address_t lhs, uint64_t rhs);
ipv6address_t ipv6address_subtract(ipv6address_t lhs, ipv6address_t rhs);
ipv6address_t ipv6address_add(ipv6address_t lhs, ipv6address_t rhs);
/**
* Given a typical EXTERNAL representation of an IPv6 address, which is
* an array of 16 bytes, convert to the canonical INTERNAL address.
*/
static inline ipv6address ipv6address_from_bytes(const unsigned char *buf) {
ipv6address addr;
addr.hi = (uint64_t)buf[ 0] << 56
| (uint64_t)buf[ 1] << 48
| (uint64_t)buf[ 2] << 40
| (uint64_t)buf[ 3] << 32
| (uint64_t)buf[ 4] << 24
| (uint64_t)buf[ 5] << 16
| (uint64_t)buf[ 6] << 8
| (uint64_t)buf[ 7] << 0;
addr.lo = (uint64_t)buf[ 8] << 56
| (uint64_t)buf[ 9] << 48
| (uint64_t)buf[10] << 40
| (uint64_t)buf[11] << 32
| (uint64_t)buf[12] << 24
| (uint64_t)buf[13] << 16
| (uint64_t)buf[14] << 8
| (uint64_t)buf[15] << 0;
return addr;
}
/**
* Given a typical EXTERNAL representation of an Ethernet MAC address,
* which is an array of 6 bytes, convert to the canonical INTERNAL address.
*/
static inline macaddress_t macaddress_from_bytes(const void *vbuf)
{
const unsigned char *buf = (const unsigned char *)vbuf;
macaddress_t result;
result.addr[0] = buf[0];
result.addr[1] = buf[1];
result.addr[2] = buf[2];
result.addr[3] = buf[3];
result.addr[4] = buf[4];
result.addr[5] = buf[5];
return result;
}
/** Test if the Ethernet MAC address is all zeroes */
static inline int macaddress_is_zero(macaddress_t mac)
{
return mac.addr[0] == 0
&& mac.addr[1] == 0
&& mac.addr[2] == 0
&& mac.addr[3] == 0
&& mac.addr[4] == 0
&& mac.addr[5] == 0;
}
/** Compare two Ethernet MAC addresses to see if they are equal */
static inline int macaddress_is_equal(macaddress_t lhs, macaddress_t rhs)
{
return lhs.addr[0] == rhs.addr[0]
&& lhs.addr[1] == rhs.addr[1]
&& lhs.addr[2] == rhs.addr[2]
&& lhs.addr[3] == rhs.addr[3]
&& lhs.addr[4] == rhs.addr[4]
&& lhs.addr[5] == rhs.addr[5];
}
/**
* Return a buffer with the formatted address
*/
typedef struct ipaddress_formatted {
char string[48];
} ipaddress_formatted_t;
struct ipaddress_formatted ipv6address_fmt(ipv6address a);
struct ipaddress_formatted ipv4address_fmt(ipv4address a);
struct ipaddress_formatted ipaddress_fmt(ipaddress a);
struct ipaddress_formatted macaddress_fmt(macaddress_t a);
unsigned massint128_bitcount(massint128_t num);
/**
* @return 0 on success, 1 on failure
*/
int ipv6address_selftest(void);
#endif