ed5964db8ae40a357f9229e92173496d8fca8d47
[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 ast_sockaddr_split_hostport(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_split_hostport(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_split_hostport(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         if (option_debug >= 1) {
347                 ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
348         }
349         return 0;
350 }
351
352 void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char *file, int line, const char *func)
353 {
354         if (addr->ss.ss_family == AF_INET &&
355             addr->len == sizeof(struct sockaddr_in)) {
356                 ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port);
357         } else if (addr->ss.ss_family == AF_INET6 &&
358                  addr->len == sizeof(struct sockaddr_in6)) {
359                 ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
360         } else if (option_debug >= 1) {
361                 ast_log(__LOG_DEBUG, file, line, func,
362                         "Not an IPv4 nor IPv6 address, cannot set port.\n");
363         }
364 }
365
366 uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
367 {
368         const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss;
369         return ntohl(sin->sin_addr.s_addr);
370 }
371
372 int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
373 {
374         return addr->ss.ss_family == AF_INET &&
375             addr->len == sizeof(struct sockaddr_in);
376 }
377
378 int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr)
379 {
380         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss;
381         return addr->len && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr);
382 }
383
384 int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
385 {
386         return addr->ss.ss_family == AF_INET6 &&
387             addr->len == sizeof(struct sockaddr_in6);
388 }
389
390 int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
391 {
392         return (ast_sockaddr_is_ipv4(addr) &&
393                 ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr ==
394                 INADDR_ANY) ||
395             (ast_sockaddr_is_ipv6(addr) &&
396              IN6_IS_ADDR_UNSPECIFIED(&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr));
397 }
398
399 int ast_sockaddr_hash(const struct ast_sockaddr *addr)
400 {
401         /*
402          * For IPv4, return the IP address as-is. For IPv6, return the last 32
403          * bits.
404          */
405         switch (addr->ss.ss_family) {
406         case AF_INET:
407                 return ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr;
408         case AF_INET6:
409                 return ((uint32_t *)&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)[3];
410         default:
411                 ast_log(LOG_ERROR, "Unknown address family '%d'.\n",
412                         addr->ss.ss_family);
413                 return 0;
414         }
415 }
416
417 int ast_accept(int sockfd, struct ast_sockaddr *addr)
418 {
419         addr->len = sizeof(addr->ss);
420         return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
421 }
422
423 int ast_bind(int sockfd, const struct ast_sockaddr *addr)
424 {
425         return bind(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
426 }
427
428 int ast_connect(int sockfd, const struct ast_sockaddr *addr)
429 {
430         return connect(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
431 }
432
433 int ast_getsockname(int sockfd, struct ast_sockaddr *addr)
434 {
435         addr->len = sizeof(addr->ss);
436         return getsockname(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
437 }
438
439 ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags,
440                      struct ast_sockaddr *src_addr)
441 {
442         src_addr->len = sizeof(src_addr->ss);
443         return recvfrom(sockfd, buf, len, flags,
444                         (struct sockaddr *)&src_addr->ss, &src_addr->len);
445 }
446
447 ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags,
448                    const struct ast_sockaddr *dest_addr)
449 {
450         return sendto(sockfd, buf, len, flags,
451                       (const struct sockaddr *)&dest_addr->ss, dest_addr->len);
452 }
453
454 int ast_set_qos(int sockfd, int tos, int cos, const char *desc)
455 {
456         int res;
457         int proto_type = IPPROTO_IP; /* ipv4 values by default */
458         int dscp_field = IP_TOS;
459         struct ast_sockaddr addr;
460
461         /* if this is IPv6 we need to set the TCLASS instead of TOS */
462         if (!ast_getsockname(sockfd, &addr) && ast_sockaddr_is_ipv6(&addr)) {
463                 proto_type = IPPROTO_IPV6;
464                 dscp_field = IPV6_TCLASS;
465         }
466
467         if ((res = setsockopt(sockfd, proto_type, dscp_field, &tos, sizeof(tos)))) {
468                 ast_log(LOG_WARNING, "Unable to set %s TOS to %d (may be you have no "
469                         "root privileges): %s\n", desc, tos, strerror(errno));
470         } else if (tos) {
471                 ast_verb(2, "Using %s TOS bits %d\n", desc, tos);
472         }
473
474 #ifdef linux
475         if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos))) {
476                 ast_log(LOG_WARNING, "Unable to set %s CoS to %d: %s\n", desc, cos,
477                         strerror(errno));
478         } else if (cos) {
479                 ast_verb(2, "Using %s CoS mark %d\n", desc, cos);
480         }
481 #endif
482
483         return res;
484 }
485
486 int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
487                         struct sockaddr_in *sin, const char *file, int line, const char *func)
488 {
489         if (ast_sockaddr_isnull(addr)) {
490                 memset(sin, 0, sizeof(*sin));
491                 return 1;
492         }
493
494         if (addr->len != sizeof(*sin)) {
495                 ast_log(__LOG_ERROR, file, line, func, "Bad address cast to IPv4\n");
496                 return 0;
497         }
498
499         if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
500                 ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
501         }
502
503         *sin = *(struct sockaddr_in *)&addr->ss;
504         return 1;
505 }
506
507 void _ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin,
508                 const char *file, int line, const char *func)
509 {
510         memcpy(&addr->ss, sin, sizeof(*sin));
511
512         if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
513                 ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
514         }
515
516         addr->len = sizeof(*sin);
517 }