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