Merge branch 'ap/maint-diff-rename-avoid-overlap' into maint
[git] / compat / inet_pton.c
1 /*
2  * Copyright (C) 1996-2001  Internet Software Consortium.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
9  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
10  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
11  * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
13  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
15  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include "../git-compat-util.h"
19
20 #ifndef NS_INT16SZ
21 #define NS_INT16SZ       2
22 #endif
23
24 #ifndef NS_INADDRSZ
25 #define NS_INADDRSZ      4
26 #endif
27
28 #ifndef NS_IN6ADDRSZ
29 #define NS_IN6ADDRSZ    16
30 #endif
31
32 /*
33  * WARNING: Don't even consider trying to compile this on a system where
34  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
35  */
36
37 static int inet_pton4(const char *src, unsigned char *dst);
38 #ifndef NO_IPV6
39 static int inet_pton6(const char *src, unsigned char *dst);
40 #endif
41
42 /* int
43  * inet_pton4(src, dst)
44  *      like inet_aton() but without all the hexadecimal and shorthand.
45  * return:
46  *      1 if `src' is a valid dotted quad, else 0.
47  * notice:
48  *      does not touch `dst' unless it's returning 1.
49  * author:
50  *      Paul Vixie, 1996.
51  */
52 static int
53 inet_pton4(const char *src, unsigned char *dst)
54 {
55         static const char digits[] = "0123456789";
56         int saw_digit, octets, ch;
57         unsigned char tmp[NS_INADDRSZ], *tp;
58
59         saw_digit = 0;
60         octets = 0;
61         *(tp = tmp) = 0;
62         while ((ch = *src++) != '\0') {
63                 const char *pch;
64
65                 if ((pch = strchr(digits, ch)) != NULL) {
66                         unsigned int new = *tp * 10 + (pch - digits);
67
68                         if (new > 255)
69                                 return (0);
70                         *tp = new;
71                         if (! saw_digit) {
72                                 if (++octets > 4)
73                                         return (0);
74                                 saw_digit = 1;
75                         }
76                 } else if (ch == '.' && saw_digit) {
77                         if (octets == 4)
78                                 return (0);
79                         *++tp = 0;
80                         saw_digit = 0;
81                 } else
82                         return (0);
83         }
84         if (octets < 4)
85                 return (0);
86         memcpy(dst, tmp, NS_INADDRSZ);
87         return (1);
88 }
89
90 /* int
91  * inet_pton6(src, dst)
92  *      convert presentation level address to network order binary form.
93  * return:
94  *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
95  * notice:
96  *      (1) does not touch `dst' unless it's returning 1.
97  *      (2) :: in a full address is silently ignored.
98  * credit:
99  *      inspired by Mark Andrews.
100  * author:
101  *      Paul Vixie, 1996.
102  */
103
104 #ifndef NO_IPV6
105 static int
106 inet_pton6(const char *src, unsigned char *dst)
107 {
108         static const char xdigits_l[] = "0123456789abcdef",
109                           xdigits_u[] = "0123456789ABCDEF";
110         unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
111         const char *xdigits, *curtok;
112         int ch, saw_xdigit;
113         unsigned int val;
114
115         memset((tp = tmp), '\0', NS_IN6ADDRSZ);
116         endp = tp + NS_IN6ADDRSZ;
117         colonp = NULL;
118         /* Leading :: requires some special handling. */
119         if (*src == ':')
120                 if (*++src != ':')
121                         return (0);
122         curtok = src;
123         saw_xdigit = 0;
124         val = 0;
125         while ((ch = *src++) != '\0') {
126                 const char *pch;
127
128                 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
129                         pch = strchr((xdigits = xdigits_u), ch);
130                 if (pch != NULL) {
131                         val <<= 4;
132                         val |= (pch - xdigits);
133                         if (val > 0xffff)
134                                 return (0);
135                         saw_xdigit = 1;
136                         continue;
137                 }
138                 if (ch == ':') {
139                         curtok = src;
140                         if (!saw_xdigit) {
141                                 if (colonp)
142                                         return (0);
143                                 colonp = tp;
144                                 continue;
145                         }
146                         if (tp + NS_INT16SZ > endp)
147                                 return (0);
148                         *tp++ = (unsigned char) (val >> 8) & 0xff;
149                         *tp++ = (unsigned char) val & 0xff;
150                         saw_xdigit = 0;
151                         val = 0;
152                         continue;
153                 }
154                 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
155                     inet_pton4(curtok, tp) > 0) {
156                         tp += NS_INADDRSZ;
157                         saw_xdigit = 0;
158                         break;  /* '\0' was seen by inet_pton4(). */
159                 }
160                 return (0);
161         }
162         if (saw_xdigit) {
163                 if (tp + NS_INT16SZ > endp)
164                         return (0);
165                 *tp++ = (unsigned char) (val >> 8) & 0xff;
166                 *tp++ = (unsigned char) val & 0xff;
167         }
168         if (colonp != NULL) {
169                 /*
170                  * Since some memmove()'s erroneously fail to handle
171                  * overlapping regions, we'll do the shift by hand.
172                  */
173                 const int n = tp - colonp;
174                 int i;
175
176                 for (i = 1; i <= n; i++) {
177                         endp[- i] = colonp[n - i];
178                         colonp[n - i] = 0;
179                 }
180                 tp = endp;
181         }
182         if (tp != endp)
183                 return (0);
184         memcpy(dst, tmp, NS_IN6ADDRSZ);
185         return (1);
186 }
187 #endif
188
189 /* int
190  * isc_net_pton(af, src, dst)
191  *      convert from presentation format (which usually means ASCII printable)
192  *      to network format (which is usually some kind of binary format).
193  * return:
194  *      1 if the address was valid for the specified address family
195  *      0 if the address wasn't valid (`dst' is untouched in this case)
196  *      -1 if some other error occurred (`dst' is untouched in this case, too)
197  * author:
198  *      Paul Vixie, 1996.
199  */
200 int
201 inet_pton(int af, const char *src, void *dst)
202 {
203         switch (af) {
204         case AF_INET:
205                 return (inet_pton4(src, dst));
206 #ifndef NO_IPV6
207         case AF_INET6:
208                 return (inet_pton6(src, dst));
209 #endif
210         default:
211                 errno = EAFNOSUPPORT;
212                 return (-1);
213         }
214         /* NOTREACHED */
215 }