]> jfr.im git - irc/quakenet/newserv.git/blob - lib/irc_ipv6.c
Rename trusts_cidr2str to CIDRtostr() and move it to lib/irc_ipv6.c.
[irc/quakenet/newserv.git] / lib / irc_ipv6.c
1 /* IPv6 helper functions */
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <assert.h>
6 #include <arpa/inet.h>
7 #include <netdb.h>
8 #include "irc_ipv6.h"
9 #include <stdio.h>
10
11 #warning This source file is probably GPLed, it needs relicensing.
12
13 /** Convert an IP address to printable ASCII form.
14 * This is generally deprecated in favor of ircd_ntoa_r().
15 * @param[in] in Address to convert.
16 * @return Pointer to a static buffer containing the readable form.
17 */
18 const char* ircd_ntoa(const struct irc_in_addr* in)
19 {
20 static char buf[SOCKIPLEN];
21 return ircd_ntoa_r(buf, in);
22 }
23
24 /** Convert an IP address to printable ASCII form.
25 * @param[out] buf Output buffer to write to.
26 * @param[in] in Address to format.
27 * @return Pointer to the output buffer \a buf.
28 */
29 const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* in)
30 {
31 assert(buf != NULL);
32 assert(in != NULL);
33
34 if (irc_in_addr_is_ipv4(in)) {
35 unsigned char *pch;
36
37 pch = (unsigned char*)&in->in6_16[6];
38 sprintf(buf,"%d.%d.%d.%d",pch[0],pch[1],pch[2],pch[3]);
39 return buf;
40 } else {
41 unsigned int pos, part, max_start, max_zeros, curr_zeros, ii;
42
43 /* Find longest run of zeros. */
44 for (max_start = ii = 1, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
45 if (!in->in6_16[ii])
46 curr_zeros++;
47 else if (curr_zeros > max_zeros) {
48 max_start = ii - curr_zeros;
49 max_zeros = curr_zeros;
50 curr_zeros = 0;
51 }
52 }
53 if (curr_zeros > max_zeros) {
54 max_start = ii - curr_zeros;
55 max_zeros = curr_zeros;
56 }
57
58 /* Print out address. */
59 /** Append \a CH to the output buffer. */
60 #define APPEND(CH) do { buf[pos++] = (CH); } while (0)
61 for (pos = ii = 0; (ii < 8); ++ii) {
62 if ((max_zeros > 0) && (ii == max_start)) {
63 APPEND(':');
64 ii += max_zeros - 1;
65 continue;
66 }
67 part = ntohs(in->in6_16[ii]);
68 pos+=sprintf(buf+pos,"%x",part);
69 if (ii < 7)
70 APPEND(':');
71 }
72 #undef APPEND
73
74 /* Nul terminate and return number of characters used. */
75 buf[pos++] = '\0';
76 return buf;
77 }
78 }
79
80 /** Convert a CIDR mask to printable ASCII form.
81 * This is generally deprecated in favor of ircd_ntoa_masked_r().
82 * @param[in] in Address to convert.
83 * @param[in] bits Mask bits.
84 * @return Pointer to a static buffer containing the readable form.
85 */
86 const char* ircd_ntoa_masked(const struct irc_in_addr* in, unsigned char bits)
87 {
88 static char buf[CIDRLEN];
89 return ircd_ntoa_masked_r(buf, in, bits);
90 }
91
92 /** Convert a CIDR mask to printable ASCII form.
93 * @param[out] buf Output buffer to write to.
94 * @param[in] in Address to format.
95 * @param[in] bits Mask bits.
96 * @return Pointer to the output buffer \a buf.
97 */
98 const char* ircd_ntoa_masked_r(char* buf, const struct irc_in_addr* in, unsigned char bits)
99 {
100 char inname[SOCKIPLEN];
101 struct irc_in_addr intemp;
102 int i;
103
104 for(i=0;i<8;i++) {
105 int curbits = bits - i * 16;
106
107 if (curbits<0)
108 curbits = 0;
109 else if (curbits>16)
110 curbits = 16;
111
112 uint16_t mask = 0xffff & ~((1 << (16 - curbits)) - 1);
113 intemp.in6_16[i] = htons(ntohs(in->in6_16[i]) & mask);
114 }
115
116 ircd_ntoa_r(inname, &intemp);
117 sprintf(buf, "%s/%u", inname, irc_bitlen(in, bits));
118
119 return buf;
120 }
121
122 /** Attempt to parse an IPv4 address into a network-endian form.
123 * @param[in] input Input string.
124 * @param[out] output Network-endian representation of the address.
125 * @param[out] pbits Number of bits found in pbits.
126 * @return Number of characters used from \a input, or 0 if the parse failed.
127 */
128 static unsigned int
129 ircd_aton_ip4(const char *input, unsigned int *output, unsigned char *pbits)
130 {
131 unsigned int dots = 0, pos = 0, part = 0, ip = 0, bits;
132
133 /* Intentionally no support for bizarre IPv4 formats (plain
134 * integers, octal or hex components) -- only vanilla dotted
135 * decimal quads.
136 */
137 if (input[0] == '.')
138 return 0;
139 bits = 32;
140 while (1) switch (input[pos]) {
141 case '\0':
142 if (dots < 3)
143 return 0;
144 out:
145 ip |= part << (24 - 8 * dots);
146 *output = htonl(ip);
147 if (pbits)
148 *pbits = bits;
149 return pos;
150 case '.':
151 if (++dots > 3)
152 return 0;
153 if (input[++pos] == '.')
154 return 0;
155 ip |= part << (32 - 8 * dots);
156 part = 0;
157 if (input[pos] == '*') {
158 while (input[++pos] == '*' || input[pos] == '.') ;
159 if (input[pos] != '\0')
160 return 0;
161 if (pbits)
162 *pbits = dots * 8;
163 *output = htonl(ip);
164 return pos;
165 }
166 break;
167 case '/':
168 if (!pbits || !IsDigit(input[pos + 1]))
169 return 0;
170 for (bits = 0; IsDigit(input[++pos]); )
171 bits = bits * 10 + input[pos] - '0';
172 if (bits > 32)
173 return 0;
174 goto out;
175 case '0': case '1': case '2': case '3': case '4':
176 case '5': case '6': case '7': case '8': case '9':
177 part = part * 10 + input[pos++] - '0';
178 if (part > 255)
179 return 0;
180 break;
181 default:
182 return 0;
183 }
184 }
185
186 /** Parse a numeric IPv4 or IPv6 address into an irc_in_addr.
187 * @param[in] input Input buffer.
188 * @param[out] ip Receives parsed IP address.
189 * @param[out] pbits If non-NULL, receives number of bits specified in address mask.
190 * @return Number of characters used from \a input, or 0 if the
191 * address was unparseable or malformed.
192 */
193 int
194 ipmask_parse(const char *input, struct irc_in_addr *ip, unsigned char *pbits)
195 {
196 char *colon;
197 char *dot;
198
199 assert(ip);
200 assert(input);
201 memset(ip, 0, sizeof(*ip));
202 colon = strchr(input, ':');
203 dot = strchr(input, '.');
204
205 if (colon && (!dot || (dot > colon))) {
206 unsigned int part = 0, pos = 0, ii = 0, colon = 8;
207 const char *part_start = NULL;
208
209 /* Parse IPv6, possibly like ::127.0.0.1.
210 * This is pretty straightforward; the only trick is borrowed
211 * from Paul Vixie (BIND): when it sees a "::" continue as if
212 * it were a single ":", but note where it happened, and fill
213 * with zeros afterward.
214 */
215 if (input[pos] == ':') {
216 if ((input[pos+1] != ':') || (input[pos+2] == ':'))
217 return 0;
218 colon = 0;
219 pos += 2;
220 part_start = input + pos;
221 }
222 while (ii < 8) switch (input[pos]) {
223 unsigned char chval;
224 case '0': case '1': case '2': case '3': case '4':
225 case '5': case '6': case '7': case '8': case '9':
226 chval = input[pos] - '0';
227 use_chval:
228 part = (part << 4) | chval;
229 if (part > 0xffff)
230 return 0;
231 pos++;
232 break;
233 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
234 chval = input[pos] - 'A' + 10;
235 goto use_chval;
236 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
237 chval = input[pos] - 'a' + 10;
238 goto use_chval;
239 case ':':
240 part_start = input + ++pos;
241 if (input[pos] == '.')
242 return 0;
243 ip->in6_16[ii++] = htons(part);
244 part = 0;
245 if (input[pos] == ':') {
246 if (colon < 8)
247 return 0;
248 colon = ii;
249 pos++;
250 }
251 break;
252 case '.': {
253 uint32_t ip4;
254 unsigned int len;
255 len = ircd_aton_ip4(part_start, &ip4, pbits);
256 if (!len || (ii > 6))
257 return 0;
258 ip->in6_16[ii++] = htons(ntohl(ip4) >> 16);
259 ip->in6_16[ii++] = htons(ntohl(ip4) & 65535);
260 if (pbits)
261 *pbits += 96;
262 pos = part_start + len - input;
263 goto finish;
264 }
265 case '/':
266 if (!pbits || !IsDigit(input[pos + 1]))
267 return 0;
268 ip->in6_16[ii++] = htons(part);
269 for (part = 0; IsDigit(input[++pos]); )
270 part = part * 10 + input[pos] - '0';
271 if (part > 128)
272 return 0;
273 *pbits = part;
274 goto finish;
275 case '*':
276 while (input[++pos] == '*' || input[pos] == ':') ;
277 if (input[pos] != '\0' || colon < 8)
278 return 0;
279 if (pbits)
280 *pbits = ii * 16;
281 return pos;
282 case '\0':
283 ip->in6_16[ii++] = htons(part);
284 if (colon == 8 && ii < 8)
285 return 0;
286 if (pbits)
287 *pbits = 128;
288 goto finish;
289 default:
290 return 0;
291 }
292 if (input[pos] != '\0')
293 return 0;
294 finish:
295 if (colon < 8) {
296 unsigned int jj;
297 /* Shift stuff after "::" up and fill middle with zeros. */
298 for (jj = 0; jj < ii - colon; jj++)
299 ip->in6_16[7 - jj] = ip->in6_16[ii - jj - 1];
300 for (jj = 0; jj < 8 - ii; jj++)
301 ip->in6_16[colon + jj] = 0;
302 }
303 return pos;
304 } else if (dot || strchr(input, '/')) {
305 unsigned int addr;
306 int len = ircd_aton_ip4(input, &addr, pbits);
307 if (len) {
308 ip->in6_16[5] = htons(65535);
309 ip->in6_16[6] = htons(ntohl(addr) >> 16);
310 ip->in6_16[7] = htons(ntohl(addr) & 65535);
311 if (pbits)
312 *pbits += 96;
313 }
314 return len;
315 } else if (input[0] == '*') {
316 unsigned int pos = 0;
317 while (input[++pos] == '*') ;
318 if (input[pos] != '\0')
319 return 0;
320 if (pbits)
321 *pbits = 0;
322 return pos;
323 } else return 0; /* parse failed */
324 }
325
326 /* from numnicks.c */
327
328 /**
329 * Converts a numeric to the corresponding character.
330 * The following characters are currently known to be forbidden:
331 *
332 * '\\0' : Because we use '\\0' as end of line.
333 *
334 * ' ' : Because parse_*() uses this as parameter separator.
335 *
336 * ':' : Because parse_server() uses this to detect if a prefix is a
337 * numeric or a name.
338 *
339 * '+' : Because m_nick() uses this to determine if parv[6] is a
340 * umode or not.
341 *
342 * '&', '#', '$', '@' and '%' :
343 * Because m_message() matches these characters to detect special cases.
344 */
345 static const char convert2y[] = {
346 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
347 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
348 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
349 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']'
350 };
351
352 /** Converts a character to its (base64) numnick value. */
353 static const unsigned int convert2n[] = {
354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
358 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
359 15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
360 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
361 41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0,
362
363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
371 };
372
373 /** Number of bits encoded in one numnick character. */
374 #define NUMNICKLOG 6
375 /** Bitmask to select value of next numnick character. */
376 #define NUMNICKMASK 63 /* (NUMNICKBASE-1) */
377 /** Number of servers representable in a numnick. */
378
379 /* *INDENT-ON* */
380
381 /** Convert a string to its value as a numnick.
382 * @param[in] s Numnick string to decode.
383 * @return %Numeric nickname value.
384 */
385 unsigned int base64toint(const char* s)
386 {
387 unsigned int i = convert2n[(unsigned char) *s++];
388 while (*s) {
389 i <<= NUMNICKLOG;
390 i += convert2n[(unsigned char) *s++];
391 }
392 return i;
393 }
394
395 /** Encode a number as a numnick.
396 * @param[out] buf Output buffer.
397 * @param[in] v Value to encode.
398 * @param[in] count Number of numnick digits to write to \a buf.
399 */
400 const char* inttobase64(char* buf, unsigned int v, unsigned int count)
401 {
402 buf[count] = '\0';
403 while (count > 0) {
404 buf[--count] = convert2y[(v & NUMNICKMASK)];
405 v >>= NUMNICKLOG;
406 }
407 return buf;
408 }
409
410 /** Number of bits encoded in one numnick character. */
411 #define NUMNICKLOG 6
412
413 /** Encode an IP address in the base64 used by numnicks.
414 * For IPv4 addresses (including IPv4-mapped and IPv4-compatible IPv6
415 * addresses), the 32-bit host address is encoded directly as six
416 * characters.
417 *
418 * For IPv6 addresses, each 16-bit address segment is encoded as three
419 * characters, but the longest run of zero segments is encoded using an
420 * underscore.
421 * @param[out] buf Output buffer to write to.
422 * @param[in] addr IP address to encode.
423 * @param[in] count Number of bytes writable to \a buf.
424 * @param[in] v6_ok If non-zero, peer understands base-64 encoded IPv6 addresses.
425 */
426 const char* iptobase64(char* buf, const struct irc_in_addr* addr, unsigned int count, int v6_ok)
427 {
428 if (irc_in_addr_is_ipv4(addr)) {
429 assert(count >= 6);
430 inttobase64(buf, (ntohs(addr->in6_16[6]) << 16) | ntohs(addr->in6_16[7]), 6);
431 } else if (!v6_ok) {
432 assert(count >= 6);
433 if (addr->in6_16[0] == htons(0x2002))
434 inttobase64(buf, (ntohs(addr->in6_16[1]) << 16) | ntohs(addr->in6_16[2]), 6);
435 else
436 strcpy(buf, "AAAAAA");
437 } else {
438 unsigned int max_start, max_zeros, curr_zeros, zero, ii;
439 char *output = buf;
440
441 assert(count >= 25);
442 /* Can start by printing out the leading non-zero parts. */
443 for (ii = 0; (addr->in6_16[ii]) && (ii < 8); ++ii) {
444 inttobase64(output, ntohs(addr->in6_16[ii]), 3);
445 output += 3;
446 }
447 /* Find the longest run of zeros. */
448 for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
449 if (!addr->in6_16[ii])
450 curr_zeros++;
451 else if (curr_zeros > max_zeros) {
452 max_start = ii - curr_zeros;
453 max_zeros = curr_zeros;
454 curr_zeros = 0;
455 }
456 }
457 if (curr_zeros > max_zeros) {
458 max_start = ii - curr_zeros;
459 max_zeros = curr_zeros;
460 }
461 /* Print the rest of the address */
462 for (ii = zero; ii < 8; ) {
463 if ((ii == max_start) && max_zeros) {
464 *output++ = '_';
465 ii += max_zeros;
466 } else {
467 inttobase64(output, ntohs(addr->in6_16[ii]), 3);
468 output += 3;
469 ii++;
470 }
471 }
472 *output = '\0';
473 }
474 return buf;
475 }
476
477 /** Decode an IP address from base64.
478 * @param[in] input Input buffer to decode.
479 * @param[out] addr IP address structure to populate.
480 */
481 void base64toip(const char* input, struct irc_in_addr* addr)
482 {
483 memset(addr, 0, sizeof(*addr));
484 if (strlen(input) == 6) {
485 unsigned int in = base64toint(input);
486 /* An all-zero address should stay that way. */
487 if (in) {
488 addr->in6_16[5] = htons(65535);
489 addr->in6_16[6] = htons(in >> 16);
490 addr->in6_16[7] = htons(in & 65535);
491 }
492 } else {
493 unsigned int pos = 0;
494 do {
495 if (*input == '_') {
496 unsigned int left;
497 for (left = (25 - strlen(input)) / 3 - pos; left; left--)
498 addr->in6_16[pos++] = 0;
499 input++;
500 } else {
501 unsigned short accum = convert2n[(unsigned char)*input++];
502 accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++];
503 accum = (accum << NUMNICKLOG) | convert2n[(unsigned char)*input++];
504 addr->in6_16[pos++] = ntohs(accum);
505 }
506 } while (pos < 8);
507 }
508 }
509
510 /** Test whether an address matches the most significant bits of a mask.
511 * @param[in] addr Address to test.
512 * @param[in] mask Address to test against.
513 * @param[in] bits Number of bits to test.
514 * @return 0 on mismatch, 1 if bits < 128 and all bits match; -1 if
515 * bits == 128 and all bits match.
516 */
517 int ipmask_check(const struct irc_in_addr *addr, const struct irc_in_addr *mask, unsigned char bits)
518 {
519 int k;
520
521 for (k = 0; k < 8; k++) {
522 if (bits < 16)
523 return !(htons(addr->in6_16[k] ^ mask->in6_16[k]) >> (16-bits));
524 if (addr->in6_16[k] != mask->in6_16[k])
525 return 0;
526 if (!(bits -= 16))
527 return 1;
528 }
529 return -1;
530 }
531
532 /** Convert IP addresses to canonical form for comparison. 6to4 and Teredo addresses
533 * are converted to IPv4 addresses. All other addresses are left alone.
534 * @param[out] out Receives canonical format for address.
535 * @param[in] in IP address to canonicalize.
536 */
537 void ip_canonicalize_tunnel(struct irc_in_addr *out, const struct irc_in_addr *in)
538 {
539 if (in->in6_16[0] == htons(0x2002)) { /* 6to4 */
540 out->in6_16[0] = out->in6_16[1] = out->in6_16[2] = 0;
541 out->in6_16[3] = out->in6_16[4] = 0;
542 out->in6_16[5] = 0xffff;
543 out->in6_16[6] = in->in6_16[1];
544 out->in6_16[7] = in->in6_16[2];
545 } else if(in->in6_16[0] == htons(0x2001) && in->in6_16[1] == 0) { /* Teredo */
546 out->in6_16[0] = out->in6_16[1] = out->in6_16[2] = 0;
547 out->in6_16[3] = out->in6_16[4] = 0;
548 out->in6_16[5] = 0xffff;
549 out->in6_16[6] = ~(in->in6_16[6]);
550 out->in6_16[7] = ~(in->in6_16[7]);
551 } else
552 memcpy(out, in, sizeof(*out));
553 }
554