1 #include "massip-addr.h"
2 #include <string.h>
3
4
5 /**
6 * Holds the output string, so that we can append to it without
7 * overflowing buffers. The _append_xxx() functions below append
8 * to this string.
9 */
10 typedef struct stream_t {
11 char *buf;
12 size_t offset;
13 size_t length;
14 } stream_t;
15
16 /**
17 * Append a character to the output string. All the other _append_xxx()
18 * functions call this one, so this is the only one where a
19 * buffer-overflow can occur.
20 */
21 static void
_append_char(stream_t * out,char c)22 _append_char(stream_t *out, char c)
23 {
24 if (out->offset < out->length)
25 out->buf[out->offset++] = c;
26
27 /* keep the string nul terminated as we build it */
28 if (out->offset < out->length)
29 out->buf[out->offset] = '\0';
30 }
31
32 static void
_append_ipv6(stream_t * out,const unsigned char * ipv6)33 _append_ipv6(stream_t *out, const unsigned char *ipv6)
34 {
35 static const char hex[] = "0123456789abcdef";
36 size_t i;
37 int is_ellision = 0;
38
39 /* An IPv6 address is pritned as a series of 2-byte hex words
40 * separated by colons :, for a total of 16-bytes */
41 for (i = 0; i < 16; i += 2) {
42 unsigned n = ipv6[i] << 8 | ipv6[i + 1];
43
44 /* Handle the ellision case. A series of words with a value
45 * of 0 can be removed completely, replaced by an extra colon */
46 if (n == 0 && !is_ellision) {
47 is_ellision = 1;
48 while (i < 16 && ipv6[i + 2] == 0 && ipv6[i + 3] == 0)
49 i += 2;
50 _append_char(out, ':');
51
52 /* test for all-zero address, in which case the output
53 * will be "::". */
54 if (i == 14)
55 _append_char(out, ':');
56 continue;
57 }
58
59 /* Print the colon between numbers. Fence-post alert: only colons
60 * between numbers are printed, not at the beginning or end of the
61 * stirng */
62 if (i)
63 _append_char(out, ':');
64
65 /* Print the digits. Leading zeroes are not printed */
66 if (n >> 12)
67 _append_char(out, hex[(n >> 12) & 0xF]);
68 if (n >> 8)
69 _append_char(out, hex[(n >> 8) & 0xF]);
70 if (n >> 4)
71 _append_char(out, hex[(n >> 4) & 0xF]);
72 _append_char(out, hex[(n >> 0) & 0xF]);
73 }
74 }
75
ipv6address_fmt(ipv6address a)76 struct ipaddress_formatted ipv6address_fmt(ipv6address a)
77 {
78 struct ipaddress_formatted out;
79 unsigned char tmp[16];
80 size_t i;
81 stream_t s;
82
83 /*
84 * Convert address into a sequence of bytes. Our code
85 * here represents an IPv6 address as two 64-bit numbers, but
86 * the formatting code above that we copied from a diffent
87 * project represents it as an array of bytes.
88 */
89 for (i=0; i<16; i++) {
90 uint64_t x;
91 if (i<8)
92 x = a.hi;
93 else
94 x = a.lo;
95 x >>= (7 - (i%8)) * 8;
96
97 tmp[i] = (unsigned char)(x & 0xFF);
98 }
99
100 /* Call the formatting function */
101 s.buf = out.string;
102 s.offset = 0;
103 s.length = sizeof(out.string);
104 _append_ipv6(&s, tmp);
105
106 return out;
107 }
108
109 /**
110 * Append a decimal integer.
111 */
112 static void
_append_decimal(stream_t * out,unsigned long long n)113 _append_decimal(stream_t *out, unsigned long long n)
114 {
115 char tmp[64];
116 size_t tmp_offset = 0;
117
118 /* Create temporary string */
119 while (n >= 10) {
120 unsigned digit = n % 10;
121 n /= 10;
122 tmp[tmp_offset++] = (char)('0' + digit);
123 }
124
125 /* the final digit, may be zero */
126 tmp[tmp_offset++] = (char)('0' + n);
127
128 /* Copy the result backwards */
129 while (tmp_offset)
130 _append_char(out, tmp[--tmp_offset]);
131 }
132 static void
_append_hex2(stream_t * out,unsigned long long n)133 _append_hex2(stream_t *out, unsigned long long n)
134 {
135 static const char hex[17] = "0123456789abcdef";
136
137 _append_char(out, hex[(n>>4)&0xF]);
138 _append_char(out, hex[(n>>0)&0xF]);
139 }
140
ipv4address_fmt(ipv4address ip)141 struct ipaddress_formatted ipv4address_fmt(ipv4address ip)
142 {
143 struct ipaddress_formatted out;
144 stream_t s;
145
146
147 /* Call the formatting function */
148 s.buf = out.string;
149 s.offset = 0;
150 s.length = sizeof(out.string);
151
152 _append_decimal(&s, (ip >> 24) & 0xFF);
153 _append_char(&s, '.');
154 _append_decimal(&s, (ip >> 16) & 0xFF);
155 _append_char(&s, '.');
156 _append_decimal(&s, (ip >> 8) & 0xFF);
157 _append_char(&s, '.');
158 _append_decimal(&s, (ip >> 0) & 0xFF);
159
160 return out;
161 }
162
macaddress_fmt(macaddress_t mac)163 struct ipaddress_formatted macaddress_fmt(macaddress_t mac)
164 {
165 struct ipaddress_formatted out;
166 stream_t s;
167
168
169 /* Call the formatting function */
170 s.buf = out.string;
171 s.offset = 0;
172 s.length = sizeof(out.string);
173
174 _append_hex2(&s, mac.addr[0]);
175 _append_char(&s, '-');
176 _append_hex2(&s, mac.addr[1]);
177 _append_char(&s, '-');
178 _append_hex2(&s, mac.addr[2]);
179 _append_char(&s, '-');
180 _append_hex2(&s, mac.addr[3]);
181 _append_char(&s, '-');
182 _append_hex2(&s, mac.addr[4]);
183 _append_char(&s, '-');
184 _append_hex2(&s, mac.addr[5]);
185
186 return out;
187 }
188
ipaddress_fmt(ipaddress a)189 struct ipaddress_formatted ipaddress_fmt(ipaddress a)
190 {
191 struct ipaddress_formatted out;
192 stream_t s;
193 ipv4address ip = a.ipv4;
194
195 if (a.version == 6) {
196 return ipv6address_fmt(a.ipv6);
197 }
198
199
200 /* Call the formatting function */
201 s.buf = out.string;
202 s.offset = 0;
203 s.length = sizeof(out.string);
204
205 _append_decimal(&s, (ip >> 24) & 0xFF);
206 _append_char(&s, '.');
207 _append_decimal(&s, (ip >> 16) & 0xFF);
208 _append_char(&s, '.');
209 _append_decimal(&s, (ip >> 8) & 0xFF);
210 _append_char(&s, '.');
211 _append_decimal(&s, (ip >> 0) & 0xFF);
212
213 return out;
214 }
215
216
_count_long(uint64_t number)217 static unsigned _count_long(uint64_t number)
218 {
219 unsigned i;
220 unsigned count = 0;
221 for (i=0; i<64; i++) {
222 if ((number >> i) & 1)
223 count = i + 1;
224 }
225 return count;
226 }
227
massint128_bitcount(massint128_t number)228 unsigned massint128_bitcount(massint128_t number)
229 {
230 if (number.hi)
231 return _count_long(number.hi) + 64;
232 else
233 return _count_long(number.lo);
234 }
235
ipv6address_selftest(void)236 int ipv6address_selftest(void)
237 {
238 int x = 0;
239 ipaddress ip;
240
241 ip.version = 4;
242 ip.ipv4 = 0x01FF00A3;
243
244 if (strcmp(ipaddress_fmt(ip).string, "1.255.0.163") != 0)
245 x++;
246
247 return x;
248 }
249
ipv6address_is_equal_prefixed(ipv6address_t lhs,ipv6address_t rhs,unsigned prefix)250 int ipv6address_is_equal_prefixed(ipv6address_t lhs, ipv6address_t rhs, unsigned prefix)
251 {
252 ipv6address mask;
253
254 /* If the prefix is bad, then the answer is 'no'. */
255 if (prefix > 128) {
256 return 0;
257 }
258
259 /* Create the mask from the prefix */
260 if (prefix > 64)
261 mask.hi = ~0ULL;
262 else if (prefix == 0)
263 mask.hi = 0;
264 else
265 mask.hi = ~0ULL << (64 - prefix);
266
267 if (prefix > 64)
268 mask.lo = ~0ULL << (128 - prefix);
269 else
270 mask.lo = 0;
271
272 /* Mask off any non-zero bits from both addresses */
273 lhs.hi &= mask.hi;
274 lhs.lo &= mask.lo;
275 rhs.hi &= mask.hi;
276 rhs.lo &= mask.lo;
277
278 /* Now do a normal compare */
279 return ipv6address_is_equal(lhs, rhs);
280 }
281