Merged revisions 332560 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_tmp->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         if ((format & AST_SOCKADDR_STR_REMOTE) == AST_SOCKADDR_STR_REMOTE) {
99                 char *p;
100                 if (ast_sockaddr_is_ipv6_link_local(sa) && (p = strchr(host, '%'))) {
101                         *p = '\0';
102                 }
103         }
104
105         switch ((format & AST_SOCKADDR_STR_FORMAT_MASK))  {
106         case AST_SOCKADDR_STR_DEFAULT:
107                 ast_str_set(&str, 0, sa_tmp->ss.ss_family == AF_INET6 ?
108                                 "[%s]:%s" : "%s:%s", host, port);
109                 break;
110         case AST_SOCKADDR_STR_ADDR:
111                 ast_str_set(&str, 0, "%s", host);
112                 break;
113         case AST_SOCKADDR_STR_HOST:
114                 ast_str_set(&str, 0,
115                             sa_tmp->ss.ss_family == AF_INET6 ? "[%s]" : "%s", host);
116                 break;
117         case AST_SOCKADDR_STR_PORT:
118                 ast_str_set(&str, 0, "%s", port);
119                 break;
120         default:
121                 ast_log(LOG_ERROR, "Invalid format\n");
122                 return "";
123         }
124
125         return ast_str_buffer(str);
126 }
127
128 int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
129 {
130         char *s = str;
131         char *orig_str = str;/* Original string in case the port presence is incorrect. */
132         char *host_end = NULL;/* Delay terminating the host in case the port presence is incorrect. */
133
134         ast_debug(5, "Splitting '%s' into...\n", str);
135         *host = NULL;
136         *port = NULL;
137         if (*s == '[') {
138                 *host = ++s;
139                 for (; *s && *s != ']'; ++s) {
140                 }
141                 if (*s == ']') {
142                         host_end = s;
143                         ++s;
144                 }
145                 if (*s == ':') {
146                         *port = s + 1;
147                 }
148         } else {
149                 *host = s;
150                 for (; *s; ++s) {
151                         if (*s == ':') {
152                                 if (*port) {
153                                         *port = NULL;
154                                         break;
155                                 } else {
156                                         *port = s;
157                                 }
158                         }
159                 }
160                 if (*port) {
161                         host_end = *port;
162                         ++*port;
163                 }
164         }
165
166         switch (flags & PARSE_PORT_MASK) {
167         case PARSE_PORT_IGNORE:
168                 *port = NULL;
169                 break;
170         case PARSE_PORT_REQUIRE:
171                 if (*port == NULL) {
172                         ast_log(LOG_WARNING, "Port missing in %s\n", orig_str);
173                         return 0;
174                 }
175                 break;
176         case PARSE_PORT_FORBID:
177                 if (*port != NULL) {
178                         ast_log(LOG_WARNING, "Port disallowed in %s\n", orig_str);
179                         return 0;
180                 }
181                 break;
182         }
183
184         /* Can terminate the host string now if needed. */
185         if (host_end) {
186                 *host_end = '\0';
187         }
188         ast_debug(5, "...host '%s' and port '%s'.\n", *host, *port ? *port : "");
189         return 1;
190 }
191
192
193
194 int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
195 {
196         struct addrinfo hints;
197         struct addrinfo *res;
198         char *s;
199         char *host;
200         char *port;
201         int     e;
202
203         s = ast_strdupa(str);
204         if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
205                 return 0;
206         }
207
208         memset(&hints, 0, sizeof(hints));
209         /* Hint to get only one entry from getaddrinfo */
210         hints.ai_socktype = SOCK_DGRAM;
211
212 #ifdef AI_NUMERICSERV
213         hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
214 #else
215         hints.ai_flags = AI_NUMERICHOST;
216 #endif
217         if ((e = getaddrinfo(host, port, &hints, &res))) {
218                 if (e != EAI_NONAME) { /* if this was just a host name rather than a ip address, don't print error */
219                         ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
220                                 host, S_OR(port, "(null)"), gai_strerror(e));
221                 }
222                 return 0;
223         }
224
225         /*
226          * I don't see how this could be possible since we're not resolving host
227          * names. But let's be careful...
228          */
229         if (res->ai_next != NULL) {
230                 ast_log(LOG_WARNING, "getaddrinfo() returned multiple "
231                         "addresses. Ignoring all but the first.\n");
232         }
233
234         addr->len = res->ai_addrlen;
235         memcpy(&addr->ss, res->ai_addr, addr->len);
236
237         freeaddrinfo(res);
238
239         return 1;
240 }
241
242 int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
243                          int flags, int family)
244 {
245         struct addrinfo hints, *res, *ai;
246         char *s, *host, *port;
247         int     e, i, res_cnt;
248
249         if (!str) {
250                 return 0;
251         }
252
253         s = ast_strdupa(str);
254         if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
255                 return 0;
256         }
257
258         memset(&hints, 0, sizeof(hints));
259         hints.ai_family = family;
260         hints.ai_socktype = SOCK_DGRAM;
261
262         if ((e = getaddrinfo(host, port, &hints, &res))) {
263                 ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
264                         host, S_OR(port, "(null)"), gai_strerror(e));
265                 return 0;
266         }
267
268         res_cnt = 0;
269         for (ai = res; ai; ai = ai->ai_next) {
270                 res_cnt++;
271         }
272
273         if ((*addrs = ast_malloc(res_cnt * sizeof(struct ast_sockaddr))) == NULL) {
274                 res_cnt = 0;
275                 goto cleanup;
276         }
277
278         i = 0;
279         for (ai = res; ai; ai = ai->ai_next) {
280                 (*addrs)[i].len = ai->ai_addrlen;
281                 memcpy(&(*addrs)[i].ss, ai->ai_addr, ai->ai_addrlen);
282                 ++i;
283         }
284
285 cleanup:
286         freeaddrinfo(res);
287         return res_cnt;
288 }
289
290 int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
291 {
292         const struct ast_sockaddr *a_tmp, *b_tmp;
293         struct ast_sockaddr ipv4_mapped;
294
295         a_tmp = a;
296         b_tmp = b;
297
298         if (a_tmp->len != b_tmp->len) {
299                 if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
300                         a_tmp = &ipv4_mapped;
301                 } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
302                         b_tmp = &ipv4_mapped;
303                 }
304         }
305
306         if (a_tmp->len < b_tmp->len) {
307                 return -1;
308         } else if (a_tmp->len > b_tmp->len) {
309                 return 1;
310         }
311
312         return memcmp(&a_tmp->ss, &b_tmp->ss, a_tmp->len);
313 }
314
315 int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
316 {
317         const struct ast_sockaddr *a_tmp, *b_tmp;
318         struct ast_sockaddr ipv4_mapped;
319         const struct in_addr *ip4a, *ip4b;
320         const struct in6_addr *ip6a, *ip6b;
321         int ret = -1;
322
323         a_tmp = a;
324         b_tmp = b;
325
326         if (a_tmp->len != b_tmp->len) {
327                 if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
328                         a_tmp = &ipv4_mapped;
329                 } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
330                         b_tmp = &ipv4_mapped;
331                 }
332         }
333
334         if (a->len < b->len) {
335                 ret = -1;
336         } else if (a->len > b->len) {
337                 ret = 1;
338         }
339
340         switch (a_tmp->ss.ss_family) {
341         case AF_INET:
342                 ip4a = &((const struct sockaddr_in*)&a_tmp->ss)->sin_addr;
343                 ip4b = &((const struct sockaddr_in*)&b_tmp->ss)->sin_addr;
344                 ret = memcmp(ip4a, ip4b, sizeof(*ip4a));
345                 break;
346         case AF_INET6:
347                 ip6a = &((const struct sockaddr_in6*)&a_tmp->ss)->sin6_addr;
348                 ip6b = &((const struct sockaddr_in6*)&b_tmp->ss)->sin6_addr;
349                 ret = memcmp(ip6a, ip6b, sizeof(*ip6a));
350                 break;
351         }
352         return ret;
353 }
354
355 uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, int line, const char *func)
356 {
357         if (addr->ss.ss_family == AF_INET &&
358             addr->len == sizeof(struct sockaddr_in)) {
359                 return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port);
360         } else if (addr->ss.ss_family == AF_INET6 &&
361                  addr->len == sizeof(struct sockaddr_in6)) {
362                 return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port);
363         }
364         if (option_debug >= 1) {
365                 ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
366         }
367         return 0;
368 }
369
370 void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char *file, int line, const char *func)
371 {
372         if (addr->ss.ss_family == AF_INET &&
373             addr->len == sizeof(struct sockaddr_in)) {
374                 ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port);
375         } else if (addr->ss.ss_family == AF_INET6 &&
376                  addr->len == sizeof(struct sockaddr_in6)) {
377                 ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
378         } else if (option_debug >= 1) {
379                 ast_log(__LOG_DEBUG, file, line, func,
380                         "Not an IPv4 nor IPv6 address, cannot set port.\n");
381         }
382 }
383
384 uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
385 {
386         const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss;
387         return ntohl(sin->sin_addr.s_addr);
388 }
389
390 int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
391 {
392         return addr->ss.ss_family == AF_INET &&
393             addr->len == sizeof(struct sockaddr_in);
394 }
395
396 int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr)
397 {
398         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss;
399         return addr->len && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr);
400 }
401
402 int ast_sockaddr_is_ipv4_multicast(const struct ast_sockaddr *addr)
403 {
404         return ((ast_sockaddr_ipv4(addr) & 0xf0000000) == 0xe0000000);
405 }
406
407 int ast_sockaddr_is_ipv6_link_local(const struct ast_sockaddr *addr)
408 {
409         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss;
410         return ast_sockaddr_is_ipv6(addr) && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr);
411 }
412
413 int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
414 {
415         return addr->ss.ss_family == AF_INET6 &&
416             addr->len == sizeof(struct sockaddr_in6);
417 }
418
419 int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
420 {
421         union {
422                 struct sockaddr_storage ss;
423                 struct sockaddr_in sin;
424                 struct sockaddr_in6 sin6;
425         } tmp_addr = {
426                 .ss = addr->ss,
427         };
428
429         return (ast_sockaddr_is_ipv4(addr) && (tmp_addr.sin.sin_addr.s_addr == INADDR_ANY)) ||
430             (ast_sockaddr_is_ipv6(addr) && IN6_IS_ADDR_UNSPECIFIED(&tmp_addr.sin6.sin6_addr));
431 }
432
433 int ast_sockaddr_hash(const struct ast_sockaddr *addr)
434 {
435         /*
436          * For IPv4, return the IP address as-is. For IPv6, return the last 32
437          * bits.
438          */
439         switch (addr->ss.ss_family) {
440         case AF_INET:
441                 return ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr;
442         case AF_INET6:
443                 return ((uint32_t *)&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)[3];
444         default:
445                 ast_log(LOG_ERROR, "Unknown address family '%d'.\n",
446                         addr->ss.ss_family);
447                 return 0;
448         }
449 }
450
451 int ast_accept(int sockfd, struct ast_sockaddr *addr)
452 {
453         addr->len = sizeof(addr->ss);
454         return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
455 }
456
457 int ast_bind(int sockfd, const struct ast_sockaddr *addr)
458 {
459         return bind(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
460 }
461
462 int ast_connect(int sockfd, const struct ast_sockaddr *addr)
463 {
464         return connect(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
465 }
466
467 int ast_getsockname(int sockfd, struct ast_sockaddr *addr)
468 {
469         addr->len = sizeof(addr->ss);
470         return getsockname(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
471 }
472
473 ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags,
474                      struct ast_sockaddr *src_addr)
475 {
476         src_addr->len = sizeof(src_addr->ss);
477         return recvfrom(sockfd, buf, len, flags,
478                         (struct sockaddr *)&src_addr->ss, &src_addr->len);
479 }
480
481 ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags,
482                    const struct ast_sockaddr *dest_addr)
483 {
484         return sendto(sockfd, buf, len, flags,
485                       (const struct sockaddr *)&dest_addr->ss, dest_addr->len);
486 }
487
488 int ast_set_qos(int sockfd, int tos, int cos, const char *desc)
489 {
490         int res = 0;
491         int set_tos;
492         int set_tclass;
493         struct ast_sockaddr addr;
494
495         /* If the sock address is IPv6, the TCLASS field must be set. */
496         set_tclass = !ast_getsockname(sockfd, &addr) && ast_sockaddr_is_ipv6(&addr) ? 1 : 0;
497
498         /* If the the sock address is IPv4 or (IPv6 set to any address [::]) set TOS bits */
499         set_tos = (!set_tclass || (set_tclass && ast_sockaddr_is_any(&addr))) ? 1 : 0;
500
501         if (set_tos) {
502                 if ((res = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) {
503                         ast_log(LOG_WARNING, "Unable to set %s DSCP TOS value to %d (may be you have no "
504                                 "root privileges): %s\n", desc, tos, strerror(errno));
505                 } else if (tos) {
506                         ast_verb(2, "Using %s TOS bits %d\n", desc, tos);
507                 }
508         }
509
510 #if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6)
511         if (set_tclass) {
512                 if (!ast_getsockname(sockfd, &addr) && ast_sockaddr_is_ipv6(&addr)) {
513                         if ((res = setsockopt(sockfd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)))) {
514                                 ast_log(LOG_WARNING, "Unable to set %s DSCP TCLASS field to %d (may be you have no "
515                                         "root privileges): %s\n", desc, tos, strerror(errno));
516                         } else if (tos) {
517                                 ast_verb(2, "Using %s TOS bits %d in TCLASS field.\n", desc, tos);
518                         }
519                 }
520         }
521 #endif
522
523 #ifdef linux
524         if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos))) {
525                 ast_log(LOG_WARNING, "Unable to set %s CoS to %d: %s\n", desc, cos,
526                         strerror(errno));
527         } else if (cos) {
528                 ast_verb(2, "Using %s CoS mark %d\n", desc, cos);
529         }
530 #endif
531
532         return res;
533 }
534
535 int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
536                         struct sockaddr_in *sin, const char *file, int line, const char *func)
537 {
538         if (ast_sockaddr_isnull(addr)) {
539                 memset(sin, 0, sizeof(*sin));
540                 return 1;
541         }
542
543         if (addr->len != sizeof(*sin)) {
544                 ast_log(__LOG_ERROR, file, line, func, "Bad address cast to IPv4\n");
545                 return 0;
546         }
547
548         if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
549                 ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
550         }
551
552         *sin = *(struct sockaddr_in *)&addr->ss;
553         return 1;
554 }
555
556 void _ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin,
557                 const char *file, int line, const char *func)
558 {
559         memcpy(&addr->ss, sin, sizeof(*sin));
560
561         if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
562                 ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
563         }
564
565         addr->len = sizeof(*sin);
566 }