File Coverage

inet_pton.c
Criterion Covered Total %
statement 97 97 100.0
branch 62 64 96.8
condition n/a
subroutine n/a
pod n/a
total 159 161 98.7


line stmt bran cond sub pod time code
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 (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
41             #include
42             #include
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
64 2205           inet_pton4 (const char *src, unsigned char *dst)
65             {
66             int saw_digit, octets, ch;
67             unsigned char tmp[NS_INADDRSZ], *tp;
68            
69 2205           memset(tmp, 0, NS_INADDRSZ);
70 2205           saw_digit = 0;
71 2205           octets = 0;
72 2205           *(tp = tmp) = 0;
73            
74 30236 100         while ((ch = *src++) != '\0') {
75 49543 100         if (ch >= '0' && ch <= '9') {
    100          
76 21506           unsigned n = *tp * 10 + (ch - '0');
77            
78 21506 100         if (saw_digit && *tp == 0) {
    100          
79 1           return 0;
80             }
81 21505 100         if (n > 255) {
82 2           return 0;
83             }
84 21503           *tp = n;
85 21503 100         if (!saw_digit) {
86 8727           ++octets;
87 8727           saw_digit = 1;
88             }
89 6534 100         } else if (ch == '.' && saw_digit) {
    50          
90 6530 100         if (octets == 4) {
91 2           return 0;
92             }
93 6528           ++tp;
94 6528           saw_digit = 0;
95             } else {
96 4           return 0;
97             }
98             }
99            
100 2196           memcpy(dst, tmp, NS_INADDRSZ);
101 2205           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
121 839           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 839           tp = (unsigned char *) memset (tmp, '\0', NS_IN6ADDRSZ);
133 839           endp = tp + NS_IN6ADDRSZ;
134 839           colonp = NULL;
135             /* Leading :: requires some special handling. */
136 839 100         if (*src == ':') {
137 40 100         if (*++src != ':') {
138 1           return 0;
139             }
140             }
141 838           curtok = src;
142 838           saw_xdigit = 0;
143 838           val = 0;
144 29352 100         while ((ch = tolower (*src++)) != '\0') {
145             const char *pch;
146            
147 28525           pch = strchr (xdigits, ch);
148 28525 100         if (pch != NULL) {
149 23205           val <<= 4;
150 23205           val |= (pch - xdigits);
151 23205 100         if (val > 0xffff) {
152 1           return 0;
153             }
154 23204           saw_xdigit = 1;
155 23204           continue;
156             }
157 5320 100         if (ch == ':') {
158 5300           curtok = src;
159 5300 100         if (!saw_xdigit) {
160 112 100         if (colonp) {
161 1           return 0;
162             }
163 111           colonp = tp;
164 111           continue;
165 5188 100         } else if (*src == '\0') {
166 1           return 0;
167             }
168 5187 100         if (tp + NS_INT16SZ > endp) {
169 2           return 0;
170             }
171 5185           *tp++ = (unsigned char) (val >> 8) & 0xff;
172 5185           *tp++ = (unsigned char) val & 0xff;
173 5185           saw_xdigit = 0;
174 5185           val = 0;
175 5185           continue;
176             }
177 20 100         if (ch == '.' && ((tp + NS_INADDRSZ) <= endp)) {
    100          
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 16           ipv4_endp = strchr(curtok, ':');
182 16 100         if (ipv4_endp) {
183 15           diff = ipv4_endp - curtok;
184 15 100         if (diff > 15) {
185 1           return 0;
186             }
187 14           memcpy(ipv4, curtok, diff);
188 14           ipv4[diff] = '\0';
189 14           diff = inet_pton4(ipv4, tp);
190             } else {
191 1           diff = inet_pton4(curtok, tp);
192             }
193 15 50         if (diff) {
194 15           val = (tp[2] << 8) | tp[3];
195 15           tp += 2;
196 15           saw_xdigit=1;
197 15 100         if (ipv4_endp) {
198 14           src = ipv4_endp;
199 14           continue;
200             } else {
201 1           saw_xdigit=0;
202 1           tp += 2;
203 1           break;
204             }
205             }
206             }
207 4           return 0;
208             }
209 828 100         if (saw_xdigit) {
210 734 100         if (tp + NS_INT16SZ > endp) {
211 1           return 0;
212             }
213 733           *tp++ = (unsigned char) (val >> 8) & 0xff;
214 733           *tp++ = (unsigned char) val & 0xff;
215             }
216 827 100         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 110           const int n = tp - colonp;
222             int i;
223            
224 110 100         if (tp == endp) {
225 1           return 0;
226             }
227 165 100         for (i = 1; i <= n; i++) {
228 56           endp[-i] = colonp[n - i];
229 56           colonp[n - i] = 0;
230             }
231 109           tp = endp;
232             }
233            
234 872 100         while (tp < endp) {
235 46           *(tp++) = 0;
236             }
237 826           memcpy(dst, tmp, NS_IN6ADDRSZ);
238 839           return 1;
239             }