9b8801fc2c14e947badfb6914f00c9424e74c5c0
[oonf.git] / src / common / netaddr.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2011, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <ctype.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include "common/common_types.h"
48 #include "common/string.h"
49 #include "common/netaddr.h"
50
51 static char *_mac_to_string(char *dst, const void *bin, size_t dst_size,
52     size_t bin_size, char separator);
53 static int _mac_from_string(void *bin, size_t bin_size,
54     const char *src, char separator);
55 static int _subnetmask_to_prefixlen(const char *src);
56 static int _read_hexdigit(const char c);
57 static bool _binary_is_in_subnet(const struct netaddr *subnet,
58     const void *bin);
59
60 const struct netaddr NETADDR_IPV4_ANY = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, AF_INET, 0 };
61 const struct netaddr NETADDR_IPV6_ANY = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, AF_INET6, 0 };
62
63 /**
64  * Read the binary representation of an address into a netaddr object
65  * @param dst pointer to netaddr object
66  * @param binary source pointer
67  * @param len length of source buffer
68  * @param addr_type address type of source
69  * @return 0 if successful read binary data, -1 otherwise
70  */
71 int
72 netaddr_from_binary(struct netaddr *dst, const void *binary,
73     size_t len, uint8_t addr_type) {
74   memset(dst->addr, 0, sizeof(dst->addr));
75   if (addr_type == AF_INET && len >= 4) {
76     /* ipv4 */
77     memcpy(dst->addr, binary, 4);
78     dst->prefix_len = 32;
79   }
80   else if (addr_type == AF_INET6 && len >= 16){
81     /* ipv6 */
82     memcpy(dst->addr, binary, 16);
83     dst->prefix_len = 128;
84   }
85   else if (addr_type == AF_MAC48 && len >= 6) {
86     /* mac48 */
87     memcpy(&dst->addr, binary, 6);
88     dst->prefix_len = 48;
89   }
90   else if (addr_type == AF_EUI64 && len >= 8) {
91     /* eui 64 */
92     memcpy(dst->addr, binary, 8);
93     dst->prefix_len = 64;
94   }
95   else {
96     /* unknown address type */
97     return -1;
98   }
99
100   /* copy address type */
101   dst->type = addr_type;
102
103   return 0;
104 }
105
106 /**
107  * Writes a netaddr object into a binary buffer
108  * @param dst binary buffer
109  * @param src netaddr source
110  * @param len length of destination buffer
111  * @return 0 if successful read binary data, -1 otherwise
112  */
113 int
114 netaddr_to_binary(void *dst, const struct netaddr *src, size_t len) {
115   if (src->type == AF_INET && len >= 4) {
116     /* ipv4 */
117     memcpy(dst, src->addr, 4);
118   }
119   else if (src->type == AF_INET6 && len >= 16) {
120     /* ipv6 */
121     memcpy(dst, src->addr, 16);
122   }
123   else if (src->type == AF_MAC48 && len >= 6) {
124     /* 48 bit MAC address */
125     memcpy(dst, src->addr, 6);
126   }
127   else if (src->type == AF_EUI64 && len >= 8) {
128     /* 64 bit EUI */
129     memcpy(dst, src->addr, 8);
130   }
131   else {
132     /* unknown address type */
133     return -1;
134   }
135   return 0;
136 }
137
138 /**
139  * Reads the address and address-type part of an
140  * netaddr_socket into a netaddr object
141  * @param dst netaddr object
142  * @param src netaddr_socket source
143  * @return 0 if successful read binary data, -1 otherwise
144  */
145 int
146 netaddr_from_socket(struct netaddr *dst, const union netaddr_socket *src) {
147   memset(dst->addr, 0, sizeof(dst->addr));
148   if (src->std.sa_family == AF_INET) {
149     /* ipv4 */
150     memcpy(dst->addr, &src->v4.sin_addr, 4);
151     dst->prefix_len = 32;
152   }
153   else if (src->std.sa_family == AF_INET6){
154     /* ipv6 */
155     memcpy(dst->addr, &src->v6.sin6_addr, 16);
156     dst->prefix_len = 128;
157   }
158   else {
159     /* unknown address type */
160     return -1;
161   }
162   dst->type = (uint8_t)src->std.sa_family;
163   return 0;
164 }
165
166 /**
167  * Writes the address and address-type of a netaddr object
168  * into a netaddr_socket.
169  * @param dst pointer to netaddr_socket
170  * @param src netaddr source
171  * @return 0 if successful read binary data, -1 otherwise
172  */
173 int
174 netaddr_to_socket(union netaddr_socket *dst, const struct netaddr *src) {
175   /* copy address type */
176   dst->std.sa_family = src->type;
177
178   if (src->type == AF_INET) {
179     /* ipv4 */
180     memcpy(&dst->v4.sin_addr, src->addr, 4);
181   }
182   else if (src->type == AF_INET6) {
183     /* ipv6 */
184     memcpy(&dst->v6.sin6_addr, src->addr, 16);
185   }
186   else {
187     /* unknown address type */
188     return -1;
189   }
190
191   /* copy address type */
192   dst->std.sa_family= src->type;
193   return 0;
194 }
195
196
197 int
198 netaddr_to_autobuf(struct autobuf *abuf, const struct netaddr *src) {
199   switch (src->type) {
200     case AF_INET:
201       /* ipv4 */
202       return abuf_memcpy(abuf, src->addr, 4);
203
204     case AF_INET6:
205       /* ipv6 */
206       return abuf_memcpy(abuf, src->addr, 16);
207
208     case AF_MAC48:
209       /* 48 bit MAC address */
210       return abuf_memcpy(abuf, src->addr, 6);
211
212     case AF_EUI64:
213       /* 64 bit EUI */
214       return abuf_memcpy(abuf, src->addr, 8);
215
216     default:
217       /* unknown address type */
218       return -1;
219   }
220 }
221
222 /**
223  * Creates a host address from a netmask and a host number part. This function
224  * will copy the netmask and then overwrite the bits after the prefix length
225  * with the one from the host number.
226  * @param host target buffer
227  * @param netmask prefix of result
228  * @param number postfix of result
229  * @param num_length length of the postfix in bytes
230  * @return -1 if an error happened, 0 otherwise
231  */
232 int
233 netaddr_create_host_bin(struct netaddr *host, const struct netaddr *netmask,
234     const void *number, size_t num_length) {
235   size_t host_index, number_index;
236   uint8_t host_part_length;
237   const uint8_t *number_byte;
238   uint8_t mask;
239
240   number_byte = number;
241
242   /* copy netmask with prefixlength max */
243   memcpy(host, netmask, sizeof(*netmask));
244   host->prefix_len = netaddr_get_maxprefix(host);
245
246   /* unknown address type */
247   if (host->prefix_len == 0) {
248     return -1;
249   }
250
251   /* netmask has no host part */
252   if (host->prefix_len == netmask->prefix_len || num_length == 0) {
253     return 0;
254   }
255
256   /* calculate starting byte in host and number */
257   host_part_length = (host->prefix_len - netmask->prefix_len + 7)/8;
258   if (host_part_length > num_length) {
259     host_index = host->prefix_len/8 - num_length;
260     number_index = 0;
261   }
262   else {
263     host_index = netmask->prefix_len / 8;
264     number_index = num_length - host_part_length;
265
266     /* copy bit masked part */
267     if ((netmask->prefix_len & 7) != 0) {
268       mask = (255 >> (netmask->prefix_len & 7));
269       host->addr[host_index] &= (~mask);
270       host->addr[host_index] |= (number_byte[number_index++]) & mask;
271       host_index++;
272     }
273   }
274
275   /* copy bytes */
276   memcpy(&host->addr[host_index], &number_byte[number_index], num_length - number_index);
277   return 0;
278 }
279
280 /**
281  * Initialize a netaddr_socket with a netaddr and a port number
282  * @param combined pointer to netaddr_socket to be initialized
283  * @param addr pointer to netaddr source
284  * @param port port number for socket
285  * @return 0 if successful read binary data, -1 otherwise
286  */
287 int
288 netaddr_socket_init(union netaddr_socket *combined, const struct netaddr *addr, uint16_t port) {
289   /* initialize memory block */
290   memset(combined, 0, sizeof(*combined));
291
292   if (addr->type == AF_INET) {
293     /* ipv4 */
294     memcpy(&combined->v4.sin_addr, addr->addr, 4);
295     combined->v4.sin_port = htons(port);
296   }
297   else if (addr->type == AF_INET6) {
298     /* ipv6 */
299     memcpy(&combined->v6.sin6_addr, addr->addr, 16);
300     combined->v6.sin6_port = htons(port);
301   }
302   else {
303     /* unknown address type */
304     return -1;
305   }
306
307   /* copy address type */
308   combined->std.sa_family = addr->type;
309   return 0;
310 }
311
312 /**
313  * @param sock pointer to netaddr_socket
314  * @return port of socket
315  */
316 uint16_t
317 netaddr_socket_get_port(const union netaddr_socket *sock) {
318   switch (sock->std.sa_family) {
319     case AF_INET:
320       return ntohs(sock->v4.sin_port);
321     case AF_INET6:
322       return ntohs(sock->v6.sin6_port);
323     default:
324       return 0;
325   }
326 }
327
328 /**
329  * Converts a netaddr into a string
330  * @param dst target string buffer
331  * @param src netaddr source
332  * @param forceprefix true if a prefix should be appended even with maximum
333  *   prefix length, false if only shorter prefixes should be appended
334  * @return pointer to target buffer, NULL if an error happened
335  */
336 const char *
337 netaddr_to_prefixstring(struct netaddr_str *dst,
338     const struct netaddr *src, bool forceprefix) {
339   const char *result = NULL;
340   int maxprefix;
341
342   if (src->type == AF_INET) {
343     result = inet_ntop(AF_INET, src->addr, dst->buf, sizeof(*dst));
344     maxprefix = 32;
345   }
346   else if (src->type == AF_INET6) {
347     result = inet_ntop(AF_INET6, src->addr, dst->buf, sizeof(*dst));
348     maxprefix = 128;
349   }
350   else if (src->type == AF_MAC48) {
351     result = _mac_to_string(dst->buf, src->addr, sizeof(*dst), 6, ':');
352     maxprefix = 48;
353   }
354   else if (src->type == AF_EUI64) {
355     result = _mac_to_string(dst->buf, src->addr, sizeof(*dst), 8, '-');
356     maxprefix = 64;
357   }
358
359   if (result != NULL && (forceprefix || src->prefix_len < maxprefix)) {
360     /* append prefix */
361     snprintf(dst->buf + strlen(result), 5, "/%d", src->prefix_len);
362   }
363   return result;
364 }
365
366 /**
367  * Generates a netaddr from a string.
368  * @param dst pointer to netaddr object
369  * @param src pointer to input string
370  * @return -1 if an error happened because of an unknown string,
371  *   0 otherwise
372  */
373 int
374 netaddr_from_string(struct netaddr *dst, const char *src) {
375   struct netaddr_str buf;
376   unsigned int colon_count, minus_count;
377   int result;
378   int prefix_len;
379   bool has_coloncolon, has_point;
380   bool last_was_colon;
381   char *ptr1, *ptr2, *ptr3;
382
383   colon_count = 0;
384   minus_count = 0;
385   has_coloncolon = false;
386   has_point = false;
387
388   last_was_colon = false;
389
390   result = -1;
391   prefix_len = -1;
392
393   /* copy input string in temporary buffer */
394   strscpy(buf.buf, src, sizeof(buf));
395   ptr1 = buf.buf;
396
397   ptr1 = str_trim(ptr1);
398
399   ptr2 = ptr1;
400   while (*ptr2 != 0 && !isspace(*ptr2) && *ptr2 != '/') {
401     switch (*ptr2) {
402       case ':':
403         if (last_was_colon) {
404           has_coloncolon = true;
405         }
406         colon_count++;
407         break;
408
409       case '.':
410         has_point = true;
411         break;
412
413       case '-':
414         minus_count++;
415         break;
416
417       default:
418         break;
419     }
420     last_was_colon = *ptr2++ == ':';
421   }
422
423   memset(dst, 0, sizeof(*dst));
424   if (*ptr2) {
425     /* split strings */
426     while (isspace(*ptr2)) *ptr2++ = 0;
427     if (*ptr2 == '/') {
428       *ptr2++ = 0;
429     }
430     while (isspace(*ptr2)) *ptr2++ = 0;
431
432     if (*ptr2 == 0) {
433       /* prefixlength is missing */
434       return -1;
435     }
436
437     /* try to read numeric prefix length */
438     prefix_len = (int)strtoul(ptr2, &ptr3, 10);
439     if (ptr3 && *ptr3) {
440       /* not a numeric prefix length */
441       prefix_len = -1;
442     }
443   }
444
445   /* use dst->prefix_len as storage for maximum prefixlen */
446   if ((colon_count == 5 || minus_count == 5)
447       && (colon_count == 0 || minus_count == 0)
448       && !has_point && !has_coloncolon) {
449     dst->type = AF_MAC48;
450     dst->prefix_len = 48;
451     if (colon_count > 0) {
452       result = _mac_from_string(dst->addr, 6, ptr1, ':');
453     }
454     else {
455       result = _mac_from_string(dst->addr, 6, ptr1, '-');
456     }
457   }
458   else if (colon_count == 0 && !has_point && minus_count == 7) {
459     dst->type = AF_EUI64;
460     dst->prefix_len = 64;
461     dst->addr[7] = 2;
462     result = _mac_from_string(dst->addr, 8, ptr1, '-');
463   }
464   else if (colon_count == 0 && has_point && minus_count == 0) {
465     dst->type = AF_INET;
466     dst->prefix_len = 32;
467     result = inet_pton(AF_INET, ptr1, dst->addr) == 1 ? 0 : -1;
468
469     if (result == 0 && *ptr2 && prefix_len == -1) {
470       /* we need a prefix length, but its not a numerical one */
471       prefix_len = _subnetmask_to_prefixlen(ptr2);
472     }
473   }
474   else if ((has_coloncolon || colon_count == 7) && minus_count == 0) {
475     dst->type = AF_INET6;
476     dst->prefix_len = 128;
477     result = inet_pton(AF_INET6, ptr1, dst->addr) == 1 ? 0 : -1;
478   }
479
480   /* stop if an error happened */
481   if (result) {
482     return -1;
483   }
484
485   if (*ptr2) {
486     if (prefix_len < 0 || prefix_len > dst->prefix_len) {
487       /* prefix is too long */
488       return -1;
489     }
490
491     /* store real prefix length */
492     dst->prefix_len = (uint8_t)prefix_len;
493   }
494   return result;
495 }
496
497 /**
498  * Converts a netaddr_socket into a string
499  * @param dst target string buffer
500  * @param src netaddr_socket source
501  * @return pointer to target buffer, NULL if an error happened
502  */
503 const char *
504 netaddr_socket_to_string(struct netaddr_str *dst, const union netaddr_socket *src) {
505   struct netaddr_str buf;
506
507   if (src->std.sa_family == AF_INET) {
508     snprintf(dst->buf, sizeof(*dst), "%s:%d",
509         inet_ntop(AF_INET, &src->v4.sin_addr, buf.buf, sizeof(buf)),
510         ntohs(src->v4.sin_port));
511   }
512   else if (src->std.sa_family == AF_INET6) {
513     snprintf(dst->buf, sizeof(*dst), "[%s]:%d",
514         inet_ntop(AF_INET6, &src->v6.sin6_addr, buf.buf, sizeof(buf)),
515         ntohs(src->v6.sin6_port));
516   }
517   else {
518     /* unknown address type */
519     return NULL;
520   }
521
522   return dst->buf;
523 }
524
525 /**
526  * Compares two addresses in network byte order.
527  * Address type will be compared last.
528  *
529  * This function is compatible with the avl comparator
530  * prototype.
531  * @param k1 address 1
532  * @param k2 address 2
533  * @param unused not used in this comparator
534  * @return >0 if k1>k2, <0 if k1<k2, 0 otherwise
535  */
536 int
537 netaddr_avlcmp(const void *k1, const void *k2, void *unused __attribute__((unused))) {
538   return netaddr_cmp(k1, k2);
539 }
540
541 /**
542  * Compares an netaddr object with the address part of
543  * a netaddr_socket.
544  * @param a1 address
545  * @param a2 socket
546  * @return >0 if k1>k2, <0 if k1<k2, 0 otherwise
547  */
548 int
549 netaddr_cmp_to_socket(const struct netaddr *a1, const union netaddr_socket *a2) {
550   int result = 0;
551
552   result = (int)a1->type - (int)a2->std.sa_family;
553   if (result) {
554     return result;
555   }
556
557   if (a1->type == AF_INET) {
558     result = memcmp(a1->addr, &a2->v4.sin_addr, 4);
559   }
560   else if (a1->type == AF_INET6) {
561     /* ipv6 */
562     result = memcmp(a1->addr, &a2->v6.sin6_addr, 16);
563   }
564
565   if (result) {
566     return result;
567   }
568
569   return (int)a1->prefix_len - (a1->type == AF_INET ? 32 : 128);
570 }
571
572 /**
573  * Calculates if a binary address is equals to a netaddr one.
574  * @param addr netaddr pointer
575  * @param bin pointer to binary address
576  * @param len length of binary address
577  * @param af family of binary address
578  * @param prefix_len prefix length of binary address
579  * @return true if matches, false otherwise
580  */
581 bool
582 netaddr_isequal_binary(const struct netaddr *addr,
583     const void *bin, size_t len, uint16_t af, uint8_t prefix_len) {
584   if (addr->type != af || addr->prefix_len != prefix_len) {
585     return false;
586   }
587
588   if (af == AF_INET && len == 4) {
589     return memcmp(addr->addr, bin, 4) == 0;
590   }
591   if (af == AF_INET6 && len == 16) {
592     return memcmp(addr->addr, bin, 16) == 0;
593   }
594   if (af == AF_MAC48 && len == 6) {
595     return memcmp(addr->addr, bin, 6) == 0;
596   }
597   if (af == AF_EUI64 && len == 8) {
598     return memcmp(addr->addr, bin, 8) == 0;
599   }
600   return false;
601 }
602
603 /**
604  * Checks if a binary address is part of a netaddr prefix.
605  * @param subnet netaddr prefix
606  * @param bin pointer to binary address
607  * @param len length of binary address
608  * @param af_family address family of binary address
609  * @return true if part of the prefix, false otherwise
610  */
611 bool
612 netaddr_binary_is_in_subnet(const struct netaddr *subnet,
613     const void *bin, size_t len, uint8_t af_family) {
614   if (subnet->type != af_family
615       || netaddr_get_maxprefix(subnet) != len * 8) {
616     return false;
617   }
618   return _binary_is_in_subnet(subnet, bin);
619 }
620
621 /**
622  * Checks if a netaddr object is part of another netaddr
623  * prefix.
624  * @param subnet netaddr prefix
625  * @param addr netaddr object that might be inside the prefix
626  * @return true if addr is part of subnet, false otherwise
627  */
628 bool
629 netaddr_is_in_subnet(const struct netaddr *subnet,
630     const struct netaddr *addr) {
631   if (subnet->type != addr->type
632       || subnet->prefix_len > addr->prefix_len) {
633     return false;
634   }
635
636   return _binary_is_in_subnet(subnet, addr->addr);
637 }
638
639 /**
640  * Calculates the maximum prefix length of an address type
641  * @param addr netaddr object
642  * @return prefix length, 0 if unknown address family
643  */
644 uint8_t
645 netaddr_get_maxprefix(const struct netaddr *addr) {
646   switch (addr->type) {
647     case AF_INET:
648       return 32;
649       break;
650     case AF_INET6:
651       return 128;
652     case AF_MAC48:
653       return 48;
654       break;
655     case AF_EUI64:
656       return 64;
657       break;
658
659     default:
660       return 0;
661   }
662 }
663
664 #ifdef WIN32
665 /**
666  * Helper function for windows
667  * @param dst
668  * @param bin
669  * @param dst_size
670  * @param bin_size
671  * @param separator
672  * @return
673  */
674 const char *
675 inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
676 {
677   if (af == AF_INET) {
678     struct sockaddr_in in;
679     memset(&in, 0, sizeof(in));
680     in.sin_family = AF_INET;
681     memcpy(&in.sin_addr, src, sizeof(struct in_addr));
682     getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in),
683         dst, cnt, NULL, 0, NI_NUMERICHOST);
684     return dst;
685   }
686   else if (af == AF_INET6) {
687     struct sockaddr_in6 in;
688     memset(&in, 0, sizeof(in));
689     in.sin6_family = AF_INET6;
690     memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
691     getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6),
692         dst, cnt, NULL, 0, NI_NUMERICHOST);
693     return dst;
694   }
695   return NULL;
696 }
697
698 /**
699  * Helper function for windows
700  * @param dst
701  * @param bin
702  * @param dst_size
703  * @param bin_size
704  * @param separator
705  * @return
706  */
707 int
708 inet_pton(int af, const char *src, void *dst)
709 {
710   struct addrinfo hints, *res;
711   union netaddr_socket *sock;
712
713   if (af != AF_INET && af != AF_INET6) {
714     return -1;
715   }
716
717   memset(&hints, 0, sizeof(struct addrinfo));
718   hints.ai_family = af;
719   hints.ai_flags = AI_NUMERICHOST;
720
721   if (getaddrinfo(src, NULL, &hints, &res) != 0)
722   {
723     return -1;
724   }
725
726   if (res == NULL) {
727     return 0;
728   }
729
730   sock = (union netaddr_socket *)res->ai_addr;
731   if (af == AF_INET) {
732     memcpy(dst, &sock->v4.sin_addr, 4);
733   }
734   else {
735     memcpy(dst, &sock->v6.sin6_addr, 16);
736   }
737
738   freeaddrinfo(res);
739   return 1;
740 }
741
742 #endif
743
744 /**
745  * Converts a binary mac address into a string representation
746  * @param dst pointer to target string buffer
747  * @param bin pointer to binary source buffer
748  * @param dst_size size of string buffer
749  * @param bin_size size of binary buffer
750  * @param separator character for separating hexadecimal octets
751  * @return pointer to target buffer, NULL if an error happened
752  */
753 static char *
754 _mac_to_string(char *dst, const void *bin, size_t dst_size,
755     size_t bin_size, char separator) {
756   static const char hex[] = "0123456789abcdef";
757   char *last_separator, *_dst;
758   const uint8_t *_bin;
759
760   _bin = bin;
761   _dst = dst;
762   last_separator = dst;
763
764   if (dst_size == 0) {
765     return NULL;
766   }
767
768   while (bin_size > 0 && dst_size >= 3) {
769     *_dst++ = hex[(*_bin) >> 4];
770     *_dst++ = hex[(*_bin) & 15];
771
772     /* copy pointer to separator */
773     last_separator = _dst;
774
775     /* write separator */
776     *_dst++ = separator;
777
778     /* advance source pointer and decrease remaining length of buffer*/
779     _bin++;
780     bin_size--;
781
782     /* calculate remaining destination size */
783     dst_size-=3;
784   }
785
786   *last_separator = 0;
787   return dst;
788 }
789
790 /**
791  * Convert a string mac address into a binary representation
792  * @param bin pointer to target binary buffer
793  * @param bin_size pointer to size of target buffer
794  * @param src pointer to source string
795  * @param separator character used to separate octets in source string
796  * @return 0 if sucessfully converted, -1 otherwise
797  */
798 static int
799 _mac_from_string(void *bin, size_t bin_size, const char *src, char separator) {
800   uint8_t *_bin;
801   int num, digit_2;
802
803   _bin = bin;
804
805   while (bin_size > 0) {
806     num = _read_hexdigit(*src++);
807     if (num == -1) {
808       return -1;
809     }
810     digit_2 = _read_hexdigit(*src);
811     if (digit_2 >= 0) {
812       num = (num << 4) + digit_2;
813       src++;
814     }
815     *_bin++ = (uint8_t) num;
816
817     bin_size--;
818
819     if (*src == 0) {
820       return bin_size ? -1 : 0;
821     }
822     if (*src++ != separator) {
823       return -1;
824     }
825   }
826   return -1;
827 }
828
829 /**
830  * Reads a single hexadecimal digit
831  * @param c digit to be read
832  * @return integer value (0-15) of digit,
833  *   -1 if not a hexadecimal digit
834  */
835 static int
836 _read_hexdigit(const char c) {
837   if (c >= '0' && c <= '9') {
838     return c - '0';
839   }
840   if (c >= 'a' && c <= 'f') {
841     return c - 'a' + 10;
842   }
843   if (c >= 'A' && c <= 'F') {
844     return c - 'A' + 10;
845   }
846   return -1;
847 }
848
849 /**
850  * Converts a ipv4 subnet mask into a prefix length.
851  * @param src string representation of subnet mask
852  * @return prefix length, -1 if source was not a wellformed
853  *   subnet mask
854  */
855 static int
856 _subnetmask_to_prefixlen(const char *src) {
857   uint32_t v4, shift;
858   int len;
859
860   if (inet_pton(AF_INET, src, &v4) != 1) {
861     return -1;
862   }
863
864   /* transform into host byte order */
865   v4 = ntohl(v4);
866
867   shift = 0xffffffff;
868   for (len = 31; len >= 0; len--) {
869     if (v4 == shift) {
870       return len;
871     }
872     shift <<= 1;
873   }
874
875   /* not wellformed */
876   return -1;
877 }
878
879 /**
880  * Calculates if a binary address is part of a netaddr prefix.
881  * It will assume that the length of the binary address and its
882  * address family makes sense.
883  * @param addr netaddr prefix
884  * @param bin pointer to binary address
885  * @return true if part of the prefix, false otherwise
886  */
887 static bool
888 _binary_is_in_subnet(const struct netaddr *subnet, const void *bin) {
889   size_t byte_length, bit_length;
890   const uint8_t *_bin;
891
892   _bin = bin;
893
894   /* split prefix length into whole bytes and bit rest */
895   byte_length = subnet->prefix_len / 8;
896   bit_length = subnet->prefix_len % 8;
897
898   /* compare whole bytes */
899   if (memcmp(subnet->addr, bin, byte_length) != 0) {
900     return false;
901   }
902
903   /* compare bits if necessary */
904   if (bit_length != 0) {
905     return (subnet->addr[byte_length] >> (8 - bit_length))
906         == (_bin[byte_length] >> (8 - bit_length));
907   }
908   return true;
909 }