Add IPv6 to Asterisk.
[asterisk/asterisk.git] / main / netsock2.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * Viagénie <asteriskv6@viagenie.ca>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Network socket handling
22  *
23  * \author Viagénie <asteriskv6@viagenie.ca>
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include "asterisk/config.h"
31 #include "asterisk/netsock2.h"
32 #include "asterisk/utils.h"
33 #include "asterisk/threadstorage.h"
34
35 static int ast_sockaddr_ipv4_mapped(const struct ast_sockaddr *addr, struct ast_sockaddr *ast_mapped)
36 {
37         const struct sockaddr_in6 *sin6;
38         struct sockaddr_in sin4;
39
40         if (!ast_sockaddr_is_ipv6(addr)) {
41                 return 0;
42         }
43
44         if (!ast_sockaddr_is_ipv4_mapped(addr)) {
45                 return 0;
46         }
47
48         sin6 = (const struct sockaddr_in6*)&addr->ss;
49
50         memset(&sin4, 0, sizeof(sin4));
51         sin4.sin_family = AF_INET;
52         sin4.sin_port = sin6->sin6_port;
53         sin4.sin_addr.s_addr = ((uint32_t *)&sin6->sin6_addr)[3];
54
55         ast_sockaddr_from_sin(ast_mapped, &sin4);
56
57         return 1;
58 }
59
60
61 AST_THREADSTORAGE(ast_sockaddr_stringify_buf);
62
63 char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format)
64 {
65         struct ast_sockaddr sa_ipv4;
66         const struct ast_sockaddr *sa_tmp;
67         char host[NI_MAXHOST];
68         char port[NI_MAXSERV];
69         struct ast_str *str;
70         int e;
71         static const size_t size = sizeof(host) - 1 + sizeof(port) - 1 + 4;
72
73
74         if (ast_sockaddr_isnull(sa)) {
75                 return "(null)";
76         }
77
78         if (!(str = ast_str_thread_get(&ast_sockaddr_stringify_buf, size))) {
79                 return "";
80         }
81
82         if (ast_sockaddr_ipv4_mapped(sa, &sa_ipv4)) {
83                 sa_tmp = &sa_ipv4;
84         } else {
85                 sa_tmp = sa;
86         }
87
88         if ((e = getnameinfo((struct sockaddr *)&sa_tmp->ss, sa->len,
89                              format & AST_SOCKADDR_STR_ADDR ? host : NULL,
90                              format & AST_SOCKADDR_STR_ADDR ? sizeof(host) : 0,
91                              format & AST_SOCKADDR_STR_PORT ? port : 0,
92                              format & AST_SOCKADDR_STR_PORT ? sizeof(port): 0,
93                              NI_NUMERICHOST | NI_NUMERICSERV))) {
94                 ast_log(LOG_ERROR, "getnameinfo(): %s\n", gai_strerror(e));
95                 return "";
96         }
97
98         switch (format)  {
99         case AST_SOCKADDR_STR_DEFAULT:
100                 ast_str_set(&str, 0, sa_tmp->ss.ss_family == AF_INET6 ?
101                                 "[%s]:%s" : "%s:%s", host, port);
102                 break;
103         case AST_SOCKADDR_STR_ADDR:
104                 ast_str_set(&str, 0, "%s", host);
105                 break;
106         case AST_SOCKADDR_STR_HOST:
107                 ast_str_set(&str, 0,
108                             sa_tmp->ss.ss_family == AF_INET6 ? "[%s]" : "%s", host);
109                 break;
110         case AST_SOCKADDR_STR_PORT:
111                 ast_str_set(&str, 0, "%s", port);
112                 break;
113         default:
114                 ast_log(LOG_ERROR, "Invalid format\n");
115                 return "";
116         }
117
118         return ast_str_buffer(str);
119 }
120
121 int static _ast_sockaddr_parse(char *str, char **host, char **port, int flags)
122 {
123         char *s = str;
124
125         ast_debug(5, "Splitting '%s' gives...\n", str);
126         *host = NULL;
127         *port = NULL;
128         if (*s == '[') {
129                 *host = ++s;
130                 for (; *s && *s != ']'; ++s) {
131                 }
132                 if (*s == ']') {
133                         *s++ = '\0';
134                 }
135                 if (*s == ':') {
136                         *port = s + 1;
137                 }
138         } else {
139                 *host = s;
140                 for (; *s; ++s) {
141                         if (*s == ':') {
142                                 if (*port) {
143                                         *port = NULL;
144                                         break;
145                                 } else {
146                                         *port = s;
147                                 }
148                         }
149                 }
150                 if (*port) {
151                         **port = '\0';
152                         ++*port;
153                 }
154         }
155         ast_debug(5, "...host '%s' and port '%s'.\n", *host, *port);
156
157         switch (flags & PARSE_PORT_MASK) {
158         case PARSE_PORT_IGNORE:
159                 *port = NULL;
160                 break;
161         case PARSE_PORT_REQUIRE:
162                 if (*port == NULL) {
163                         ast_log(LOG_WARNING, "missing port\n");
164                         return 0;
165                 }
166                 break;
167         case PARSE_PORT_FORBID:
168                 if (*port != NULL) {
169                         ast_log(LOG_WARNING, "port disallowed\n");
170                         return 0;
171                 }
172                 break;
173         }
174
175         return 1;
176 }
177
178
179
180 int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
181 {
182         struct addrinfo hints;
183         struct addrinfo *res;
184         char *s;
185         char *host;
186         char *port;
187         int     e;
188
189         s = ast_strdupa(str);
190         if (!_ast_sockaddr_parse(s, &host, &port, flags)) {
191                 return 0;
192         }
193
194         memset(&hints, 0, sizeof(hints));
195         /* Hint to get only one entry from getaddrinfo */
196         hints.ai_socktype = SOCK_DGRAM;
197
198         hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
199         if ((e = getaddrinfo(host, port, &hints, &res))) {
200                 ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
201                         host, S_OR(port, "(null)"), gai_strerror(e));
202                 return 0;
203         }
204
205         /*
206          * I don't see how this could be possible since we're not resolving host
207          * names. But let's be careful...
208          */
209         if (res->ai_next != NULL) {
210                 ast_log(LOG_WARNING, "getaddrinfo() returned multiple "
211                         "addresses. Ignoring all but the first.\n");
212         }
213
214         addr->len = res->ai_addrlen;
215         memcpy(&addr->ss, res->ai_addr, addr->len);
216
217         freeaddrinfo(res);
218
219         return 1;
220 }
221
222 int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
223                          int flags, int family)
224 {
225         struct addrinfo hints, *res, *ai;
226         char *s, *host, *port;
227         int     e, i, res_cnt;
228
229         s = ast_strdupa(str);
230         if (!_ast_sockaddr_parse(s, &host, &port, flags)) {
231                 return 0;
232         }
233
234         memset(&hints, 0, sizeof(hints));
235         hints.ai_family = family;
236         hints.ai_socktype = SOCK_DGRAM;
237
238         if ((e = getaddrinfo(host, port, &hints, &res))) {
239                 ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
240                         host, S_OR(port, "(null)"), gai_strerror(e));
241                 return 0;
242         }
243
244         res_cnt = 0;
245         for (ai = res; ai; ai = ai->ai_next) {
246                 res_cnt++;
247         }
248
249         if ((*addrs = ast_malloc(res_cnt * sizeof(struct ast_sockaddr))) == NULL) {
250                 res_cnt = 0;
251                 goto cleanup;
252         }
253
254         i = 0;
255         for (ai = res; ai; ai = ai->ai_next) {
256                 (*addrs)[i].len = ai->ai_addrlen;
257                 memcpy(&(*addrs)[i].ss, ai->ai_addr, ai->ai_addrlen);
258                 ++i;
259         }
260
261 cleanup:
262         freeaddrinfo(res);
263         return res_cnt;
264 }
265
266 int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
267 {
268         const struct ast_sockaddr *a_tmp, *b_tmp;
269         struct ast_sockaddr ipv4_mapped;
270
271         a_tmp = a;
272         b_tmp = b;
273
274         if (a_tmp->len != b_tmp->len) {
275                 if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
276                         a_tmp = &ipv4_mapped;
277                 } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
278                         b_tmp = &ipv4_mapped;
279                 }
280         }
281
282         if (a_tmp->len < b_tmp->len) {
283                 return -1;
284         } else if (a_tmp->len > b_tmp->len) {
285                 return 1;
286         }
287
288         return memcmp(&a_tmp->ss, &b_tmp->ss, a_tmp->len);
289 }
290
291 int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
292 {
293         const struct ast_sockaddr *a_tmp, *b_tmp;
294         struct ast_sockaddr ipv4_mapped;
295         const struct in_addr *ip4a, *ip4b;
296         const struct in6_addr *ip6a, *ip6b;
297         int ret = -1;
298
299         a_tmp = a;
300         b_tmp = b;
301
302         if (a_tmp->len != b_tmp->len) {
303                 if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
304                         a_tmp = &ipv4_mapped;
305                 } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
306                         b_tmp = &ipv4_mapped;
307                 }
308         }
309
310         if (a->len < b->len) {
311                 ret = -1;
312         } else if (a->len > b->len) {
313                 ret = 1;
314         }
315
316         switch (a_tmp->ss.ss_family) {
317         case AF_INET:
318                 ip4a = &((const struct sockaddr_in*)&a_tmp->ss)->sin_addr;
319                 ip4b = &((const struct sockaddr_in*)&b_tmp->ss)->sin_addr;
320                 ret = memcmp(ip4a, ip4b, sizeof(*ip4a));
321                 break;
322         case AF_INET6:
323                 ip6a = &((const struct sockaddr_in6*)&a_tmp->ss)->sin6_addr;
324                 ip6b = &((const struct sockaddr_in6*)&b_tmp->ss)->sin6_addr;
325                 ret = memcmp(ip6a, ip6b, sizeof(*ip6a));
326                 break;
327         }
328         return ret;
329 }
330
331 uint16_t ast_sockaddr_port(const struct ast_sockaddr *addr)
332 {
333         if (addr->ss.ss_family == AF_INET &&
334             addr->len == sizeof(struct sockaddr_in)) {
335                 return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port);
336         } else if (addr->ss.ss_family == AF_INET6 &&
337                  addr->len == sizeof(struct sockaddr_in6)) {
338                 return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port);
339         }
340         ast_log(LOG_ERROR, "Not an IPv4 nor IPv6 address, cannot get port.\n");
341         return 0;
342 }
343
344 void ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port)
345 {
346         if (addr->ss.ss_family == AF_INET &&
347             addr->len == sizeof(struct sockaddr_in)) {
348                 ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port);
349         } else if (addr->ss.ss_family == AF_INET6 &&
350                  addr->len == sizeof(struct sockaddr_in6)) {
351                 ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
352         } else {
353                 ast_log(LOG_ERROR,
354                         "Not an IPv4 nor IPv6 address, cannot set port.\n");
355         }
356 }
357
358 uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
359 {
360         const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss;
361         return ntohl(sin->sin_addr.s_addr);
362 }
363
364 int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
365 {
366         return addr->ss.ss_family == AF_INET &&
367             addr->len == sizeof(struct sockaddr_in);
368 }
369
370 int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr)
371 {
372         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss;
373         return addr->len && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr);
374 }
375
376 int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
377 {
378         return addr->ss.ss_family == AF_INET6 &&
379             addr->len == sizeof(struct sockaddr_in6);
380 }
381
382 int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
383 {
384         return (ast_sockaddr_is_ipv4(addr) &&
385                 ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr ==
386                 INADDR_ANY) ||
387             (ast_sockaddr_is_ipv6(addr) &&
388              IN6_IS_ADDR_UNSPECIFIED(&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr));
389 }
390
391 int ast_sockaddr_hash(const struct ast_sockaddr *addr)
392 {
393         /*
394          * For IPv4, return the IP address as-is. For IPv6, return the last 32
395          * bits.
396          */
397         switch (addr->ss.ss_family) {
398         case AF_INET:
399                 return ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr;
400         case AF_INET6:
401                 return ((uint32_t *)&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)[3];
402         default:
403                 ast_log(LOG_ERROR, "Unknown address family '%d'.\n",
404                         addr->ss.ss_family);
405                 return 0;
406         }
407 }
408
409 int ast_accept(int sockfd, struct ast_sockaddr *addr)
410 {
411         addr->len = sizeof(addr->ss);
412         return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
413 }
414
415 int ast_bind(int sockfd, const struct ast_sockaddr *addr)
416 {
417         return bind(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
418 }
419
420 int ast_connect(int sockfd, const struct ast_sockaddr *addr)
421 {
422         return connect(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
423 }
424
425 int ast_getsockname(int sockfd, struct ast_sockaddr *addr)
426 {
427         addr->len = sizeof(addr->ss);
428         return getsockname(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
429 }
430
431 ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags,
432                      struct ast_sockaddr *src_addr)
433 {
434         src_addr->len = sizeof(src_addr->ss);
435         return recvfrom(sockfd, buf, len, flags,
436                         (struct sockaddr *)&src_addr->ss, &src_addr->len);
437 }
438
439 ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags,
440                    const struct ast_sockaddr *dest_addr)
441 {
442         return sendto(sockfd, buf, len, flags,
443                       (const struct sockaddr *)&dest_addr->ss, dest_addr->len);
444 }
445
446 int ast_set_qos(int sockfd, int tos, int cos, const char *desc)
447 {
448         int res;
449
450         if ((res = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) {
451                 ast_log(LOG_WARNING, "Unable to set %s TOS to %d (may be you have no "
452                         "root privileges): %s\n", desc, tos, strerror(errno));
453         } else if (tos) {
454                 ast_verb(2, "Using %s TOS bits %d\n", desc, tos);
455         }
456
457 #ifdef linux
458         if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos))) {
459                 ast_log(LOG_WARNING, "Unable to set %s CoS to %d: %s\n", desc, cos,
460                         strerror(errno));
461         } else if (cos) {
462                 ast_verb(2, "Using %s CoS mark %d\n", desc, cos);
463         }
464 #endif
465
466         return res;
467 }
468
469 int ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
470                         struct sockaddr_in *sin)
471 {
472         if (ast_sockaddr_isnull(addr)) {
473                 memset(sin, 0, sizeof(*sin));
474                 return 1;
475         }
476
477         if (addr->len != sizeof(*sin)) {
478                 ast_log(LOG_ERROR, "Bad address cast to IPv4\n");
479                 return 0;
480         }
481
482         if (addr->ss.ss_family != AF_INET) {
483                 ast_log(LOG_DEBUG, "Address family is not AF_INET\n");
484         }
485
486         *sin = *(struct sockaddr_in *)&addr->ss;
487         return 1;
488 }
489
490 void ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin)
491 {
492         *((struct sockaddr_in *)&addr->ss) = *sin;
493
494         if (addr->ss.ss_family != AF_INET) {
495                 ast_log(LOG_DEBUG, "Address family is not AF_INET\n");
496         }
497
498         addr->len = sizeof(*sin);
499 }