]> Sergey Matveev's repositories - ndproxy.git/blob - ndparse.c
Compatibility with FreeBSD 14
[ndproxy.git] / ndparse.c
1 /*-
2  * Copyright (c) 2015-2019 Alexandre Fenyo <alex@fenyo.net> - http://www.fenyo.net
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/socket.h>
30 #include <sys/ctype.h>
31 #include <net/if.h>
32 #include <net/pfil.h>
33 #include <net/ethernet.h>
34 #include <netinet/in.h>
35 #include <netinet6/scope6_var.h>
36
37 #if (__FreeBSD_version < 1100000)
38 #include <netinet6/in6_var.h>
39 #endif
40
41 #include "ndparse.h"
42 #include "ndconf.h"
43
44 static const char hexdigits[] = "0123456789abcdef";
45 static int digit2int(const char digit) {
46   return strchr(hexdigits, digit) - hexdigits;
47 }
48
49 // This Ethernet address parser only handles the hexadecimal representation made of 6 groups of 2 hexadecimal
50 // numbers separated by colons: "XX:XX:XX:XX:XX:XX".
51 // Other representations will return -1.
52 int parse_mac(char *str, struct ether_addr *retaddr) {
53   if (strlen(str) != MACMAXSIZE) return -1;
54   for (int i = 0; i < 6; i++) {
55     if ((i < 5 && str[3 * i + 2] != ':') || !isxdigit(str[3 * i]) || !isxdigit(str[3 * i + 1])) return -1;
56     retaddr->octet[i] = (digit2int(tolower(str[3 * i])) << 4) + digit2int(tolower(str[3 * i + 1]));
57   }
58   return 0;
59 }
60
61 // This IPv6 address parser handles any valid textual representation according to RFC-4291 and RFC-5952.
62 // Other representations will return -1.
63 //
64 // note that str input parameter has been modified when the function call returns
65 //
66 // parse_ipv6(char *str, struct in6_addr *retaddr)
67 // parse textual representation of IPv6 addresses
68 // str:     input arg
69 // retaddr: output arg
70 int parse_ipv6(char *str, struct in6_addr *retaddr) {
71   bool compressed_field_found = false;
72   unsigned char *_retaddr = (unsigned char *) retaddr;
73   char *_str = str;
74   char *delim;
75
76   bzero((void *) retaddr, sizeof(struct in6_addr));
77   if (!strlen(str) || strchr(str, ':') == NULL || (str[0] == ':' && str[1] != ':') ||
78       (strlen(str) >= 2 && str[strlen(str) - 1] == ':' && str[strlen(str) - 2] != ':')) return -1;
79
80   // convert transitional to standard textual representation
81   if (strchr(str, '.')) {
82     int ipv4bytes[4];
83     char *curp = strrchr(str, ':');
84     if (curp == NULL) return -1;
85     char *_curp = ++curp;
86     for (int i = 0; i < 4; i++) {
87       char *nextsep = strchr(_curp, '.');
88       if (_curp[0] == '0' || (i < 3 && nextsep == NULL) || (i == 3 && nextsep != NULL)) return -1;
89       if (nextsep != NULL) *nextsep = 0;
90       for (int j = 0; j < strlen(_curp); j++) if (_curp[j] < '0' || _curp[j] > '9') return -1;
91       if (strlen(_curp) > 3) return -1;
92       const long val = strtol(_curp, NULL, 10);
93       if (val < 0 || val > 255) return -1;
94       ipv4bytes[i] = val;
95       _curp = nextsep + 1;
96     }
97     sprintf(curp, "%x%02x:%x%02x", ipv4bytes[0], ipv4bytes[1], ipv4bytes[2], ipv4bytes[3]);
98   }     
99
100   // parse standard textual representation
101   do {
102     if ((delim = strchr(_str, ':')) == _str || (delim == NULL && !strlen(_str))) {
103       if (delim == str) _str++;
104       else if (delim == NULL) return 0;
105       else {
106         if (compressed_field_found == true) return -1;
107         if (delim == str + strlen(str) - 1 && _retaddr != (unsigned char *) (retaddr + 1)) return 0;
108         compressed_field_found = true;
109         _str++;
110         int cnt = 0;
111         for (char *__str = _str; *__str; ) if (*(__str++) == ':') cnt++;
112         unsigned char *__retaddr = - 2 * ++cnt + (unsigned char *) (retaddr + 1);
113         if (__retaddr <= _retaddr) return -1;
114         _retaddr = __retaddr;
115       }
116     } else {
117       char hexnum[4] = "0000";
118       if (delim == NULL) delim = str + strlen(str);
119       if (delim - _str > 4) return -1;
120       for (int i = 0; i < delim - _str; i++)
121         if (!isxdigit(_str[i])) return -1;
122         else hexnum[4 - (delim - _str) + i] = tolower(_str[i]);
123       _str = delim + 1;
124       *(_retaddr++) = (digit2int(hexnum[0]) << 4) + digit2int(hexnum[1]);
125       *(_retaddr++) = (digit2int(hexnum[2]) << 4) + digit2int(hexnum[3]);
126     }
127   } while (_str < str + strlen(str));
128   return 0;
129 }
130
131 void printf_ip6addr(const struct in6_addr *addrp, const bool clear_scope) {
132   struct in6_addr tmpaddr = *addrp;
133   char addrstr[INET6_ADDRSTRLEN + 1];
134
135   if (clear_scope) in6_clearscope(&tmpaddr);
136   ip6_sprintf(addrstr, &tmpaddr);
137   addrstr[INET6_ADDRSTRLEN] = 0;
138   printf("%s", addrstr);
139 }
140
141 void printf_ip6addr_network_format(const struct in6_addr *addrp) {
142   struct in6_addr tmpaddr = *addrp;
143
144   in6_clearscope(&tmpaddr);
145
146   //  for (int i = 0; i < 4; i++) printf("addr[%d] = %x\n", i, tmpaddr.__u6_addr.__u6_addr32[i]);
147   for (int i = 0; i < 16; i++) {
148     printf("%02X", ((const unsigned char *) addrp)[i]);
149     if (i%2 && i != 15) printf(":");
150   }
151 }
152
153 void printf_macaddr_network_format(const struct ether_addr *addrp) {
154   char addrstr[MACMAXSIZE + 1];
155   sprintf(addrstr, "%02X:%02X:%02X:%02X:%02X:%02X", addrp->octet[0], addrp->octet[1], addrp->octet[2], addrp->octet[3], addrp->octet[4], addrp->octet[5]);
156   printf("%s", addrstr);
157 }