/*
* Asterisk -- An open source telephony toolkit.
*
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2012, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* \author Mark Spencer <markster@digium.com>
*/
-#include "asterisk.h"
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include "asterisk.h"
#include "asterisk/network.h"
struct ifaddrs *ifap, *ifaphead;
int rtnerr;
const struct sockaddr_in *sin;
- int best_score = -100;
#endif /* BSD_OR_LINUX */
struct in_addr best_addr;
+ int best_score = -100;
memset(&best_addr, 0, sizeof(best_addr));
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__) || defined(__GLIBC__)
}
bufsz = ifn.lifn_count * sizeof(struct lifreq);
- if (!(buf = malloc(bufsz))) {
+ if (!(buf = ast_malloc(bufsz))) {
close(s);
return -1;
}
ifc.lifc_flags = 0;
if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) {
close(s);
- free(buf);
+ ast_free(buf);
return -1;
}
}
}
- free(buf);
+ ast_free(buf);
#endif /* SOLARIS */
close(s);
}
}
+/* Free ACL list structure */
+struct ast_acl_list *ast_free_acl_list(struct ast_acl_list *acl_list)
+{
+ struct ast_acl *current;
+
+ if (!acl_list) {
+ return NULL;
+ }
+
+ AST_LIST_LOCK(acl_list);
+ while ((current = AST_LIST_REMOVE_HEAD(acl_list, list))) {
+ ast_free_ha(current->acl);
+ ast_free(current);
+ }
+ AST_LIST_UNLOCK(acl_list);
+
+ AST_LIST_HEAD_DESTROY(acl_list);
+ ast_free(acl_list);
+
+ return NULL;
+}
+
/* Copy HA structure */
void ast_copy_ha(const struct ast_ha *from, struct ast_ha *to)
{
while (start) {
current = ast_duplicate_ha(start); /* Create copy of this object */
+ if (!current) {
+ ast_free_ha(ret);
+
+ return NULL;
+ }
+
if (prev) {
prev->next = current; /* Link previous to this object */
}
return ret; /* Return start of list */
}
-/*!
- * \brief
- * Isolate a 32-bit section of an IPv6 address
- *
- * An IPv6 address can be divided into 4 32-bit chunks. This gives
- * easy access to one of these chunks.
- *
- * \param sin6 A pointer to a struct sockaddr_in6
- * \param index Which 32-bit chunk to operate on. Must be in the range 0-3.
- */
-#define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
+static int acl_new(struct ast_acl **pointer, const char *name) {
+ struct ast_acl *acl;
+ if (!(acl = ast_calloc(1, sizeof(*acl)))) {
+ return 1;
+ }
-/*!
- * \brief
- * Apply a netmask to an address and store the result in a separate structure.
- *
- * When dealing with IPv6 addresses, one cannot apply a netmask with a simple
- * logical and operation. Furthermore, the incoming address may be an IPv4 address
- * and need to be mapped properly before attempting to apply a rule.
- *
- * \param addr The IP address to apply the mask to.
- * \param netmask The netmask configured in the host access rule.
- * \param result The resultant address after applying the netmask to the given address
- * \retval 0 Successfully applied netmask
- * \reval -1 Failed to apply netmask
- */
-static int apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
- struct ast_sockaddr *result)
+ *pointer = acl;
+ ast_copy_string(acl->name, name, ACL_NAME_LENGTH);
+ return 0;
+}
+
+struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original)
{
- int res = 0;
-
- if (ast_sockaddr_is_ipv4(addr)) {
- struct sockaddr_in result4 = { 0, };
- struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr->ss;
- struct sockaddr_in *mask4 = (struct sockaddr_in *) &netmask->ss;
- result4.sin_family = AF_INET;
- result4.sin_addr.s_addr = addr4->sin_addr.s_addr & mask4->sin_addr.s_addr;
- ast_sockaddr_from_sin(result, &result4);
- } else if (ast_sockaddr_is_ipv6(addr)) {
- struct sockaddr_in6 result6 = { 0, };
- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr->ss;
- struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *) &netmask->ss;
- int i;
- result6.sin6_family = AF_INET6;
- for (i = 0; i < 4; ++i) {
- V6_WORD(&result6, i) = V6_WORD(addr6, i) & V6_WORD(mask6, i);
+ struct ast_acl_list *clone;
+ struct ast_acl *current_cursor;
+ struct ast_acl *current_clone;
+
+ /* Early return if we receive a duplication request for a NULL original. */
+ if (!original) {
+ return NULL;
+ }
+
+ if (!(clone = ast_calloc(1, sizeof(*clone)))) {
+ ast_log(LOG_ERROR, "Failed to allocate ast_acl_list struct while cloning an ACL\n");
+ return NULL;
+ }
+ AST_LIST_HEAD_INIT(clone);
+
+ AST_LIST_LOCK(original);
+
+ AST_LIST_TRAVERSE(original, current_cursor, list) {
+ if ((acl_new(¤t_clone, current_cursor->name))) {
+ ast_log(LOG_ERROR, "Failed to allocate ast_acl struct while cloning an ACL.\n");
+ ast_free_acl_list(clone);
+ clone = NULL;
+ break;
+ }
+
+ /* Copy data from original ACL to clone ACL */
+ current_clone->acl = ast_duplicate_ha_list(current_cursor->acl);
+
+ current_clone->is_invalid = current_cursor->is_invalid;
+ current_clone->is_realtime = current_cursor->is_realtime;
+
+ AST_LIST_INSERT_TAIL(clone, current_clone, list);
+
+ if (current_cursor->acl && !current_clone->acl) {
+ /* Deal with failure after adding to clone so we don't have to free
+ * current_clone separately. */
+ ast_log(LOG_ERROR, "Failed to duplicate HA list while cloning ACL.\n");
+ ast_free_acl_list(clone);
+ clone = NULL;
+ break;
}
- memcpy(&result->ss, &result6, sizeof(result6));
- result->len = sizeof(result6);
- } else {
- /* Unsupported address scheme */
- res = -1;
}
- return res;
+ AST_LIST_UNLOCK(original);
+
+ return clone;
}
/*!
return 0;
}
+void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
+{
+ struct ast_acl *acl = NULL;
+ struct ast_acl *current;
+ struct ast_acl_list *working_list;
+
+ char *tmp, *list;
+
+ /* If the ACL list is currently uninitialized, it must be initialized. */
+ if (*path == NULL) {
+ struct ast_acl_list *list;
+ list = ast_calloc(1, sizeof(*list));
+ if (!list) {
+ /* Allocation Error */
+ if (error) {
+ *error = 1;
+ }
+ return;
+ }
+
+ AST_LIST_HEAD_INIT(list);
+ *path = list;
+ }
+
+ working_list = *path;
+
+ AST_LIST_LOCK(working_list);
+
+ /* First we need to determine if we will need to add a new ACL node or if we can use an existing one. */
+ if (strncasecmp(sense, "a", 1)) {
+ /* The first element in the path should be the unnamed, base ACL. If that's the case, we use it. If not,
+ * we have to make one and link it up appropriately. */
+ current = AST_LIST_FIRST(working_list);
+
+ if (!current || !ast_strlen_zero(current->name)) {
+ if (acl_new(&acl, "")) {
+ if (error) {
+ *error = 1;
+ }
+ AST_LIST_UNLOCK(working_list);
+ return;
+ }
+ // Need to INSERT the ACL at the head here.
+ AST_LIST_INSERT_HEAD(working_list, acl, list);
+ } else {
+ /* If the first element was already the unnamed base ACL, we just use that one. */
+ acl = current;
+ }
+
+ /* With the proper ACL set for modification, we can just pass this off to the ast_ha append function. */
+ acl->acl = ast_append_ha(sense, stuff, acl->acl, error);
+
+ AST_LIST_UNLOCK(working_list);
+ return;
+ }
+
+ /* We are in ACL append mode, so we know we'll be adding one or more named ACLs. */
+ list = ast_strdupa(stuff);
+
+ while ((tmp = strsep(&list, ","))) {
+ struct ast_ha *named_ha;
+ int already_included = 0;
+
+ /* Remove leading whitespace from the string in case the user put spaces between items */
+ tmp = ast_skip_blanks(tmp);
+
+ /* The first step is to check for a duplicate */
+ AST_LIST_TRAVERSE(working_list, current, list) {
+ if (!strcasecmp(current->name, tmp)) { /* ACL= */
+ /* Inclusion of the same ACL multiple times isn't a catastrophic error, but it will raise the error flag and skip the entry. */
+ ast_log(LOG_ERROR, "Named ACL '%s' occurs multiple times in ACL definition. "
+ "Please update your ACL configuration.\n", tmp);
+ if (error) {
+ *error = 1;
+ }
+ already_included = 1;
+ break;
+ }
+ }
+
+ if (already_included) {
+ continue;
+ }
+
+ if (acl_new(&acl, tmp)) {
+ /* This is a catastrophic allocation error and we'll return immediately if this happens. */
+ if (error) {
+ *error = 1;
+ }
+ AST_LIST_UNLOCK(working_list);
+ return;
+ }
+
+ /* Attempt to grab the Named ACL we are looking for. */
+ named_ha = ast_named_acl_find(tmp, &acl->is_realtime, &acl->is_invalid);
+
+ /* Set the ACL's ast_ha to the duplicated named ACL retrieved above. */
+ acl->acl = named_ha;
+
+ /* Raise the named_acl_flag since we are adding a named ACL to the ACL container. */
+ if (named_acl_flag) {
+ *named_acl_flag = 1;
+ }
+
+ /* Now insert the new ACL at the end of the list. */
+ AST_LIST_INSERT_TAIL(working_list, acl, list);
+ }
+
+ AST_LIST_UNLOCK(working_list);
+}
+
+int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
+{
+ struct ast_acl *head;
+
+ if (!acl_list) {
+ return 1;
+ }
+
+ AST_LIST_LOCK(acl_list);
+ head = AST_LIST_FIRST(acl_list);
+ AST_LIST_UNLOCK(acl_list);
+
+ if (head) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*!
+ * \internal
+ * \brief Used by ast_append_ha to avoid ast_strdupa in a loop.
+ *
+ * \note This function is only called at debug level 3 and higher.
+ */
+static void debug_ha_sense_appended(struct ast_ha *ha)
+{
+ const char *parsed_mask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask));
+
+ ast_log(LOG_DEBUG, "%s/%s sense %u appended to ACL\n",
+ ast_sockaddr_stringify(&ha->addr),
+ parsed_mask,
+ ha->sense);
+}
+
struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
{
struct ast_ha *ha;
struct ast_ha *prev = NULL;
struct ast_ha *ret;
- char *tmp = ast_strdupa(stuff);
+ char *tmp, *list = ast_strdupa(stuff);
char *address = NULL, *mask = NULL;
int addr_is_v4;
+ int allowing = strncasecmp(sense, "p", 1) ? AST_SENSE_DENY : AST_SENSE_ALLOW;
ret = path;
while (path) {
path = path->next;
}
- if (!(ha = ast_calloc(1, sizeof(*ha)))) {
- if (error) {
- *error = 1;
+ while ((tmp = strsep(&list, ","))) {
+ if (!(ha = ast_calloc(1, sizeof(*ha)))) {
+ if (error) {
+ *error = 1;
+ }
+ return ret;
}
- return ret;
- }
-
- address = strsep(&tmp, "/");
- if (!address) {
- address = tmp;
- } else {
- mask = tmp;
- }
- if (!ast_sockaddr_parse(&ha->addr, address, PARSE_PORT_FORBID)) {
- ast_log(LOG_WARNING, "Invalid IP address: %s\n", address);
- ast_free_ha(ha);
- if (error) {
- *error = 1;
+ address = strsep(&tmp, "/");
+ if (!address) {
+ address = tmp;
+ } else {
+ mask = tmp;
}
- return ret;
- }
- /* If someone specifies an IPv4-mapped IPv6 address,
- * we just convert this to an IPv4 ACL
- */
- if (ast_sockaddr_ipv4_mapped(&ha->addr, &ha->addr)) {
- ast_log(LOG_NOTICE, "IPv4-mapped ACL network address specified. "
- "Converting to an IPv4 ACL network address.\n");
- }
-
- addr_is_v4 = ast_sockaddr_is_ipv4(&ha->addr);
+ if (*address == '!') {
+ ha->sense = (allowing == AST_SENSE_DENY) ? AST_SENSE_ALLOW : AST_SENSE_DENY;
+ address++;
+ } else {
+ ha->sense = allowing;
+ }
- if (!mask) {
- parse_cidr_mask(&ha->netmask, addr_is_v4, addr_is_v4 ? "32" : "128");
- } else if (strchr(mask, ':') || strchr(mask, '.')) {
- int mask_is_v4;
- /* Mask is of x.x.x.x or x:x:x:x:x:x:x:x variety */
- if (!ast_sockaddr_parse(&ha->netmask, mask, PARSE_PORT_FORBID)) {
- ast_log(LOG_WARNING, "Invalid netmask: %s\n", mask);
+ if (!ast_sockaddr_parse(&ha->addr, address, PARSE_PORT_FORBID)) {
+ ast_log(LOG_WARNING, "Invalid IP address: %s\n", address);
ast_free_ha(ha);
if (error) {
*error = 1;
}
return ret;
}
- /* If someone specifies an IPv4-mapped IPv6 netmask,
+
+ /* If someone specifies an IPv4-mapped IPv6 address,
* we just convert this to an IPv4 ACL
*/
- if (ast_sockaddr_ipv4_mapped(&ha->netmask, &ha->netmask)) {
- ast_log(LOG_NOTICE, "IPv4-mapped ACL netmask specified. "
+ if (ast_sockaddr_ipv4_mapped(&ha->addr, &ha->addr)) {
+ ast_log(LOG_NOTICE, "IPv4-mapped ACL network address specified. "
+ "Converting to an IPv4 ACL network address.\n");
+ }
+
+ addr_is_v4 = ast_sockaddr_is_ipv4(&ha->addr);
+
+ if (!mask) {
+ parse_cidr_mask(&ha->netmask, addr_is_v4, addr_is_v4 ? "32" : "128");
+ } else if (strchr(mask, ':') || strchr(mask, '.')) {
+ int mask_is_v4;
+ /* Mask is of x.x.x.x or x:x:x:x:x:x:x:x variety */
+ if (!ast_sockaddr_parse(&ha->netmask, mask, PARSE_PORT_FORBID)) {
+ ast_log(LOG_WARNING, "Invalid netmask: %s\n", mask);
+ ast_free_ha(ha);
+ if (error) {
+ *error = 1;
+ }
+ return ret;
+ }
+ /* If someone specifies an IPv4-mapped IPv6 netmask,
+ * we just convert this to an IPv4 ACL
+ */
+ if (ast_sockaddr_ipv4_mapped(&ha->netmask, &ha->netmask)) {
+ ast_log(LOG_NOTICE, "IPv4-mapped ACL netmask specified. "
"Converting to an IPv4 ACL netmask.\n");
+ }
+ mask_is_v4 = ast_sockaddr_is_ipv4(&ha->netmask);
+ if (addr_is_v4 ^ mask_is_v4) {
+ ast_log(LOG_WARNING, "Address and mask are not using same address scheme.\n");
+ ast_free_ha(ha);
+ if (error) {
+ *error = 1;
+ }
+ return ret;
+ }
+ } else if (parse_cidr_mask(&ha->netmask, addr_is_v4, mask)) {
+ ast_log(LOG_WARNING, "Invalid CIDR netmask: %s\n", mask);
+ ast_free_ha(ha);
+ if (error) {
+ *error = 1;
+ }
+ return ret;
}
- mask_is_v4 = ast_sockaddr_is_ipv4(&ha->netmask);
- if (addr_is_v4 ^ mask_is_v4) {
- ast_log(LOG_WARNING, "Address and mask are not using same address scheme.\n");
+
+ if (ast_sockaddr_apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
+ /* This shouldn't happen because ast_sockaddr_parse would
+ * have failed much earlier on an unsupported address scheme
+ */
+ char *failmask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask));
+ char *failaddr = ast_strdupa(ast_sockaddr_stringify(&ha->addr));
+ ast_log(LOG_WARNING, "Unable to apply netmask %s to address %s\n", failmask, failaddr);
ast_free_ha(ha);
if (error) {
*error = 1;
}
return ret;
}
- } else if (parse_cidr_mask(&ha->netmask, addr_is_v4, mask)) {
- ast_log(LOG_WARNING, "Invalid CIDR netmask: %s\n", mask);
- ast_free_ha(ha);
- if (error) {
- *error = 1;
+
+ if (prev) {
+ prev->next = ha;
+ } else {
+ ret = ha;
+ }
+ prev = ha;
+
+ if (DEBUG_ATLEAST(3)) {
+ debug_ha_sense_appended(ha);
}
- return ret;
}
- if (apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
- /* This shouldn't happen because ast_sockaddr_parse would
- * have failed much earlier on an unsupported address scheme
- */
- char *failmask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask));
- char *failaddr = ast_strdupa(ast_sockaddr_stringify(&ha->addr));
- ast_log(LOG_WARNING, "Unable to apply netmask %s to address %s\n", failmask, failaddr);
- ast_free_ha(ha);
- if (error) {
- *error = 1;
+ return ret;
+}
+
+void ast_ha_join(const struct ast_ha *ha, struct ast_str **buf)
+{
+ for (; ha; ha = ha->next) {
+ ast_str_append(buf, 0, "%s%s/",
+ ha->sense == AST_SENSE_ALLOW ? "!" : "",
+ ast_sockaddr_stringify_addr(&ha->addr));
+ /* Separated to avoid duplicating stringified addresses. */
+ ast_str_append(buf, 0, "%s", ast_sockaddr_stringify_addr(&ha->netmask));
+ if (ha->next) {
+ ast_str_append(buf, 0, ",");
+ }
+ }
+}
+
+void ast_ha_join_cidr(const struct ast_ha *ha, struct ast_str **buf)
+{
+ for (; ha; ha = ha->next) {
+ const char *addr = ast_sockaddr_stringify_addr(&ha->addr);
+ ast_str_append(buf, 0, "%s%s/%d",
+ ha->sense == AST_SENSE_ALLOW ? "!" : "",
+ addr, ast_sockaddr_cidr_bits(&ha->netmask));
+ if (ha->next) {
+ ast_str_append(buf, 0, ",");
}
- return ret;
}
+}
- ha->sense = strncasecmp(sense, "p", 1) ? AST_SENSE_DENY : AST_SENSE_ALLOW;
+enum ast_acl_sense ast_apply_acl(struct ast_acl_list *acl_list, const struct ast_sockaddr *addr, const char *purpose)
+{
+ struct ast_acl *acl;
- ha->next = NULL;
- if (prev) {
- prev->next = ha;
- } else {
- ret = ha;
+ /* If the list is NULL, there are no rules, so we'll allow automatically. */
+ if (!acl_list) {
+ return AST_SENSE_ALLOW;
}
- {
- const char *addr = ast_strdupa(ast_sockaddr_stringify(&ha->addr));
- const char *mask = ast_strdupa(ast_sockaddr_stringify(&ha->netmask));
+ AST_LIST_LOCK(acl_list);
+
+ AST_LIST_TRAVERSE(acl_list, acl, list) {
+ if (acl->is_invalid) {
+ /* In this case, the baseline ACL shouldn't ever trigger this, but if that somehow happens, it'll still be shown. */
+ ast_log(LOG_WARNING, "%sRejecting '%s' due to use of an invalid ACL '%s'.\n", purpose ? purpose : "", ast_sockaddr_stringify_addr(addr),
+ ast_strlen_zero(acl->name) ? "(BASELINE)" : acl->name);
+ AST_LIST_UNLOCK(acl_list);
+ return AST_SENSE_DENY;
+ }
- ast_debug(1, "%s/%s sense %d appended to acl for peer\n", addr, mask, ha->sense);
+ if (acl->acl) {
+ if (ast_apply_ha(acl->acl, addr) == AST_SENSE_DENY) {
+ ast_log(LOG_NOTICE, "%sRejecting '%s' due to a failure to pass ACL '%s'\n", purpose ? purpose : "", ast_sockaddr_stringify_addr(addr),
+ ast_strlen_zero(acl->name) ? "(BASELINE)" : acl->name);
+ AST_LIST_UNLOCK(acl_list);
+ return AST_SENSE_DENY;
+ }
+ }
}
- return ret;
+ AST_LIST_UNLOCK(acl_list);
+
+ return AST_SENSE_ALLOW;
}
-int ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr)
+enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr)
{
/* Start optimistic */
- int res = AST_SENSE_ALLOW;
+ enum ast_acl_sense res = AST_SENSE_ALLOW;
const struct ast_ha *current_ha;
for (current_ha = ha; current_ha; current_ha = current_ha->next) {
char iabuf[INET_ADDRSTRLEN];
char iabuf2[INET_ADDRSTRLEN];
/* DEBUG */
- ast_copy_string(iabuf, ast_inet_ntoa(sin->sin_addr), sizeof(iabuf));
- ast_copy_string(iabuf2, ast_inet_ntoa(ha->netaddr), sizeof(iabuf2));
+ ast_copy_string(iabuf, ast_sockaddr_stringify(addr), sizeof(iabuf));
+ ast_copy_string(iabuf2, ast_sockaddr_stringify(¤t_ha->addr), sizeof(iabuf2));
ast_debug(1, "##### Testing %s with %s\n", iabuf, iabuf2);
#endif
- if (ast_sockaddr_is_ipv4(&ha->addr)) {
+ if (ast_sockaddr_is_ipv4(¤t_ha->addr)) {
if (ast_sockaddr_is_ipv6(addr)) {
if (ast_sockaddr_is_ipv4_mapped(addr)) {
/* IPv4 ACLs apply to IPv4-mapped addresses */
- ast_sockaddr_ipv4_mapped(addr, &mapped_addr);
+ if (!ast_sockaddr_ipv4_mapped(addr, &mapped_addr)) {
+ ast_log(LOG_ERROR, "%s provided to ast_sockaddr_ipv4_mapped could not be converted. That shouldn't be possible.\n",
+ ast_sockaddr_stringify(addr));
+ continue;
+ }
addr_to_use = &mapped_addr;
} else {
/* An IPv4 ACL does not apply to an IPv6 address */
/* For each rule, if this address and the netmask = the net address
apply the current rule */
- if (apply_netmask(addr_to_use, ¤t_ha->netmask, &result)) {
+ if (ast_sockaddr_apply_netmask(addr_to_use, ¤t_ha->netmask, &result)) {
/* Unlikely to happen since we know the address to be IPv4 or IPv6 */
continue;
}
int ast_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us)
{
+ /*
+ * We must create the errno string before creating the address
+ * string because it could wipe out errno on the error return
+ * paths.
+ */
+ const char *sock_err;
int port;
int s;
+ /* Preserve our original address port */
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");
+ s = socket(ast_sockaddr_is_ipv6(them) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ sock_err = ast_strdupa(strerror(errno));
+ ast_log(LOG_ERROR, "Cannot create socket to %s: %s\n",
+ ast_sockaddr_stringify_addr(them), sock_err);
return -1;
}
if (ast_connect(s, them)) {
- ast_log(LOG_WARNING, "Cannot connect\n");
+ sock_err = ast_strdupa(strerror(errno));
+ ast_log(LOG_WARNING, "Cannot connect to %s: %s\n",
+ ast_sockaddr_stringify_addr(them), sock_err);
close(s);
return -1;
}
if (ast_getsockname(s, us)) {
-
- ast_log(LOG_WARNING, "Cannot get socket name\n");
+ sock_err = ast_strdupa(strerror(errno));
+ ast_log(LOG_WARNING, "Cannot get socket name for connection to %s: %s\n",
+ ast_sockaddr_stringify_addr(them), sock_err);
close(s);
return -1;
}
close(s);
- {
- const char *them_addr = ast_strdupa(ast_sockaddr_stringify_addr(them));
- const char *us_addr = ast_strdupa(ast_sockaddr_stringify_addr(us));
-
- ast_debug(3, "For destination '%s', our source address is '%s'.\n",
- them_addr, us_addr);
- }
-
ast_sockaddr_set_port(us, port);
+ ast_debug(3, "For destination '%s', our source address is '%s'.\n",
+ ast_strdupa(ast_sockaddr_stringify_addr(them)),
+ ast_strdupa(ast_sockaddr_stringify_addr(us)));
+
return 0;
}
{
char ourhost[MAXHOSTNAMELEN] = "";
struct ast_sockaddr root;
+ int res, port = ast_sockaddr_port(ourip);
/* just use the bind address if it is nonzero */
if (!ast_sockaddr_is_any(bindaddr)) {
ast_log(LOG_WARNING, "Unable to get hostname\n");
} else {
if (resolve_first(ourip, ourhost, PARSE_PORT_FORBID, family) == 0) {
+ /* reset port since resolve_first wipes this out */
+ ast_sockaddr_set_port(ourip, port);
return 0;
}
}
/* A.ROOT-SERVERS.NET. */
if (!resolve_first(&root, "A.ROOT-SERVERS.NET", PARSE_PORT_FORBID, 0) &&
!ast_ouraddrfor(&root, ourip)) {
+ /* reset port since resolve_first wipes this out */
+ ast_sockaddr_set_port(ourip, port);
return 0;
}
- return get_local_address(ourip);
+ res = get_local_address(ourip);
+ ast_sockaddr_set_port(ourip, port);
+ return res;
}
-