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