1 /*
2     Simple module for handling addresses (IPv6, IPv4, MAC).
3     Also implements a 128-bit type for dealing with addresses.
4 
5     This is the module that almost all the other code depends
6     upon, because everything else deals with the IP address
7     types defined here.
8 
9 */
10 #ifndef MASSIP_ADDR_H
11 #define MASSIP_ADDR_H
12 #include <stdint.h>
13 #include <stddef.h>
14 
15 #if defined(_MSC_VER) && !defined(inline)
16 #define inline __inline
17 #endif
18 #if defined(_MSC_VER)
19 #pragma warning(disable: 4201)
20 #endif
21 
22 /**
23  * An IPv6 address is represented as two 64-bit integers intead of a single
24  * 128-bit integer. This is because curently (year 2020) most compilers
25  * do not support the `uint128_t` type, but all relevant ones do support
26  * the `uint64_t` type.
27  */
28 struct ipv6address {uint64_t hi; uint64_t lo;};
29 typedef struct ipv6address ipv6address;
30 typedef struct ipv6address ipv6address_t;
31 
32 /**
33  * IPv4 addresses are represented simply with an integer.
34  */
35 typedef unsigned ipv4address;
36 typedef ipv4address ipv4address_t;
37 
38 /**
39  * MAC address (layer 2).  Since we have canonical types for IPv4/IPv6
40  * addresses, we may as well have a canonical type for MAC addresses,
41  * too.
42  */
43 struct macaddress_t {unsigned char addr[6];};
44 typedef struct macaddress_t macaddress_t;
45 
46 /**
47  * In many cases we need to do arithmetic on IPv6 addresses, treating
48  * them as a large 128-bit integer. Thus, we declare our own 128-bit
49  * integer type (and some accompanying math functions). But it's
50  * still just the same as a 128-bit integer.
51  */
52 typedef ipv6address massint128_t;
53 
54 
55 /**
56  * Most of the code in this project is agnostic to the version of IP
57  * addresses (IPv4 or IPv6). Therefore, we represnet them as a union
58  * distinguished by a version number. The `version` is an integer
59  * with a value of either 4 or 6.
60  */
61 struct ipaddress {
62     union {
63         unsigned ipv4;
64         ipv6address ipv6;
65     };
66     unsigned char version;
67 };
68 typedef struct ipaddress ipaddress;
69 
ipv6address_is_zero(ipv6address_t a)70 static inline int ipv6address_is_zero(ipv6address_t a) {
71     return a.hi == 0 && a.lo == 0;
72 }
73 #define massint128_is_zero ipv6address_is_zero
74 
ipv6address_is_invalid(ipv6address_t a)75 static inline int ipv6address_is_invalid(ipv6address_t a) {
76     return a.hi == ~0ULL && a.lo == ~0ULL;
77 }
ipv6address_is_equal(ipv6address_t a,ipv6address_t b)78 static inline int ipv6address_is_equal(ipv6address_t a, ipv6address_t b) {
79     return a.hi == b.hi && a.lo == b.lo;
80 }
ipv6address_is_lessthan(ipv6address_t a,ipv6address_t b)81 static inline int ipv6address_is_lessthan(ipv6address_t a, ipv6address_t b) {
82     return (a.hi == b.hi)?(a.lo < b.lo):(a.hi < b.hi);
83 }
84 
85 int ipv6address_is_equal_prefixed(ipv6address_t lhs, ipv6address_t rhs, unsigned prefix);
86 
87 
ipv6address_from_bytes(const unsigned char * buf)88 static inline ipv6address ipv6address_from_bytes(const unsigned char *buf) {
89     ipv6address addr;
90     addr.hi = (uint64_t)buf[ 0] << 56
91             | (uint64_t)buf[ 1] << 48
92             | (uint64_t)buf[ 2] << 40
93             | (uint64_t)buf[ 3] << 32
94             | (uint64_t)buf[ 4] << 24
95             | (uint64_t)buf[ 5] << 16
96             | (uint64_t)buf[ 6] <<  8
97             | (uint64_t)buf[ 7] <<  0;
98     addr.lo = (uint64_t)buf[ 8] << 56
99             | (uint64_t)buf[ 9] << 48
100             | (uint64_t)buf[10] << 40
101             | (uint64_t)buf[11] << 32
102             | (uint64_t)buf[12] << 24
103             | (uint64_t)buf[13] << 16
104             | (uint64_t)buf[14] <<  8
105             | (uint64_t)buf[15] <<  0;
106     return addr;
107 }
macaddress_from_bytes(const void * vbuf)108 static inline macaddress_t macaddress_from_bytes(const void *vbuf)
109 {
110     const unsigned char *buf = (const unsigned char *)vbuf;
111     macaddress_t result;
112     result.addr[0] = buf[0];
113     result.addr[1] = buf[1];
114     result.addr[2] = buf[2];
115     result.addr[3] = buf[3];
116     result.addr[4] = buf[4];
117     result.addr[5] = buf[5];
118     return result;
119 }
macaddress_is_zero(macaddress_t mac)120 static inline int macaddress_is_zero(macaddress_t mac)
121 {
122     return mac.addr[0] == 0
123     && mac.addr[1] == 0
124     && mac.addr[2] == 0
125     && mac.addr[3] == 0
126     && mac.addr[4] == 0
127     && mac.addr[5] == 0;
128 }
macaddress_is_equal(macaddress_t lhs,macaddress_t rhs)129 static inline int macaddress_is_equal(macaddress_t lhs, macaddress_t rhs)
130 {
131     return lhs.addr[0] == rhs.addr[0]
132     && lhs.addr[1] == rhs.addr[1]
133     && lhs.addr[2] == rhs.addr[2]
134     && lhs.addr[3] == rhs.addr[3]
135     && lhs.addr[4] == rhs.addr[4]
136     && lhs.addr[5] == rhs.addr[5];
137 }
138 
139 /**
140  * Return a buffer with the formatted address
141  */
142 typedef struct ipaddress_formatted {
143     char string[48];
144 } ipaddress_formatted_t;
145 
146 struct ipaddress_formatted ipv6address_fmt(ipv6address a);
147 struct ipaddress_formatted ipv4address_fmt(ipv4address a);
148 struct ipaddress_formatted ipaddress_fmt(ipaddress a);
149 struct ipaddress_formatted macaddress_fmt(macaddress_t a);
150 
151 unsigned massint128_bitcount(massint128_t num);
152 
153 /**
154  * @return 0 on success, 1 on failure
155  */
156 int ipv6address_selftest(void);
157 
158 #endif
159