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