Merged revisions 279817 via svnmerge from
[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 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 #ifdef AI_NUMERICSERV
199         hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
200 #else
201         hints.ai_flags = AI_NUMERICHOST;
202 #endif
203         if ((e = getaddrinfo(host, port, &hints, &res))) {
204                 if (e != EAI_NONAME) { /* if this was just a host name rather than a ip address, don't print error */
205                         ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
206                                 host, S_OR(port, "(null)"), gai_strerror(e));
207                 }
208                 return 0;
209         }
210
211         /*
212          * I don't see how this could be possible since we're not resolving host
213          * names. But let's be careful...
214          */
215         if (res->ai_next != NULL) {
216                 ast_log(LOG_WARNING, "getaddrinfo() returned multiple "
217                         "addresses. Ignoring all but the first.\n");
218         }
219
220         addr->len = res->ai_addrlen;
221         memcpy(&addr->ss, res->ai_addr, addr->len);
222
223         freeaddrinfo(res);
224
225         return 1;
226 }
227
228 int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
229                          int flags, int family)
230 {
231         struct addrinfo hints, *res, *ai;
232         char *s, *host, *port;
233         int     e, i, res_cnt;
234
235         s = ast_strdupa(str);
236         if (!_ast_sockaddr_parse(s, &host, &port, flags)) {
237                 return 0;
238         }
239
240         memset(&hints, 0, sizeof(hints));
241         hints.ai_family = family;
242         hints.ai_socktype = SOCK_DGRAM;
243
244         if ((e = getaddrinfo(host, port, &hints, &res))) {
245                 ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
246                         host, S_OR(port, "(null)"), gai_strerror(e));
247                 return 0;
248         }
249
250         res_cnt = 0;
251         for (ai = res; ai; ai = ai->ai_next) {
252                 res_cnt++;
253         }
254
255         if ((*addrs = ast_malloc(res_cnt * sizeof(struct ast_sockaddr))) == NULL) {
256                 res_cnt = 0;
257                 goto cleanup;
258         }
259
260         i = 0;
261         for (ai = res; ai; ai = ai->ai_next) {
262                 (*addrs)[i].len = ai->ai_addrlen;
263                 memcpy(&(*addrs)[i].ss, ai->ai_addr, ai->ai_addrlen);
264                 ++i;
265         }
266
267 cleanup:
268         freeaddrinfo(res);
269         return res_cnt;
270 }
271
272 int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
273 {
274         const struct ast_sockaddr *a_tmp, *b_tmp;
275         struct ast_sockaddr ipv4_mapped;
276
277         a_tmp = a;
278         b_tmp = b;
279
280         if (a_tmp->len != b_tmp->len) {
281                 if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
282                         a_tmp = &ipv4_mapped;
283                 } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
284                         b_tmp = &ipv4_mapped;
285                 }
286         }
287
288         if (a_tmp->len < b_tmp->len) {
289                 return -1;
290         } else if (a_tmp->len > b_tmp->len) {
291                 return 1;
292         }
293
294         return memcmp(&a_tmp->ss, &b_tmp->ss, a_tmp->len);
295 }
296
297 int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
298 {
299         const struct ast_sockaddr *a_tmp, *b_tmp;
300         struct ast_sockaddr ipv4_mapped;
301         const struct in_addr *ip4a, *ip4b;
302         const struct in6_addr *ip6a, *ip6b;
303         int ret = -1;
304
305         a_tmp = a;
306         b_tmp = b;
307
308         if (a_tmp->len != b_tmp->len) {
309                 if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
310                         a_tmp = &ipv4_mapped;
311                 } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
312                         b_tmp = &ipv4_mapped;
313                 }
314         }
315
316         if (a->len < b->len) {
317                 ret = -1;
318         } else if (a->len > b->len) {
319                 ret = 1;
320         }
321
322         switch (a_tmp->ss.ss_family) {
323         case AF_INET:
324                 ip4a = &((const struct sockaddr_in*)&a_tmp->ss)->sin_addr;
325                 ip4b = &((const struct sockaddr_in*)&b_tmp->ss)->sin_addr;
326                 ret = memcmp(ip4a, ip4b, sizeof(*ip4a));
327                 break;
328         case AF_INET6:
329                 ip6a = &((const struct sockaddr_in6*)&a_tmp->ss)->sin6_addr;
330                 ip6b = &((const struct sockaddr_in6*)&b_tmp->ss)->sin6_addr;
331                 ret = memcmp(ip6a, ip6b, sizeof(*ip6a));
332                 break;
333         }
334         return ret;
335 }
336
337 uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, int line, const char *func)
338 {
339         if (addr->ss.ss_family == AF_INET &&
340             addr->len == sizeof(struct sockaddr_in)) {
341                 return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port);
342         } else if (addr->ss.ss_family == AF_INET6 &&
343                  addr->len == sizeof(struct sockaddr_in6)) {
344                 return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port);
345         }
346         ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
347         return 0;
348 }
349
350 void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char *file, int line, const char *func)
351 {
352         if (addr->ss.ss_family == AF_INET &&
353             addr->len == sizeof(struct sockaddr_in)) {
354                 ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port);
355         } else if (addr->ss.ss_family == AF_INET6 &&
356                  addr->len == sizeof(struct sockaddr_in6)) {
357                 ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
358         } else {
359                 ast_log(__LOG_DEBUG, file, line, func,
360                         "Not an IPv4 nor IPv6 address, cannot set port.\n");
361         }
362 }
363
364 uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
365 {
366         const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss;
367         return ntohl(sin->sin_addr.s_addr);
368 }
369
370 int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
371 {
372         return addr->ss.ss_family == AF_INET &&
373             addr->len == sizeof(struct sockaddr_in);
374 }
375
376 int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr)
377 {
378         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss;
379         return addr->len && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr);
380 }
381
382 int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
383 {
384         return addr->ss.ss_family == AF_INET6 &&
385             addr->len == sizeof(struct sockaddr_in6);
386 }
387
388 int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
389 {
390         return (ast_sockaddr_is_ipv4(addr) &&
391                 ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr ==
392                 INADDR_ANY) ||
393             (ast_sockaddr_is_ipv6(addr) &&
394              IN6_IS_ADDR_UNSPECIFIED(&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr));
395 }
396
397 int ast_sockaddr_hash(const struct ast_sockaddr *addr)
398 {
399         /*
400          * For IPv4, return the IP address as-is. For IPv6, return the last 32
401          * bits.
402          */
403         switch (addr->ss.ss_family) {
404         case AF_INET:
405                 return ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr;
406         case AF_INET6:
407                 return ((uint32_t *)&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)[3];
408         default:
409                 ast_log(LOG_ERROR, "Unknown address family '%d'.\n",
410                         addr->ss.ss_family);
411                 return 0;
412         }
413 }
414
415 int ast_accept(int sockfd, struct ast_sockaddr *addr)
416 {
417         addr->len = sizeof(addr->ss);
418         return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
419 }
420
421 int ast_bind(int sockfd, const struct ast_sockaddr *addr)
422 {
423         return bind(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
424 }
425
426 int ast_connect(int sockfd, const struct ast_sockaddr *addr)
427 {
428         return connect(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
429 }
430
431 int ast_getsockname(int sockfd, struct ast_sockaddr *addr)
432 {
433         addr->len = sizeof(addr->ss);
434         return getsockname(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
435 }
436
437 ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags,
438                      struct ast_sockaddr *src_addr)
439 {
440         src_addr->len = sizeof(src_addr->ss);
441         return recvfrom(sockfd, buf, len, flags,
442                         (struct sockaddr *)&src_addr->ss, &src_addr->len);
443 }
444
445 ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags,
446                    const struct ast_sockaddr *dest_addr)
447 {
448         return sendto(sockfd, buf, len, flags,
449                       (const struct sockaddr *)&dest_addr->ss, dest_addr->len);
450 }
451
452 int ast_set_qos(int sockfd, int tos, int cos, const char *desc)
453 {
454         int res;
455
456         if ((res = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) {
457                 ast_log(LOG_WARNING, "Unable to set %s TOS to %d (may be you have no "
458                         "root privileges): %s\n", desc, tos, strerror(errno));
459         } else if (tos) {
460                 ast_verb(2, "Using %s TOS bits %d\n", desc, tos);
461         }
462
463 #ifdef linux
464         if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos))) {
465                 ast_log(LOG_WARNING, "Unable to set %s CoS to %d: %s\n", desc, cos,
466                         strerror(errno));
467         } else if (cos) {
468                 ast_verb(2, "Using %s CoS mark %d\n", desc, cos);
469         }
470 #endif
471
472         return res;
473 }
474
475 int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
476                         struct sockaddr_in *sin, const char *file, int line, const char *func)
477 {
478         if (ast_sockaddr_isnull(addr)) {
479                 memset(sin, 0, sizeof(*sin));
480                 return 1;
481         }
482
483         if (addr->len != sizeof(*sin)) {
484                 ast_log(__LOG_ERROR, file, line, func, "Bad address cast to IPv4\n");
485                 return 0;
486         }
487
488         if (addr->ss.ss_family != AF_INET) {
489                 ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
490         }
491
492         *sin = *(struct sockaddr_in *)&addr->ss;
493         return 1;
494 }
495
496 void _ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin,
497                 const char *file, int line, const char *func)
498 {
499         memcpy(&addr->ss, sin, sizeof(*sin));
500
501         if (addr->ss.ss_family != AF_INET) {
502                 ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
503         }
504
505         addr->len = sizeof(*sin);
506 }