diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/acl.c | 101 | ||||
-rw-r--r-- | main/app.c | 10 | ||||
-rw-r--r-- | main/config.c | 16 | ||||
-rw-r--r-- | main/dnsmgr.c | 43 | ||||
-rw-r--r-- | main/http.c | 55 | ||||
-rw-r--r-- | main/manager.c | 91 | ||||
-rw-r--r-- | main/netsock2.c | 499 | ||||
-rw-r--r-- | main/rtp_engine.c | 155 | ||||
-rw-r--r-- | main/tcptls.c | 58 |
9 files changed, 823 insertions, 205 deletions
diff --git a/main/acl.c b/main/acl.c index caa1d56f0..082048a16 100644 --- a/main/acl.c +++ b/main/acl.c @@ -48,7 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/srv.h" #if (!defined(SOLARIS) && !defined(HAVE_GETIFADDRS)) -static int get_local_address(struct in_addr *ourip) +static int get_local_address(struct ast_sockaddr *ourip) { return -1; } @@ -112,7 +112,7 @@ static void score_address(const struct sockaddr_in *sin, struct in_addr *best_ad } } -static int get_local_address(struct in_addr *ourip) +static int get_local_address(struct ast_sockaddr *ourip) { int s, res = -1; #ifdef SOLARIS @@ -207,7 +207,9 @@ static int get_local_address(struct in_addr *ourip) #endif /* BSD_OR_LINUX */ if (res == 0 && ourip) { - memcpy(ourip, &best_addr, sizeof(*ourip)); + ast_sockaddr_setnull(ourip); + ourip->ss.ss_family = AF_INET; + ((struct sockaddr_in *)&ourip->ss)->sin_addr = best_addr; } return res; } @@ -372,27 +374,49 @@ int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin) return res; } -int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service) +static int resolve_first(struct ast_sockaddr *addr, const char *name, int flag, + int family) +{ + struct ast_sockaddr *addrs; + int addrs_cnt; + + addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family); + if (addrs_cnt > 0) { + if (addrs_cnt > 1) { + ast_debug(1, "Multiple addresses. Using the first only\n"); + } + ast_sockaddr_copy(addr, &addrs[0]); + ast_free(addrs); + } else { + ast_log(LOG_WARNING, "Unable to lookup '%s'\n", name); + return -1; + } + + return 0; +} + +int ast_get_ip_or_srv(struct ast_sockaddr *addr, const char *value, const char *service) { - struct hostent *hp; - struct ast_hostent ahp; char srv[256]; char host[256]; - int tportno = ntohs(sin->sin_port); + int srv_ret = 0; + int tportno; + if (service) { snprintf(srv, sizeof(srv), "%s.%s", service, value); - if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) { - sin->sin_port = htons(tportno); + if ((srv_ret = ast_get_srv(NULL, host, sizeof(host), &tportno, srv)) > 0) { value = host; } } - if ((hp = ast_gethostbyname(value, &ahp))) { - sin->sin_family = hp->h_addrtype; - memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr)); - } else { - ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value); + + if (resolve_first(addr, value, PARSE_PORT_FORBID, addr->ss.ss_family) != 0) { return -1; } + + if (srv_ret > 0) { + ast_sockaddr_set_port(addr, tportno); + } + return 0; } @@ -474,51 +498,53 @@ const char *ast_tos2str(unsigned int tos) return "unknown"; } -int ast_get_ip(struct sockaddr_in *sin, const char *value) +int ast_get_ip(struct ast_sockaddr *addr, const char *value) { - return ast_get_ip_or_srv(sin, value, NULL); + return ast_get_ip_or_srv(addr, value, NULL); } -int ast_ouraddrfor(struct in_addr *them, struct in_addr *us) +int ast_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us) { + int port; int s; - struct sockaddr_in sin; - socklen_t slen; - if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + port = ast_sockaddr_port(us); + + if ((s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET, + SOCK_DGRAM, 0)) < 0) { ast_log(LOG_ERROR, "Cannot create socket\n"); return -1; } - sin.sin_family = AF_INET; - sin.sin_port = htons(5060); - sin.sin_addr = *them; - if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) { + + if (ast_connect(s, them)) { ast_log(LOG_WARNING, "Cannot connect\n"); close(s); return -1; } - slen = sizeof(sin); - if (getsockname(s, (struct sockaddr *)&sin, &slen)) { + if (ast_getsockname(s, us)) { + ast_log(LOG_WARNING, "Cannot get socket name\n"); close(s); return -1; } close(s); - ast_debug(3, "Found IP address for this socket\n"); - *us = sin.sin_addr; + ast_debug(3, "For destination '%s', our source address is '%s'.\n", + ast_sockaddr_stringify_addr(them), + ast_sockaddr_stringify_addr(us)); + + ast_sockaddr_set_port(us, port); + return 0; } -int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr) +int ast_find_ourip(struct ast_sockaddr *ourip, const struct ast_sockaddr *bindaddr) { char ourhost[MAXHOSTNAMELEN] = ""; - struct ast_hostent ahp; - struct hostent *hp; - struct in_addr saddr; + struct ast_sockaddr root; /* just use the bind address if it is nonzero */ - if (ntohl(bindaddr.sin_addr.s_addr)) { - memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip)); + if (!ast_sockaddr_is_any(bindaddr)) { + ast_sockaddr_copy(ourip, bindaddr); ast_debug(3, "Attached to given IP address\n"); return 0; } @@ -526,15 +552,14 @@ int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr) if (gethostname(ourhost, sizeof(ourhost) - 1)) { ast_log(LOG_WARNING, "Unable to get hostname\n"); } else { - if ((hp = ast_gethostbyname(ourhost, &ahp))) { - memcpy(ourip, hp->h_addr, sizeof(*ourip)); - ast_debug(3, "Found one IP address based on local hostname %s.\n", ourhost); + if (resolve_first(ourip, ourhost, PARSE_PORT_FORBID, 0) == 0) { return 0; } } ast_debug(3, "Trying to check A.ROOT-SERVERS.NET and get our IP address for that connection\n"); /* A.ROOT-SERVERS.NET. */ - if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip)) { + if (!resolve_first(&root, "A.ROOT-SERVERS.NET", PARSE_PORT_FORBID, 0) && + !ast_ouraddrfor(&root, ourip)) { return 0; } return get_local_address(ourip); diff --git a/main/app.c b/main/app.c index a171f2611..050c4e238 100644 --- a/main/app.c +++ b/main/app.c @@ -1190,7 +1190,7 @@ unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, ch { int argc; char *scan, *wasdelim = NULL; - int paren = 0, quote = 0; + int paren = 0, quote = 0, bracket = 0; if (!array || !arraylen) { return 0; @@ -1213,6 +1213,12 @@ unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, ch if (paren) { paren--; } + } else if (*scan == '[') { + bracket++; + } else if (*scan == ']') { + if (bracket) { + bracket--; + } } else if (*scan == '"' && delim != '"') { quote = quote ? 0 : 1; if (remove_chars) { @@ -1227,7 +1233,7 @@ unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, ch } else { scan++; } - } else if ((*scan == delim) && !paren && !quote) { + } else if ((*scan == delim) && !paren && !quote && !bracket) { wasdelim = scan; *scan++ = '\0'; break; diff --git a/main/config.c b/main/config.c index 9400abd8c..e1c51dcd6 100644 --- a/main/config.c +++ b/main/config.c @@ -47,6 +47,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/astobj2.h" #include "asterisk/strings.h" /* for the ast_str_*() API */ +#include "asterisk/netsock2.h" #define MAX_NESTED_COMMENTS 128 #define COMMENT_START ";--" @@ -2386,7 +2387,20 @@ int ast_parse_arg(const char *arg, enum ast_parse_flags flags, result ? *result : x, error); break; } - case PARSE_INADDR: + case PARSE_ADDR: + { + struct ast_sockaddr *addr = (struct ast_sockaddr *)p_result; + + if (!ast_sockaddr_parse(addr, arg, flags & PARSE_PORT_MASK)) { + error = 1; + } + + ast_debug(3, "extract addr from %s gives %s(%d)\n", + arg, ast_sockaddr_stringify(addr), error); + + break; + } + case PARSE_INADDR: /* TODO Remove this (use PARSE_ADDR instead). */ { char *port, *buf; struct sockaddr_in _sa_buf; /* buffer for the result */ diff --git a/main/dnsmgr.c b/main/dnsmgr.c index ca181e3f2..29ac4e30f 100644 --- a/main/dnsmgr.c +++ b/main/dnsmgr.c @@ -51,7 +51,7 @@ static pthread_t refresh_thread = AST_PTHREADT_NULL; struct ast_dnsmgr_entry { /*! where we will store the resulting IP address and port number */ - struct sockaddr_in *result; + struct ast_sockaddr *result; /*! SRV record to lookup, if provided. Composed of service, protocol, and domain name: _Service._Proto.Name */ char *service; /*! Set to 1 if the entry changes */ @@ -83,7 +83,7 @@ static struct refresh_info master_refresh_info = { .verbose = 0, }; -struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct sockaddr_in *result, const char *service) +struct ast_dnsmgr_entry *ast_dnsmgr_get(const char *name, struct ast_sockaddr *result, const char *service) { struct ast_dnsmgr_entry *entry; int total_size = sizeof(*entry) + strlen(name) + (service ? strlen(service) + 1 : 0); @@ -120,10 +120,7 @@ void ast_dnsmgr_release(struct ast_dnsmgr_entry *entry) ast_free(entry); } -/* - * Allocate a new DNS manager entry and perform the initial lookup before returning - */ -int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_dnsmgr_entry **dnsmgr, const char *service) +int ast_dnsmgr_lookup(const char *name, struct ast_sockaddr *result, struct ast_dnsmgr_entry **dnsmgr, const char *service) { if (ast_strlen_zero(name) || !result || !dnsmgr) return -1; @@ -131,13 +128,6 @@ int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_d if (*dnsmgr && !strcasecmp((*dnsmgr)->name, name)) return 0; - /* if it's actually an IP address and not a name, - there's no need for a managed lookup */ - if (inet_aton(name, &result->sin_addr)) { - result->sin_family = AF_INET; - return 0; - } - ast_verb(4, "doing dnsmgr_lookup for '%s'\n", name); /* do a lookup now but add a manager so it will automagically get updated in the background */ @@ -157,25 +147,26 @@ int ast_dnsmgr_lookup(const char *name, struct sockaddr_in *result, struct ast_d */ static int dnsmgr_refresh(struct ast_dnsmgr_entry *entry, int verbose) { - char iabuf[INET_ADDRSTRLEN]; - char iabuf2[INET_ADDRSTRLEN]; - struct sockaddr_in tmp; + struct ast_sockaddr tmp; int changed = 0; - + ast_mutex_lock(&entry->lock); if (verbose) ast_verb(3, "refreshing '%s'\n", entry->name); memset(&tmp, 0, sizeof(tmp)); - tmp.sin_port = entry->result->sin_port; - - if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service) && inaddrcmp(&tmp, entry->result)) { - ast_copy_string(iabuf, ast_inet_ntoa(entry->result->sin_addr), sizeof(iabuf)); - ast_copy_string(iabuf2, ast_inet_ntoa(tmp.sin_addr), sizeof(iabuf2)); - ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s:%d to %s:%d\n", - entry->name, iabuf, ntohs(entry->result->sin_port), iabuf2, ntohs(tmp.sin_port)); - *entry->result = tmp; - changed = entry->changed = 1; + + if (!ast_get_ip_or_srv(&tmp, entry->name, entry->service)) { + if (!ast_sockaddr_port(&tmp)) + ast_sockaddr_set_port(&tmp, ast_sockaddr_port(entry->result)); + if (ast_sockaddr_cmp(&tmp, entry->result)) { + ast_log(LOG_NOTICE, "dnssrv: host '%s' changed from %s to %s\n", + entry->name, ast_sockaddr_stringify(entry->result), + ast_sockaddr_stringify(&tmp)); + + ast_sockaddr_copy(entry->result, &tmp); + changed = entry->changed = 1; + } } ast_mutex_unlock(&entry->lock); diff --git a/main/http.c b/main/http.c index dcbfc4d66..6390297e5 100644 --- a/main/http.c +++ b/main/http.c @@ -316,12 +316,12 @@ static int httpstatus_callback(struct ast_tcptls_session_instance *ser, ast_str_append(&out, 0, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix); ast_str_append(&out, 0, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n", - ast_inet_ntoa(http_desc.old_address.sin_addr)); - ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n", - ntohs(http_desc.old_address.sin_port)); + ast_sockaddr_stringify_addr(&http_desc.old_address)); + ast_str_append(&out, 0, "<tr><td><i>Bind Port</i></td><td><b>%s</b></td></tr>\r\n", + ast_sockaddr_stringify_port(&http_desc.old_address)); if (http_tls_cfg.enabled) { - ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%d</b></td></tr>\r\n", - ntohs(https_desc.old_address.sin_port)); + ast_str_append(&out, 0, "<tr><td><i>SSL Bind Port</i></td><td><b>%s</b></td></tr>\r\n", + ast_sockaddr_stringify_port(&https_desc.old_address)); } ast_str_append(&out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n"); for (v = get_vars; v; v = v->next) { @@ -989,6 +989,8 @@ static int __ast_http_load(int reload) char newprefix[MAX_PREFIX] = ""; struct http_uri_redirect *redirect; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; + struct sockaddr_in tmp = {0,}; + struct sockaddr_in tmp2 = {0,}; cfg = ast_config_load2("http.conf", "http", config_flags); if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { @@ -996,11 +998,13 @@ static int __ast_http_load(int reload) } /* default values */ - memset(&http_desc.local_address, 0, sizeof(http_desc.local_address)); - http_desc.local_address.sin_port = htons(8088); + tmp.sin_family = AF_INET; + tmp.sin_port = htons(8088); + ast_sockaddr_from_sin(&http_desc.local_address, &tmp); - memset(&https_desc.local_address, 0, sizeof(https_desc.local_address)); - https_desc.local_address.sin_port = htons(8089); + tmp2.sin_family = AF_INET; + tmp2.sin_port = htons(8089); + ast_sockaddr_from_sin(&https_desc.local_address, &tmp2); http_tls_cfg.enabled = 0; if (http_tls_cfg.certfile) { @@ -1038,10 +1042,15 @@ static int __ast_http_load(int reload) } else if (!strcasecmp(v->name, "enablestatic")) { newenablestatic = ast_true(v->value); } else if (!strcasecmp(v->name, "bindport")) { - http_desc.local_address.sin_port = htons(atoi(v->value)); + ast_sockaddr_set_port(&http_desc.local_address, + atoi(v->value)); } else if (!strcasecmp(v->name, "bindaddr")) { if ((hp = ast_gethostbyname(v->value, &ahp))) { - memcpy(&http_desc.local_address.sin_addr, hp->h_addr, sizeof(http_desc.local_address.sin_addr)); + ast_sockaddr_to_sin(&http_desc.local_address, + &tmp); + memcpy(&tmp.sin_addr, hp->h_addr, sizeof(tmp.sin_addr)); + ast_sockaddr_from_sin(&http_desc.local_address, + &tmp); } else { ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value); } @@ -1062,11 +1071,15 @@ static int __ast_http_load(int reload) ast_config_destroy(cfg); } /* if the https addres has not been set, default is the same as non secure http */ - if (!https_desc.local_address.sin_addr.s_addr) { - https_desc.local_address.sin_addr = http_desc.local_address.sin_addr; + ast_sockaddr_to_sin(&http_desc.local_address, &tmp); + ast_sockaddr_to_sin(&https_desc.local_address, &tmp2); + if (!tmp2.sin_addr.s_addr) { + tmp2.sin_addr = tmp.sin_addr; + ast_sockaddr_from_sin(&https_desc.local_address, &tmp2); } - if (enabled) { - http_desc.local_address.sin_family = https_desc.local_address.sin_family = AF_INET; + if (!enabled) { + http_desc.local_address.ss.ss_family = 0; + https_desc.local_address.ss.ss_family = 0; } if (strcmp(prefix, newprefix)) { ast_copy_string(prefix, newprefix, sizeof(prefix)); @@ -1084,6 +1097,7 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a { struct ast_http_uri *urih; struct http_uri_redirect *redirect; + struct sockaddr_in tmp; switch (cmd) { case CLI_INIT: @@ -1101,16 +1115,17 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a } ast_cli(a->fd, "HTTP Server Status:\n"); ast_cli(a->fd, "Prefix: %s\n", prefix); - if (!http_desc.old_address.sin_family) { + ast_sockaddr_to_sin(&http_desc.old_address, &tmp); + if (!tmp.sin_family) { ast_cli(a->fd, "Server Disabled\n\n"); } else { ast_cli(a->fd, "Server Enabled and Bound to %s:%d\n\n", - ast_inet_ntoa(http_desc.old_address.sin_addr), - ntohs(http_desc.old_address.sin_port)); + ast_inet_ntoa(tmp.sin_addr), ntohs(tmp.sin_port)); if (http_tls_cfg.enabled) { + ast_sockaddr_to_sin(&https_desc.old_address, &tmp); ast_cli(a->fd, "HTTPS Server Enabled and Bound to %s:%d\n\n", - ast_inet_ntoa(https_desc.old_address.sin_addr), - ntohs(https_desc.old_address.sin_port)); + ast_inet_ntoa(tmp.sin_addr), + ntohs(tmp.sin_port)); } } diff --git a/main/manager.c b/main/manager.c index dffe92a15..5c8f893af 100644 --- a/main/manager.c +++ b/main/manager.c @@ -1984,7 +1984,8 @@ static enum ast_security_event_transport_type mansession_get_transport(const str static struct sockaddr_in *mansession_encode_sin_local(const struct mansession *s, struct sockaddr_in *sin_local) { - *sin_local = s->tcptls_session->parent->local_address; + ast_sockaddr_to_sin(&s->tcptls_session->parent->local_address, + sin_local); return sin_local; } @@ -4598,14 +4599,18 @@ static int do_message(struct mansession *s) static void *session_do(void *data) { struct ast_tcptls_session_instance *ser = data; - struct mansession_session *session = build_mansession(ser->remote_address); + struct mansession_session *session; struct mansession s = { .tcptls_session = data, }; int flags; int res; + struct sockaddr_in ser_remote_address_tmp; struct protoent *p; + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + session = build_mansession(ser_remote_address_tmp); + if (session == NULL) { goto done; } @@ -4640,7 +4645,7 @@ static void *session_do(void *data) /* these fields duplicate those in the 'ser' structure */ session->fd = s.fd = ser->fd; session->f = s.f = ser->f; - session->sin = ser->remote_address; + session->sin = ser_remote_address_tmp; s.session = session; AST_LIST_HEAD_INIT_NOLOCK(&session->datastores); @@ -5912,17 +5917,35 @@ out_401: static int manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return generic_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = generic_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return generic_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = generic_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return generic_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = generic_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static struct ast_http_uri rawmanuri = { @@ -5953,17 +5976,35 @@ static struct ast_http_uri managerxmluri = { /* Callback with Digest authentication */ static int auth_manager_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return auth_http_callback(ser, method, FORMAT_HTML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = auth_http_callback(ser, method, FORMAT_HTML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int auth_mxml_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return auth_http_callback(ser, method, FORMAT_XML, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = auth_http_callback(ser, method, FORMAT_XML, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static int auth_rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers) { - return auth_http_callback(ser, method, FORMAT_RAW, &ser->remote_address, uri, get_params, headers); + int retval; + struct sockaddr_in ser_remote_address_tmp; + + ast_sockaddr_to_sin(&ser->remote_address, &ser_remote_address_tmp); + retval = auth_http_callback(ser, method, FORMAT_RAW, &ser_remote_address_tmp, uri, get_params, headers); + ast_sockaddr_from_sin(&ser->remote_address, &ser_remote_address_tmp); + return retval; } static struct ast_http_uri arawmanuri = { @@ -6049,12 +6090,10 @@ static char *handle_manager_show_settings(struct ast_cli_entry *e, int cmd, stru ast_cli(a->fd, "----------------\n"); ast_cli(a->fd, FORMAT, "Manager (AMI):", AST_CLI_YESNO(manager_enabled)); ast_cli(a->fd, FORMAT, "Web Manager (AMI/HTTP):", AST_CLI_YESNO(webmanager_enabled)); - ast_cli(a->fd, FORMAT, "TCP Bindaddress:", ast_inet_ntoa(ami_desc.local_address.sin_addr)); - ast_cli(a->fd, FORMAT2, "TCP Port:", ntohs(ami_desc.local_address.sin_port)); + ast_cli(a->fd, FORMAT, "TCP Bindaddress:", ast_sockaddr_stringify(&ami_desc.local_address)); ast_cli(a->fd, FORMAT2, "HTTP Timeout (minutes):", httptimeout); ast_cli(a->fd, FORMAT, "TLS Enable:", AST_CLI_YESNO(ami_tls_cfg.enabled)); - ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ast_inet_ntoa(amis_desc.local_address.sin_addr)); - ast_cli(a->fd, FORMAT2, "TLS Port:", ntohs(amis_desc.local_address.sin_port)); + ast_cli(a->fd, FORMAT, "TLS Bindaddress:", ast_sockaddr_stringify(&amis_desc.local_address)); ast_cli(a->fd, FORMAT, "TLS Certfile:", ami_tls_cfg.certfile); ast_cli(a->fd, FORMAT, "TLS Privatekey:", ami_tls_cfg.pvtfile); ast_cli(a->fd, FORMAT, "TLS Cipher:", ami_tls_cfg.cipher); @@ -6093,6 +6132,8 @@ static int __init_manager(int reload) struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; char a1[256]; char a1_hash[256]; + struct sockaddr_in ami_desc_local_address_tmp = { 0, }; + struct sockaddr_in amis_desc_local_address_tmp = { 0, }; manager_enabled = 0; @@ -6151,10 +6192,8 @@ static int __init_manager(int reload) /* default values */ ast_copy_string(global_realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(global_realm)); - memset(&ami_desc.local_address, 0, sizeof(struct sockaddr_in)); - memset(&amis_desc.local_address, 0, sizeof(amis_desc.local_address)); - amis_desc.local_address.sin_port = htons(5039); - ami_desc.local_address.sin_port = htons(DEFAULT_MANAGER_PORT); + amis_desc_local_address_tmp.sin_port = htons(5039); + ami_desc_local_address_tmp.sin_port = htons(DEFAULT_MANAGER_PORT); ami_tls_cfg.enabled = 0; if (ami_tls_cfg.certfile) { @@ -6186,11 +6225,12 @@ static int __init_manager(int reload) } else if (!strcasecmp(var->name, "webenabled")) { webmanager_enabled = ast_true(val); } else if (!strcasecmp(var->name, "port")) { - ami_desc.local_address.sin_port = htons(atoi(val)); + ami_desc_local_address_tmp.sin_port = htons(atoi(val)); } else if (!strcasecmp(var->name, "bindaddr")) { - if (!inet_aton(val, &ami_desc.local_address.sin_addr)) { + if (!inet_aton(val, &ami_desc_local_address_tmp.sin_addr)) { ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); - memset(&ami_desc.local_address.sin_addr, 0, sizeof(ami_desc.local_address.sin_addr)); + memset(&ami_desc_local_address_tmp.sin_addr, 0, + sizeof(ami_desc_local_address_tmp.sin_addr)); } } else if (!strcasecmp(var->name, "brokeneventsaction")) { broken_events_action = ast_true(val); @@ -6228,15 +6268,18 @@ static int __init_manager(int reload) } if (manager_enabled) { - ami_desc.local_address.sin_family = AF_INET; + ami_desc_local_address_tmp.sin_family = AF_INET; } /* if the amis address has not been set, default is the same as non secure ami */ - if (!amis_desc.local_address.sin_addr.s_addr) { - amis_desc.local_address.sin_addr = ami_desc.local_address.sin_addr; + if (!amis_desc_local_address_tmp.sin_addr.s_addr) { + amis_desc_local_address_tmp.sin_addr = + ami_desc_local_address_tmp.sin_addr; } if (ami_tls_cfg.enabled) { - amis_desc.local_address.sin_family = AF_INET; + amis_desc_local_address_tmp.sin_family = AF_INET; } + ast_sockaddr_from_sin(&ami_desc.local_address, &ami_desc_local_address_tmp); + ast_sockaddr_from_sin(&amis_desc.local_address, &amis_desc_local_address_tmp); AST_RWLIST_WRLOCK(&users); diff --git a/main/netsock2.c b/main/netsock2.c new file mode 100644 index 000000000..4d93a911b --- /dev/null +++ b/main/netsock2.c @@ -0,0 +1,499 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Viagénie <asteriskv6@viagenie.ca> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Network socket handling + * + * \author Viagénie <asteriskv6@viagenie.ca> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/config.h" +#include "asterisk/netsock2.h" +#include "asterisk/utils.h" +#include "asterisk/threadstorage.h" + +static int ast_sockaddr_ipv4_mapped(const struct ast_sockaddr *addr, struct ast_sockaddr *ast_mapped) +{ + const struct sockaddr_in6 *sin6; + struct sockaddr_in sin4; + + if (!ast_sockaddr_is_ipv6(addr)) { + return 0; + } + + if (!ast_sockaddr_is_ipv4_mapped(addr)) { + return 0; + } + + sin6 = (const struct sockaddr_in6*)&addr->ss; + + memset(&sin4, 0, sizeof(sin4)); + sin4.sin_family = AF_INET; + sin4.sin_port = sin6->sin6_port; + sin4.sin_addr.s_addr = ((uint32_t *)&sin6->sin6_addr)[3]; + + ast_sockaddr_from_sin(ast_mapped, &sin4); + + return 1; +} + + +AST_THREADSTORAGE(ast_sockaddr_stringify_buf); + +char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format) +{ + struct ast_sockaddr sa_ipv4; + const struct ast_sockaddr *sa_tmp; + char host[NI_MAXHOST]; + char port[NI_MAXSERV]; + struct ast_str *str; + int e; + static const size_t size = sizeof(host) - 1 + sizeof(port) - 1 + 4; + + + if (ast_sockaddr_isnull(sa)) { + return "(null)"; + } + + if (!(str = ast_str_thread_get(&ast_sockaddr_stringify_buf, size))) { + return ""; + } + + if (ast_sockaddr_ipv4_mapped(sa, &sa_ipv4)) { + sa_tmp = &sa_ipv4; + } else { + sa_tmp = sa; + } + + if ((e = getnameinfo((struct sockaddr *)&sa_tmp->ss, sa->len, + format & AST_SOCKADDR_STR_ADDR ? host : NULL, + format & AST_SOCKADDR_STR_ADDR ? sizeof(host) : 0, + format & AST_SOCKADDR_STR_PORT ? port : 0, + format & AST_SOCKADDR_STR_PORT ? sizeof(port): 0, + NI_NUMERICHOST | NI_NUMERICSERV))) { + ast_log(LOG_ERROR, "getnameinfo(): %s\n", gai_strerror(e)); + return ""; + } + + switch (format) { + case AST_SOCKADDR_STR_DEFAULT: + ast_str_set(&str, 0, sa_tmp->ss.ss_family == AF_INET6 ? + "[%s]:%s" : "%s:%s", host, port); + break; + case AST_SOCKADDR_STR_ADDR: + ast_str_set(&str, 0, "%s", host); + break; + case AST_SOCKADDR_STR_HOST: + ast_str_set(&str, 0, + sa_tmp->ss.ss_family == AF_INET6 ? "[%s]" : "%s", host); + break; + case AST_SOCKADDR_STR_PORT: + ast_str_set(&str, 0, "%s", port); + break; + default: + ast_log(LOG_ERROR, "Invalid format\n"); + return ""; + } + + return ast_str_buffer(str); +} + +int static _ast_sockaddr_parse(char *str, char **host, char **port, int flags) +{ + char *s = str; + + ast_debug(5, "Splitting '%s' gives...\n", str); + *host = NULL; + *port = NULL; + if (*s == '[') { + *host = ++s; + for (; *s && *s != ']'; ++s) { + } + if (*s == ']') { + *s++ = '\0'; + } + if (*s == ':') { + *port = s + 1; + } + } else { + *host = s; + for (; *s; ++s) { + if (*s == ':') { + if (*port) { + *port = NULL; + break; + } else { + *port = s; + } + } + } + if (*port) { + **port = '\0'; + ++*port; + } + } + ast_debug(5, "...host '%s' and port '%s'.\n", *host, *port); + + switch (flags & PARSE_PORT_MASK) { + case PARSE_PORT_IGNORE: + *port = NULL; + break; + case PARSE_PORT_REQUIRE: + if (*port == NULL) { + ast_log(LOG_WARNING, "missing port\n"); + return 0; + } + break; + case PARSE_PORT_FORBID: + if (*port != NULL) { + ast_log(LOG_WARNING, "port disallowed\n"); + return 0; + } + break; + } + + return 1; +} + + + +int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags) +{ + struct addrinfo hints; + struct addrinfo *res; + char *s; + char *host; + char *port; + int e; + + s = ast_strdupa(str); + if (!_ast_sockaddr_parse(s, &host, &port, flags)) { + return 0; + } + + memset(&hints, 0, sizeof(hints)); + /* Hint to get only one entry from getaddrinfo */ + hints.ai_socktype = SOCK_DGRAM; + + hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + if ((e = getaddrinfo(host, port, &hints, &res))) { + ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n", + host, S_OR(port, "(null)"), gai_strerror(e)); + return 0; + } + + /* + * I don't see how this could be possible since we're not resolving host + * names. But let's be careful... + */ + if (res->ai_next != NULL) { + ast_log(LOG_WARNING, "getaddrinfo() returned multiple " + "addresses. Ignoring all but the first.\n"); + } + + addr->len = res->ai_addrlen; + memcpy(&addr->ss, res->ai_addr, addr->len); + + freeaddrinfo(res); + + return 1; +} + +int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, + int flags, int family) +{ + struct addrinfo hints, *res, *ai; + char *s, *host, *port; + int e, i, res_cnt; + + s = ast_strdupa(str); + if (!_ast_sockaddr_parse(s, &host, &port, flags)) { + return 0; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_DGRAM; + + if ((e = getaddrinfo(host, port, &hints, &res))) { + ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n", + host, S_OR(port, "(null)"), gai_strerror(e)); + return 0; + } + + res_cnt = 0; + for (ai = res; ai; ai = ai->ai_next) { + res_cnt++; + } + + if ((*addrs = ast_malloc(res_cnt * sizeof(struct ast_sockaddr))) == NULL) { + res_cnt = 0; + goto cleanup; + } + + i = 0; + for (ai = res; ai; ai = ai->ai_next) { + (*addrs)[i].len = ai->ai_addrlen; + memcpy(&(*addrs)[i].ss, ai->ai_addr, ai->ai_addrlen); + ++i; + } + +cleanup: + freeaddrinfo(res); + return res_cnt; +} + +int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b) +{ + const struct ast_sockaddr *a_tmp, *b_tmp; + struct ast_sockaddr ipv4_mapped; + + a_tmp = a; + b_tmp = b; + + if (a_tmp->len != b_tmp->len) { + if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) { + a_tmp = &ipv4_mapped; + } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) { + b_tmp = &ipv4_mapped; + } + } + + if (a_tmp->len < b_tmp->len) { + return -1; + } else if (a_tmp->len > b_tmp->len) { + return 1; + } + + return memcmp(&a_tmp->ss, &b_tmp->ss, a_tmp->len); +} + +int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b) +{ + const struct ast_sockaddr *a_tmp, *b_tmp; + struct ast_sockaddr ipv4_mapped; + const struct in_addr *ip4a, *ip4b; + const struct in6_addr *ip6a, *ip6b; + int ret = -1; + + a_tmp = a; + b_tmp = b; + + if (a_tmp->len != b_tmp->len) { + if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) { + a_tmp = &ipv4_mapped; + } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) { + b_tmp = &ipv4_mapped; + } + } + + if (a->len < b->len) { + ret = -1; + } else if (a->len > b->len) { + ret = 1; + } + + switch (a_tmp->ss.ss_family) { + case AF_INET: + ip4a = &((const struct sockaddr_in*)&a_tmp->ss)->sin_addr; + ip4b = &((const struct sockaddr_in*)&b_tmp->ss)->sin_addr; + ret = memcmp(ip4a, ip4b, sizeof(*ip4a)); + break; + case AF_INET6: + ip6a = &((const struct sockaddr_in6*)&a_tmp->ss)->sin6_addr; + ip6b = &((const struct sockaddr_in6*)&b_tmp->ss)->sin6_addr; + ret = memcmp(ip6a, ip6b, sizeof(*ip6a)); + break; + } + return ret; +} + +uint16_t ast_sockaddr_port(const struct ast_sockaddr *addr) +{ + if (addr->ss.ss_family == AF_INET && + addr->len == sizeof(struct sockaddr_in)) { + return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port); + } else if (addr->ss.ss_family == AF_INET6 && + addr->len == sizeof(struct sockaddr_in6)) { + return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port); + } + ast_log(LOG_ERROR, "Not an IPv4 nor IPv6 address, cannot get port.\n"); + return 0; +} + +void ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port) +{ + if (addr->ss.ss_family == AF_INET && + addr->len == sizeof(struct sockaddr_in)) { + ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port); + } else if (addr->ss.ss_family == AF_INET6 && + addr->len == sizeof(struct sockaddr_in6)) { + ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port); + } else { + ast_log(LOG_ERROR, + "Not an IPv4 nor IPv6 address, cannot set port.\n"); + } +} + +uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr) +{ + const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss; + return ntohl(sin->sin_addr.s_addr); +} + +int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr) +{ + return addr->ss.ss_family == AF_INET && + addr->len == sizeof(struct sockaddr_in); +} + +int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr) +{ + const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss; + return addr->len && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr); +} + +int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr) +{ + return addr->ss.ss_family == AF_INET6 && + addr->len == sizeof(struct sockaddr_in6); +} + +int ast_sockaddr_is_any(const struct ast_sockaddr *addr) +{ + return (ast_sockaddr_is_ipv4(addr) && + ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr == + INADDR_ANY) || + (ast_sockaddr_is_ipv6(addr) && + IN6_IS_ADDR_UNSPECIFIED(&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)); +} + +int ast_sockaddr_hash(const struct ast_sockaddr *addr) +{ + /* + * For IPv4, return the IP address as-is. For IPv6, return the last 32 + * bits. + */ + switch (addr->ss.ss_family) { + case AF_INET: + return ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr; + case AF_INET6: + return ((uint32_t *)&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)[3]; + default: + ast_log(LOG_ERROR, "Unknown address family '%d'.\n", + addr->ss.ss_family); + return 0; + } +} + +int ast_accept(int sockfd, struct ast_sockaddr *addr) +{ + addr->len = sizeof(addr->ss); + return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len); +} + +int ast_bind(int sockfd, const struct ast_sockaddr *addr) +{ + return bind(sockfd, (const struct sockaddr *)&addr->ss, addr->len); +} + +int ast_connect(int sockfd, const struct ast_sockaddr *addr) +{ + return connect(sockfd, (const struct sockaddr *)&addr->ss, addr->len); +} + +int ast_getsockname(int sockfd, struct ast_sockaddr *addr) +{ + addr->len = sizeof(addr->ss); + return getsockname(sockfd, (struct sockaddr *)&addr->ss, &addr->len); +} + +ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags, + struct ast_sockaddr *src_addr) +{ + src_addr->len = sizeof(src_addr->ss); + return recvfrom(sockfd, buf, len, flags, + (struct sockaddr *)&src_addr->ss, &src_addr->len); +} + +ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags, + const struct ast_sockaddr *dest_addr) +{ + return sendto(sockfd, buf, len, flags, + (const struct sockaddr *)&dest_addr->ss, dest_addr->len); +} + +int ast_set_qos(int sockfd, int tos, int cos, const char *desc) +{ + int res; + + if ((res = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) { + ast_log(LOG_WARNING, "Unable to set %s TOS to %d (may be you have no " + "root privileges): %s\n", desc, tos, strerror(errno)); + } else if (tos) { + ast_verb(2, "Using %s TOS bits %d\n", desc, tos); + } + +#ifdef linux + if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos))) { + ast_log(LOG_WARNING, "Unable to set %s CoS to %d: %s\n", desc, cos, + strerror(errno)); + } else if (cos) { + ast_verb(2, "Using %s CoS mark %d\n", desc, cos); + } +#endif + + return res; +} + +int ast_sockaddr_to_sin(const struct ast_sockaddr *addr, + struct sockaddr_in *sin) +{ + if (ast_sockaddr_isnull(addr)) { + memset(sin, 0, sizeof(*sin)); + return 1; + } + + if (addr->len != sizeof(*sin)) { + ast_log(LOG_ERROR, "Bad address cast to IPv4\n"); + return 0; + } + + if (addr->ss.ss_family != AF_INET) { + ast_log(LOG_DEBUG, "Address family is not AF_INET\n"); + } + + *sin = *(struct sockaddr_in *)&addr->ss; + return 1; +} + +void ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin) +{ + *((struct sockaddr_in *)&addr->ss) = *sin; + + if (addr->ss.ss_family != AF_INET) { + ast_log(LOG_DEBUG, "Address family is not AF_INET\n"); + } + + addr->len = sizeof(*sin); +} diff --git a/main/rtp_engine.c b/main/rtp_engine.c index eeaa008a8..d23056b5f 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/pbx.h" #include "asterisk/translate.h" +#include "asterisk/netsock2.h" struct ast_srtp_res *res_srtp = NULL; struct ast_srtp_policy_res *res_srtp_policy = NULL; @@ -51,11 +52,11 @@ struct ast_rtp_instance { /*! RTP properties that have been set and their value */ int properties[AST_RTP_PROPERTY_MAX]; /*! Address that we are expecting RTP to come in to */ - struct sockaddr_in local_address; + struct ast_sockaddr local_address; /*! Address that we are sending RTP to */ - struct sockaddr_in remote_address; + struct ast_sockaddr remote_address; /*! Alternate address that we are receiving RTP from */ - struct sockaddr_in alt_remote_address; + struct ast_sockaddr alt_remote_address; /*! Instance that we are bridged to if doing remote or local bridging */ struct ast_rtp_instance *bridged; /*! Payload and packetization information */ @@ -294,9 +295,11 @@ int ast_rtp_instance_destroy(struct ast_rtp_instance *instance) return 0; } -struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, struct sched_context *sched, struct sockaddr_in *sin, void *data) +struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, + struct sched_context *sched, const struct ast_sockaddr *sa, + void *data) { - struct sockaddr_in address = { 0, }; + struct ast_sockaddr address = {{0,}}; struct ast_rtp_instance *instance = NULL; struct ast_rtp_engine *engine = NULL; @@ -331,11 +334,8 @@ struct ast_rtp_instance *ast_rtp_instance_new(const char *engine_name, struct sc return NULL; } instance->engine = engine; - instance->local_address.sin_family = AF_INET; - instance->local_address.sin_addr = sin->sin_addr; - instance->remote_address.sin_family = AF_INET; - address.sin_family = AF_INET; - address.sin_addr = sin->sin_addr; + ast_sockaddr_copy(&instance->local_address, sa); + ast_sockaddr_copy(&address, sa); ast_debug(1, "Using engine '%s' for RTP instance '%p'\n", engine->name, instance); @@ -371,17 +371,17 @@ struct ast_frame *ast_rtp_instance_read(struct ast_rtp_instance *instance, int r return instance->engine->read(instance, rtcp); } -int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_set_local_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) { - instance->local_address.sin_addr = address->sin_addr; - instance->local_address.sin_port = address->sin_port; + ast_sockaddr_copy(&instance->local_address, address); return 0; } -int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) { - instance->remote_address.sin_addr = address->sin_addr; - instance->remote_address.sin_port = address->sin_port; + ast_sockaddr_copy(&instance->remote_address, address); /* moo */ @@ -392,10 +392,10 @@ int ast_rtp_instance_set_remote_address(struct ast_rtp_instance *instance, struc return 0; } -int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, + const struct ast_sockaddr *address) { - instance->alt_remote_address.sin_addr = address->sin_addr; - instance->alt_remote_address.sin_port = address->sin_port; + ast_sockaddr_copy(&instance->alt_remote_address, address); /* oink */ @@ -406,24 +406,22 @@ int ast_rtp_instance_set_alt_remote_address(struct ast_rtp_instance *instance, s return 0; } -int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, + struct ast_sockaddr *address) { - if ((address->sin_family != AF_INET) || - (address->sin_port != instance->local_address.sin_port) || - (address->sin_addr.s_addr != instance->local_address.sin_addr.s_addr)) { - memcpy(address, &instance->local_address, sizeof(*address)); + if (ast_sockaddr_cmp(address, &instance->local_address) != 0) { + ast_sockaddr_copy(address, &instance->local_address); return 1; } return 0; } -int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, struct sockaddr_in *address) +int ast_rtp_instance_get_remote_address(struct ast_rtp_instance *instance, + struct ast_sockaddr *address) { - if ((address->sin_family != AF_INET) || - (address->sin_port != instance->remote_address.sin_port) || - (address->sin_addr.s_addr != instance->remote_address.sin_addr.s_addr)) { - memcpy(address, &instance->remote_address, sizeof(*address)); + if (ast_sockaddr_cmp(address, &instance->remote_address) != 0) { + ast_sockaddr_copy(address, &instance->remote_address); return 1; } @@ -959,8 +957,8 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct enum ast_bridge_result res = AST_BRIDGE_FAILED; struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, }; format_t oldcodec0 = codec0, oldcodec1 = codec1; - struct sockaddr_in ac1 = {0,}, vac1 = {0,}, tac1 = {0,}, ac0 = {0,}, vac0 = {0,}, tac0 = {0,}; - struct sockaddr_in t1 = {0,}, vt1 = {0,}, tt1 = {0,}, t0 = {0,}, vt0 = {0,}, tt0 = {0,}; + struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}}; + struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}}; struct ast_frame *fr = NULL; /* Test the first channel */ @@ -1035,44 +1033,59 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct codec0 = glue0->get_codec(c0); } - if ((inaddrcmp(&t1, &ac1)) || - (vinstance1 && inaddrcmp(&vt1, &vac1)) || - (tinstance1 && inaddrcmp(&tt1, &tac1)) || + if ((ast_sockaddr_cmp(&t1, &ac1)) || + (vinstance1 && ast_sockaddr_cmp(&vt1, &vac1)) || + (tinstance1 && ast_sockaddr_cmp(&tt1, &tac1)) || (codec1 != oldcodec1)) { - ast_debug(1, "Oooh, '%s' changed end address to %s:%d (format %s)\n", - c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port), ast_getformatname(codec1)); - ast_debug(1, "Oooh, '%s' changed end vaddress to %s:%d (format %s)\n", - c1->name, ast_inet_ntoa(vt1.sin_addr), ntohs(vt1.sin_port), ast_getformatname(codec1)); - ast_debug(1, "Oooh, '%s' changed end taddress to %s:%d (format %s)\n", - c1->name, ast_inet_ntoa(tt1.sin_addr), ntohs(tt1.sin_port), ast_getformatname(codec1)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port), ast_getformatname(oldcodec1)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c1->name, ast_inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), ast_getformatname(oldcodec1)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c1->name, ast_inet_ntoa(tac1.sin_addr), ntohs(tac1.sin_port), ast_getformatname(oldcodec1)); - if (glue0->update_peer(c0, t1.sin_addr.s_addr ? instance1 : NULL, vt1.sin_addr.s_addr ? vinstance1 : NULL, tt1.sin_addr.s_addr ? tinstance1 : NULL, codec1, 0)) { + ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n", + c1->name, ast_sockaddr_stringify(&t1), + ast_getformatname(codec1)); + ast_debug(1, "Oooh, '%s' changed end vaddress to %s (format %s)\n", + c1->name, ast_sockaddr_stringify(&vt1), + ast_getformatname(codec1)); + ast_debug(1, "Oooh, '%s' changed end taddress to %s (format %s)\n", + c1->name, ast_sockaddr_stringify(&tt1), + ast_getformatname(codec1)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c1->name, ast_sockaddr_stringify(&ac1), + ast_getformatname(oldcodec1)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c1->name, ast_sockaddr_stringify(&vac1), + ast_getformatname(oldcodec1)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c1->name, ast_sockaddr_stringify(&tac1), + ast_getformatname(oldcodec1)); + if (glue0->update_peer(c0, + ast_sockaddr_isnull(&t1) ? NULL : instance1, + ast_sockaddr_isnull(&vt1) ? NULL : vinstance1, + ast_sockaddr_isnull(&tt1) ? NULL : tinstance1, + codec1, 0)) { ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name); } - memcpy(&ac1, &t1, sizeof(ac1)); - memcpy(&vac1, &vt1, sizeof(vac1)); - memcpy(&tac1, &tt1, sizeof(tac1)); + ast_sockaddr_copy(&ac1, &t1); + ast_sockaddr_copy(&vac1, &vt1); + ast_sockaddr_copy(&tac1, &tt1); oldcodec1 = codec1; } - if ((inaddrcmp(&t0, &ac0)) || - (vinstance0 && inaddrcmp(&vt0, &vac0)) || - (tinstance0 && inaddrcmp(&tt0, &tac0)) || + if ((ast_sockaddr_cmp(&t0, &ac0)) || + (vinstance0 && ast_sockaddr_cmp(&vt0, &vac0)) || + (tinstance0 && ast_sockaddr_cmp(&tt0, &tac0)) || (codec0 != oldcodec0)) { - ast_debug(1, "Oooh, '%s' changed end address to %s:%d (format %s)\n", - c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port), ast_getformatname(codec0)); - ast_debug(1, "Oooh, '%s' was %s:%d/(format %s)\n", - c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), ast_getformatname(oldcodec0)); - if (glue1->update_peer(c1, t0.sin_addr.s_addr ? instance0 : NULL, vt0.sin_addr.s_addr ? vinstance0 : NULL, tt0.sin_addr.s_addr ? tinstance0 : NULL, codec0, 0)) { + ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n", + c0->name, ast_sockaddr_stringify(&t0), + ast_getformatname(codec0)); + ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", + c0->name, ast_sockaddr_stringify(&ac0), + ast_getformatname(oldcodec0)); + if (glue1->update_peer(c1, t0.len ? instance0 : NULL, + vt0.len ? vinstance0 : NULL, + tt0.len ? tinstance0 : NULL, + codec0, 0)) { ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name); } - memcpy(&ac0, &t0, sizeof(ac0)); - memcpy(&vac0, &vt0, sizeof(vac0)); - memcpy(&tac0, &tt0, sizeof(tac0)); + ast_sockaddr_copy(&ac0, &t0); + ast_sockaddr_copy(&vac0, &vt0); + ast_sockaddr_copy(&tac0, &tt0); oldcodec0 = codec0; } @@ -1122,9 +1135,9 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct } /* Update local address information */ ast_rtp_instance_get_remote_address(instance0, &t0); - memcpy(&ac0, &t0, sizeof(ac0)); + ast_sockaddr_copy(&ac0, &t0); ast_rtp_instance_get_remote_address(instance1, &t1); - memcpy(&ac1, &t1, sizeof(ac1)); + ast_sockaddr_copy(&ac1, &t1); /* Update codec information */ if (glue0->get_codec && c0->tech_pvt) { oldcodec0 = codec0 = glue0->get_codec(c0); @@ -1201,6 +1214,7 @@ enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct as *vinstance0 = NULL, *vinstance1 = NULL, *tinstance0 = NULL, *tinstance1 = NULL; struct ast_rtp_glue *glue0, *glue1; + struct ast_sockaddr addr1, addr2; enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID, text_glue0_res = AST_RTP_GLUE_RESULT_FORBID; enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID, text_glue1_res = AST_RTP_GLUE_RESULT_FORBID; enum ast_bridge_result res = AST_BRIDGE_FAILED; @@ -1249,6 +1263,17 @@ enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct as goto done; } + + /* If address families differ, force a local bridge */ + ast_rtp_instance_get_remote_address(instance0, &addr1); + ast_rtp_instance_get_remote_address(instance1, &addr2); + + if (addr1.ss.ss_family != addr2.ss.ss_family || + (ast_sockaddr_is_ipv4_mapped(&addr1) != ast_sockaddr_is_ipv4_mapped(&addr2))) { + audio_glue0_res = AST_RTP_GLUE_RESULT_LOCAL; + audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; + } + /* If we need to get DTMF see if we can do it outside of the RTP stream itself */ if ((flags & AST_BRIDGE_DTMF_CHANNEL_0) && instance0->properties[AST_RTP_PROPERTY_DTMF]) { res = AST_BRIDGE_FAILED_NOWARN; @@ -1640,7 +1665,9 @@ int ast_rtp_instance_activate(struct ast_rtp_instance *instance) return instance->engine->activate ? instance->engine->activate(instance) : 0; } -void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, struct sockaddr_in *suggestion, const char *username) +void ast_rtp_instance_stun_request(struct ast_rtp_instance *instance, + struct ast_sockaddr *suggestion, + const char *username) { if (instance->engine->stun_request) { instance->engine->stun_request(instance, suggestion, username); diff --git a/main/tcptls.c b/main/tcptls.c index 8c95502e7..b505f2a01 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -235,8 +235,7 @@ void *ast_tcptls_server_root(void *data) { struct ast_tcptls_session_args *desc = data; int fd; - struct sockaddr_in sin; - socklen_t sinlen; + struct ast_sockaddr addr; struct ast_tcptls_session_instance *tcptls_session; pthread_t launched; @@ -248,8 +247,7 @@ void *ast_tcptls_server_root(void *data) i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); if (i <= 0) continue; - sinlen = sizeof(sin); - fd = accept(desc->accept_fd, (struct sockaddr *) &sin, &sinlen); + fd = ast_accept(desc->accept_fd, &addr); if (fd < 0) { if ((errno != EAGAIN) && (errno != EINTR)) ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); @@ -268,7 +266,7 @@ void *ast_tcptls_server_root(void *data) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); tcptls_session->fd = fd; tcptls_session->parent = desc; - memcpy(&tcptls_session->remote_address, &sin, sizeof(tcptls_session->remote_address)); + ast_sockaddr_copy(&tcptls_session->remote_address, &addr); tcptls_session->client = 0; @@ -373,10 +371,10 @@ struct ast_tcptls_session_instance *ast_tcptls_client_start(struct ast_tcptls_se goto client_start_error; } - if (connect(desc->accept_fd, (const struct sockaddr *) &desc->remote_address, sizeof(desc->remote_address))) { - ast_log(LOG_ERROR, "Unable to connect %s to %s:%d: %s\n", + if (ast_connect(desc->accept_fd, &desc->remote_address)) { + ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", desc->name, - ast_inet_ntoa(desc->remote_address.sin_addr), ntohs(desc->remote_address.sin_port), + ast_sockaddr_stringify(&desc->remote_address), strerror(errno)); goto client_start_error; } @@ -407,17 +405,18 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s struct ast_tcptls_session_instance *tcptls_session = NULL; /* Do nothing if nothing has changed */ - if (!memcmp(&desc->old_address, &desc->remote_address, sizeof(desc->old_address))) { + if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { ast_debug(1, "Nothing changed in %s\n", desc->name); return NULL; } - desc->old_address = desc->remote_address; + ast_sockaddr_copy(&desc->old_address, &desc->remote_address); if (desc->accept_fd != -1) close(desc->accept_fd); - desc->accept_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? + AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); if (desc->accept_fd < 0) { ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); @@ -426,12 +425,12 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s /* if a local address was specified, bind to it so the connection will originate from the desired address */ - if (desc->local_address.sin_family != 0) { + if (!ast_sockaddr_isnull(&desc->local_address)) { setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); - if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) { - ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n", - desc->name, - ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port), + if (ast_bind(desc->accept_fd, &desc->local_address)) { + ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", + desc->name, + ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } @@ -445,7 +444,8 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s tcptls_session->fd = desc->accept_fd; tcptls_session->parent = desc; tcptls_session->parent->worker_fn = NULL; - memcpy(&tcptls_session->remote_address, &desc->remote_address, sizeof(tcptls_session->remote_address)); + ast_sockaddr_copy(&tcptls_session->remote_address, + &desc->remote_address); return tcptls_session; @@ -463,12 +463,12 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) int x = 1; /* Do nothing if nothing has changed */ - if (!memcmp(&desc->old_address, &desc->local_address, sizeof(desc->old_address))) { + if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { ast_debug(1, "Nothing changed in %s\n", desc->name); return; } - desc->old_address = desc->local_address; + ast_sockaddr_copy(&desc->old_address, &desc->local_address); /* Shutdown a running server if there is one */ if (desc->master != AST_PTHREADT_NULL) { @@ -481,22 +481,23 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) close(desc->accept_fd); /* If there's no new server, stop here */ - if (desc->local_address.sin_family == 0) { + if (ast_sockaddr_isnull(&desc->local_address)) { ast_debug(2, "Server disabled: %s\n", desc->name); return; } - desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0); + desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? + AF_INET6 : AF_INET, SOCK_STREAM, 0); if (desc->accept_fd < 0) { ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); return; } setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); - if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) { - ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n", + if (ast_bind(desc->accept_fd, &desc->local_address)) { + ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", desc->name, - ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port), + ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } @@ -507,9 +508,9 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) flags = fcntl(desc->accept_fd, F_GETFL); fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { - ast_log(LOG_ERROR, "Unable to launch thread for %s on %s:%d: %s\n", + ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", desc->name, - ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port), + ast_sockaddr_stringify(&desc->local_address), strerror(errno)); goto error; } @@ -537,7 +538,6 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_ { if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { tls_cfg->enabled = ast_true(value) ? 1 : 0; - tls_desc->local_address.sin_family = AF_INET; } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { ast_free(tls_cfg->certfile); tls_cfg->certfile = ast_strdup(value); @@ -558,10 +558,8 @@ int ast_tls_read_conf(struct ast_tls_config *tls_cfg, struct ast_tcptls_session_ } else if (!strcasecmp(varname, "tlsdontverifyserver")) { ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { - if (ast_parse_arg(value, PARSE_INADDR, &tls_desc->local_address)) + if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); - } else if (!strcasecmp(varname, "tlsbindport") || !strcasecmp(varname, "sslbindport")) { - tls_desc->local_address.sin_port = htons(atoi(value)); } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { if (!strcasecmp(value, "tlsv1")) { ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); |