1 /**
2 * @file pton.c Network address structure functions
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6
7 #define _BSD_SOURCE 1
8 #define _DEFAULT_SOURCE 1
9
10 #ifdef HAVE_INET_PTON
11 #ifdef WIN32
12 #include <windows.h>
13 #else
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <arpa/inet.h>
17 #define __USE_POSIX 1 /**< Use POSIX code */
18 #include <netdb.h>
19 #endif /* WIN32 */
20 #endif
21 #include <string.h>
22 #include <re_types.h>
23 #include <re_fmt.h>
24 #include <re_mbuf.h>
25 #include <re_sa.h>
26 #include "sa.h"
27
28
29 #define DEBUG_MODULE "net_pton"
30 #define DEBUG_LEVEL 5
31 #include <re_dbg.h>
32
33
34 #ifndef HAVE_INET_PTON
35
36
37 #define NS_INADDRSZ 4 /**< IPv4 T_A */
38 #define NS_IN6ADDRSZ 16 /**< IPv6 T_AAAA */
39 #define NS_INT16SZ 2 /**< #/bytes of data in a u_int16_t */
40
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
inet_pton4(const char * src,u_char * dst)53 inet_pton4(const char *src, u_char *dst)
54 {
55 static const char digits[] = "0123456789";
56 int saw_digit, octets, ch;
57 u_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 u_int newVal = (u_int) (*tp * 10 + (pch - digits));
67
68 if (newVal > 255)
69 return 0;
70 *tp = newVal;
71 if (! saw_digit) {
72 if (++octets > 4)
73 return 0;
74 saw_digit = 1;
75 }
76 }
77 else if (ch == '.' && saw_digit) {
78 if (octets == 4)
79 return 0;
80 *++tp = 0;
81 saw_digit = 0;
82 }
83 else
84 return 0;
85 }
86 if (octets < 4)
87 return 0;
88
89 memcpy(dst, tmp, NS_INADDRSZ);
90 return 1;
91 }
92
93
94 #ifdef HAVE_INET6
95 /* int
96 * inet_pton6(src, dst)
97 * convert presentation level address to network order binary form.
98 * return:
99 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
100 * notice:
101 * (1) does not touch `dst' unless it's returning 1.
102 * (2) :: in a full address is silently ignored.
103 * credit:
104 * inspired by Mark Andrews.
105 * author:
106 * Paul Vixie, 1996.
107 */
108 static int
inet_pton6(const char * src,u_char * dst)109 inet_pton6(const char *src, u_char *dst)
110 {
111 static const char xdigits_l[] = "0123456789abcdef",
112 xdigits_u[] = "0123456789ABCDEF";
113 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
114 const char *xdigits, *curtok;
115 int ch, saw_xdigit;
116 u_int val;
117
118 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
119 endp = tp + NS_IN6ADDRSZ;
120 colonp = NULL;
121 /* Leading :: requires some special handling. */
122 if (*src == ':')
123 if (*++src != ':')
124 return 0;
125 curtok = src;
126 saw_xdigit = 0;
127 val = 0;
128 while ((ch = *src++) != '\0') {
129 const char *pch;
130
131 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
132 pch = strchr((xdigits = xdigits_u), ch);
133 if (pch != NULL) {
134 val <<= 4;
135 val |= (u_int)(pch - xdigits);
136 if (val > 0xffff)
137 return 0;
138 saw_xdigit = 1;
139 continue;
140 }
141 if (ch == ':') {
142 curtok = src;
143 if (!saw_xdigit) {
144 if (colonp)
145 return 0;
146 colonp = tp;
147 continue;
148 }
149 if (tp + NS_INT16SZ > endp)
150 return 0;
151 *tp++ = (u_char) (val >> 8) & 0xff;
152 *tp++ = (u_char) val & 0xff;
153 saw_xdigit = 0;
154 val = 0;
155 continue;
156 }
157 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
158 inet_pton4(curtok, tp) > 0) {
159 tp += NS_INADDRSZ;
160 saw_xdigit = 0;
161 break; /* '\0' was seen by inet_pton4(). */
162 }
163 return 0;
164 }
165 if (saw_xdigit) {
166 if (tp + NS_INT16SZ > endp)
167 return 0;
168 *tp++ = (u_char) (val >> 8) & 0xff;
169 *tp++ = (u_char) val & 0xff;
170 }
171 if (colonp != NULL) {
172 /*
173 * Since some memmove()'s erroneously fail to handle
174 * overlapping regions, we'll do the shift by hand.
175 */
176 const int n = (int)(tp - colonp);
177 int i;
178
179 for (i = 1; i <= n; i++) {
180 endp[- i] = colonp[n - i];
181 colonp[n - i] = 0;
182 }
183 tp = endp;
184 }
185 if (tp != endp)
186 return 0;
187 memcpy(dst, tmp, NS_IN6ADDRSZ);
188
189 return 1;
190 }
191 #endif
192
193
194 /**
195 * Implementation of inet_pton()
196 */
inet_pton(int af,const char * src,void * dst)197 static int inet_pton(int af, const char *src, void *dst)
198 {
199 if (!src || !dst)
200 return 0;
201
202 switch (af) {
203
204 case AF_INET:
205 return inet_pton4(src, (u_char*) dst);
206
207 #ifdef HAVE_INET6
208 case AF_INET6:
209 return inet_pton6(src, (u_char*) dst);
210 #endif
211
212 default:
213 DEBUG_INFO("inet_pton: unknown address family %d\n", af);
214 errno = EAFNOSUPPORT;
215 return -1;
216 }
217 }
218 #endif
219
220
221 /**
222 * Convert character string to a network address structure
223 *
224 * @param addr IP address string
225 * @param sa Returned socket address
226 *
227 * @return 0 if success, otherwise errorcode
228 */
net_inet_pton(const char * addr,struct sa * sa)229 int net_inet_pton(const char *addr, struct sa *sa)
230 {
231 if (!addr)
232 return EINVAL;
233
234 if (inet_pton(AF_INET, addr, &sa->u.in.sin_addr) > 0) {
235 sa->u.in.sin_family = AF_INET;
236 }
237 #ifdef HAVE_INET6
238 else if (inet_pton(AF_INET6, addr, &sa->u.in6.sin6_addr) > 0) {
239
240 if (IN6_IS_ADDR_V4MAPPED(&sa->u.in6.sin6_addr)) {
241 const uint8_t *a = &sa->u.in6.sin6_addr.s6_addr[12];
242 sa->u.in.sin_family = AF_INET;
243 memcpy(&sa->u.in.sin_addr.s_addr, a, 4);
244 }
245 else {
246 sa->u.in6.sin6_family = AF_INET6;
247 }
248 }
249 #endif
250 else {
251 return EINVAL;
252 }
253
254 return 0;
255 }
256