1 /*
2 inet_pton.c -- convert IPv4 and IPv6 addresses from text to binary form
3
4 Modifications to inet_pton6 allowing IPv4 addresses to appear
5 throughout, and miscellaneous modifications to inet_pton4, by Tom
6 Harrison <tomhrr@cpan.org> (Copyright (C) 2010).
7
8 Copyright (C) 2006 Free Software Foundation, Inc.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
24 Copyright (c) 1996,1999 by Internet Software Consortium.
25
26 Permission to use, copy, modify, and distribute this software for any
27 purpose with or without fee is hereby granted, provided that the above
28 copyright notice and this permission notice appear in all copies.
29
30 THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
31 ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
32 OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
33 CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
34 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
35 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
36 ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37 SOFTWARE.
38 */
39
40 #include <ctype.h>
41 #include <string.h>
42 #include <errno.h>
43
44 #define NS_INADDRSZ 4
45 #define NS_IN6ADDRSZ 16
46 #define NS_INT16SZ 2
47
48 int inet_pton4 (const char *src, unsigned char *dst);
49 int inet_pton6 (const char *src, unsigned char *dst);
50
51 /* int
52 * inet_pton4(src, dst)
53 * like inet_aton() but without all the hexadecimal, octal (with the
54 * exception of 0) and shorthand.
55 * return:
56 * 1 if `src' is a valid dotted quad, else 0.
57 * notice:
58 * does not touch `dst' unless it's returning 1.
59 * author:
60 * Paul Vixie, 1996.
61 * (Some modifications by Tom Harrison, 2010.)
62 */
63 int
inet_pton4(const char * src,unsigned char * dst)64 inet_pton4 (const char *src, unsigned char *dst)
65 {
66 int saw_digit, octets, ch;
67 unsigned char tmp[NS_INADDRSZ], *tp;
68
69 memset(tmp, 0, NS_INADDRSZ);
70 saw_digit = 0;
71 octets = 0;
72 *(tp = tmp) = 0;
73
74 while ((ch = *src++) != '\0') {
75 if (ch >= '0' && ch <= '9') {
76 unsigned n = *tp * 10 + (ch - '0');
77
78 if (saw_digit && *tp == 0) {
79 return 0;
80 }
81 if (n > 255) {
82 return 0;
83 }
84 *tp = n;
85 if (!saw_digit) {
86 ++octets;
87 saw_digit = 1;
88 }
89 } else if (ch == '.' && saw_digit) {
90 if (octets == 4) {
91 return 0;
92 }
93 ++tp;
94 saw_digit = 0;
95 } else {
96 return 0;
97 }
98 }
99
100 memcpy(dst, tmp, NS_INADDRSZ);
101 return 1;
102 }
103
104 /* int
105 * inet_pton6(src, dst)
106 * convert presentation level address to network order binary form.
107 * return:
108 * 1 if `src' is a valid IPv6 address (may contain IPv4 addresses
109 * in any position), else 0.
110 * notice:
111 * (1) does not touch `dst' unless it's returning 1.
112 * (2) :: in a full address is silently ignored.
113 * credit:
114 * inspired by Mark Andrews.
115 * author:
116 * Paul Vixie, 1996.
117 * (Modifications allowing IPv4 addresses to appear throughout
118 * by Tom Harrison, 2010.)
119 */
120 int
inet_pton6(const char * src,unsigned char * dst)121 inet_pton6 (const char *src, unsigned char *dst)
122 {
123 static const char xdigits[] = "0123456789abcdef";
124 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
125 const char *ipv4_endp;
126 char ipv4[16];
127 int diff;
128 const char *curtok;
129 int ch, saw_xdigit;
130 unsigned val;
131
132 tp = (unsigned char *) memset (tmp, '\0', NS_IN6ADDRSZ);
133 endp = tp + NS_IN6ADDRSZ;
134 colonp = NULL;
135 /* Leading :: requires some special handling. */
136 if (*src == ':') {
137 if (*++src != ':') {
138 return 0;
139 }
140 }
141 curtok = src;
142 saw_xdigit = 0;
143 val = 0;
144 while ((ch = tolower (*src++)) != '\0') {
145 const char *pch;
146
147 pch = strchr (xdigits, ch);
148 if (pch != NULL) {
149 val <<= 4;
150 val |= (pch - xdigits);
151 if (val > 0xffff) {
152 return 0;
153 }
154 saw_xdigit = 1;
155 continue;
156 }
157 if (ch == ':') {
158 curtok = src;
159 if (!saw_xdigit) {
160 if (colonp) {
161 return 0;
162 }
163 colonp = tp;
164 continue;
165 } else if (*src == '\0') {
166 return 0;
167 }
168 if (tp + NS_INT16SZ > endp) {
169 return 0;
170 }
171 *tp++ = (unsigned char) (val >> 8) & 0xff;
172 *tp++ = (unsigned char) val & 0xff;
173 saw_xdigit = 0;
174 val = 0;
175 continue;
176 }
177 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)) {
178 /* Find the next : from curtok, copy from curtok to that
179 * point to ipv4, if it's IPv4 all is good. If the : is not found,
180 * it terminates, so check it directly. */
181 ipv4_endp = strchr(curtok, ':');
182 if (ipv4_endp) {
183 diff = ipv4_endp - curtok;
184 if (diff > 15) {
185 return 0;
186 }
187 memcpy(ipv4, curtok, diff);
188 ipv4[diff] = '\0';
189 diff = inet_pton4(ipv4, tp);
190 } else {
191 diff = inet_pton4(curtok, tp);
192 }
193 if (diff) {
194 val = (tp[2] << 8) | tp[3];
195 tp += 2;
196 saw_xdigit=1;
197 if (ipv4_endp) {
198 src = ipv4_endp;
199 continue;
200 } else {
201 saw_xdigit=0;
202 tp += 2;
203 break;
204 }
205 }
206 }
207 return 0;
208 }
209 if (saw_xdigit) {
210 if (tp + NS_INT16SZ > endp) {
211 return 0;
212 }
213 *tp++ = (unsigned char) (val >> 8) & 0xff;
214 *tp++ = (unsigned char) val & 0xff;
215 }
216 if (colonp != NULL) {
217 /*
218 * Since some memmove()'s erroneously fail to handle
219 * overlapping regions, we'll do the shift by hand.
220 */
221 const int n = tp - colonp;
222 int i;
223
224 if (tp == endp) {
225 return 0;
226 }
227 for (i = 1; i <= n; i++) {
228 endp[-i] = colonp[n - i];
229 colonp[n - i] = 0;
230 }
231 tp = endp;
232 }
233
234 while (tp < endp) {
235 *(tp++) = 0;
236 }
237 memcpy(dst, tmp, NS_IN6ADDRSZ);
238 return 1;
239 }
240