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