2 * Copyright (c) 2015-2019 Alexandre Fenyo <alex@fenyo.net> - http://www.fenyo.net
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/socket.h>
30 #include <sys/ctype.h>
33 #include <net/ethernet.h>
34 #include <netinet/in.h>
35 #include <netinet6/scope6_var.h>
37 #if (__FreeBSD_version < 1100000)
38 #include <netinet6/in6_var.h>
44 static const char hexdigits[] = "0123456789abcdef";
45 static int digit2int(const char digit) {
46 return strchr(hexdigits, digit) - hexdigits;
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]));
61 // This IPv6 address parser handles any valid textual representation according to RFC-4291 and RFC-5952.
62 // Other representations will return -1.
64 // note that str input parameter has been modified when the function call returns
66 // parse_ipv6(char *str, struct in6_addr *retaddr)
67 // parse textual representation of IPv6 addresses
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;
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;
80 // convert transitional to standard textual representation
81 if (strchr(str, '.')) {
83 char *curp = strrchr(str, ':');
84 if (curp == NULL) return -1;
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;
97 sprintf(curp, "%x%02x:%x%02x", ipv4bytes[0], ipv4bytes[1], ipv4bytes[2], ipv4bytes[3]);
100 // parse standard textual representation
102 if ((delim = strchr(_str, ':')) == _str || (delim == NULL && !strlen(_str))) {
103 if (delim == str) _str++;
104 else if (delim == NULL) return 0;
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;
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;
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]);
124 *(_retaddr++) = (digit2int(hexnum[0]) << 4) + digit2int(hexnum[1]);
125 *(_retaddr++) = (digit2int(hexnum[2]) << 4) + digit2int(hexnum[3]);
127 } while (_str < str + strlen(str));
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];
135 if (clear_scope) in6_clearscope(&tmpaddr);
136 ip6_sprintf(addrstr, &tmpaddr);
137 addrstr[INET6_ADDRSTRLEN] = 0;
138 printf("%s", addrstr);
141 void printf_ip6addr_network_format(const struct in6_addr *addrp) {
142 struct in6_addr tmpaddr = *addrp;
144 in6_clearscope(&tmpaddr);
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(":");
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);