vendor/TCPDUMP: Import libpcap 4.99.1
[dragonfly.git] / contrib / tcpdump / strtoaddr.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1996,1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #include "netdissect-stdinc.h"
23 #include <stddef.h>
24 #include <string.h>
25
26 #include "netdissect-ctype.h"
27
28 #include "strtoaddr.h"
29
30 #ifndef NS_INADDRSZ
31 #define NS_INADDRSZ     4       /* IPv4 T_A */
32 #endif
33
34 #ifndef NS_IN6ADDRSZ
35 #define NS_IN6ADDRSZ    16      /* IPv6 T_AAAA */
36 #endif
37
38 #ifndef NS_INT16SZ
39 #define NS_INT16SZ      2       /* #/bytes of data in a uint16_t */
40 #endif
41
42 /*%
43  * WARNING: Don't even consider trying to compile this on a system where
44  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
45  */
46
47 /* int
48  * strtoaddr(src, dst)
49  *      convert presentation level IPv4 address to network order binary form.
50  * return:
51  *      1 if `src' is a valid input, else 0.
52  * notice:
53  *      does not touch `dst' unless it's returning 1.
54  * author:
55  *      Paul Vixie, 1996.
56  */
57 int
58 strtoaddr(const char *src, void *dst)
59 {
60         uint32_t val;
61         u_int digit;
62         ptrdiff_t n;
63         unsigned char c;
64         u_int parts[4];
65         u_int *pp = parts;
66
67         c = *src;
68         for (;;) {
69                 /*
70                  * Collect number up to ``.''.
71                  * Values are specified as for C:
72                  * 0x=hex, 0=octal, isdigit=decimal.
73                  */
74                 if (!ND_ASCII_ISDIGIT(c))
75                         return (0);
76                 val = 0;
77                 if (c == '0') {
78                         c = *++src;
79                         if (c == 'x' || c == 'X')
80                                 return (0);
81                         else if (ND_ASCII_ISDIGIT(c) && c != '9')
82                                 return (0);
83                 }
84                 for (;;) {
85                         if (ND_ASCII_ISDIGIT(c)) {
86                                 digit = c - '0';
87                                 val = (val * 10) + digit;
88                                 c = *++src;
89                         } else
90                                 break;
91                 }
92                 if (c == '.') {
93                         /*
94                          * Internet format:
95                          *      a.b.c.d
96                          *      a.b.c   (with c treated as 16 bits)
97                          *      a.b     (with b treated as 24 bits)
98                          *      a       (with a treated as 32 bits)
99                          */
100                         if (pp >= parts + 3)
101                                 return (0);
102                         *pp++ = val;
103                         c = *++src;
104                 } else
105                         break;
106         }
107         /*
108          * Check for trailing characters.
109          */
110         if (c != '\0' && c != ' ' && c != '\t')
111                 return (0);
112         /*
113          * Find the number of parts specified.
114          * It must be 4; we only support dotted quads, we don't
115          * support shorthand.
116          */
117         n = pp - parts + 1;
118         if (n != 4)
119                 return (0);
120         /*
121          * parts[0-2] were set to the first 3 parts of the address;
122          * val was set to the 4th part.
123          *
124          * Check if any part is bigger than 255.
125          */
126         if ((parts[0] | parts[1] | parts[2] | val) > 0xff)
127                 return (0);
128         /*
129          * Add the other three parts to val.
130          */
131         val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
132         if (dst) {
133                 val = htonl(val);
134                 memcpy(dst, &val, NS_INADDRSZ);
135         }
136         return (1);
137 }
138
139 /* int
140  * strtoaddr6(src, dst)
141  *      convert presentation level IPv6 address to network order binary form.
142  * return:
143  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
144  * notice:
145  *      (1) does not touch `dst' unless it's returning 1.
146  *      (2) :: in a full address is silently ignored.
147  * credit:
148  *      inspired by Mark Andrews.
149  * author:
150  *      Paul Vixie, 1996.
151  */
152 int
153 strtoaddr6(const char *src, void *dst)
154 {
155         static const char xdigits_l[] = "0123456789abcdef",
156                           xdigits_u[] = "0123456789ABCDEF";
157         u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
158         const char *xdigits, *curtok;
159         int ch, seen_xdigits;
160         u_int val;
161
162         memset((tp = tmp), '\0', NS_IN6ADDRSZ);
163         endp = tp + NS_IN6ADDRSZ;
164         colonp = NULL;
165         /* Leading :: requires some special handling. */
166         if (*src == ':')
167                 if (*++src != ':')
168                         return (0);
169         curtok = src;
170         seen_xdigits = 0;
171         val = 0;
172         while ((ch = *src++) != '\0') {
173                 const char *pch;
174
175                 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
176                         pch = strchr((xdigits = xdigits_u), ch);
177                 if (pch != NULL) {
178                         val <<= 4;
179                         val |= (int)(pch - xdigits);
180                         if (++seen_xdigits > 4)
181                                 return (0);
182                         continue;
183                 }
184                 if (ch == ':') {
185                         curtok = src;
186                         if (!seen_xdigits) {
187                                 if (colonp)
188                                         return (0);
189                                 colonp = tp;
190                                 continue;
191                         } else if (*src == '\0')
192                                 return (0);
193                         if (tp + NS_INT16SZ > endp)
194                                 return (0);
195                         *tp++ = (u_char) (val >> 8) & 0xff;
196                         *tp++ = (u_char) val & 0xff;
197                         seen_xdigits = 0;
198                         val = 0;
199                         continue;
200                 }
201                 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
202                     strtoaddr(curtok, tp) > 0) {
203                         tp += NS_INADDRSZ;
204                         seen_xdigits = 0;
205                         break;  /*%< '\\0' was seen by strtoaddr(). */
206                 }
207                 return (0);
208         }
209         if (seen_xdigits) {
210                 if (tp + NS_INT16SZ > endp)
211                         return (0);
212                 *tp++ = (u_char) (val >> 8) & 0xff;
213                 *tp++ = (u_char) val & 0xff;
214         }
215         if (colonp != NULL) {
216                 /*
217                  * Since some memmove()'s erroneously fail to handle
218                  * overlapping regions, we'll do the shift by hand.
219                  */
220                 const ptrdiff_t n = tp - colonp;
221                 int i;
222
223                 if (tp == endp)
224                         return (0);
225                 for (i = 1; i <= n; i++) {
226                         endp[- i] = colonp[n - i];
227                         colonp[n - i] = 0;
228                 }
229                 tp = endp;
230         }
231         if (tp != endp)
232                 return (0);
233         memcpy(dst, tmp, NS_IN6ADDRSZ);
234         return (1);
235 }