From 328f772d3bf849d1bebc43030eaf67c6db050142 Mon Sep 17 00:00:00 2001 From: Kirsty Tyerman Date: Mon, 11 Jun 2018 15:07:17 +1000 Subject: [PATCH] pbx_dundi: Added IPv6 support for dundi Change includes move to netsock2 library. ASTERISK-27164 Reported-by: Adam Secombe Change-Id: Ia9e8dc3d153de7a291dbda4bd87fc827dd2bb846 --- CHANGES | 4 + pbx/dundi-parser.c | 9 +- pbx/dundi-parser.h | 2 +- pbx/pbx_dundi.c | 289 +++++++++++++++++++++++++++++---------------- 4 files changed, 199 insertions(+), 105 deletions(-) diff --git a/CHANGES b/CHANGES index 38c87e6e25..0a6db0522b 100644 --- a/CHANGES +++ b/CHANGES @@ -125,6 +125,10 @@ format_jpeg ------------------ * The format_jpeg module has been removed. +pbx_dundi +------------------ + * DUNDi now supports IPv6 + Core: ------------------ * libedit is no longer available as an embedded library and must be provided diff --git a/pbx/dundi-parser.c b/pbx/dundi-parser.c index 808559c592..f24ec860bf 100644 --- a/pbx/dundi-parser.c +++ b/pbx/dundi-parser.c @@ -37,6 +37,7 @@ #include "asterisk/dundi.h" #include "dundi-parser.h" + static void internaloutput(const char *str) { fputs(str, stdout); @@ -428,7 +429,7 @@ static void dump_ies(unsigned char *iedata, int spaces, int len) outputf("\n"); } -void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen) +void dundi_showframe(struct dundi_hdr *fhi, int rx, struct ast_sockaddr *sin, int datalen) { char *pref[] = { "Tx", @@ -469,11 +470,13 @@ void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int pref[rx], fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command"); outputf(tmp); + snprintf(tmp, (int)sizeof(tmp), - "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "", + "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s]%s\n", (rx > 1) ? " " : "", subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS, - ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), + ast_sockaddr_stringify(sin), fhi->cmdresp & 0x80 ? " (Final)" : ""); + outputf(tmp); dump_ies(fhi->ies, rx > 1, datalen); } diff --git a/pbx/dundi-parser.h b/pbx/dundi-parser.h index b24d486a0e..ba93299e6f 100644 --- a/pbx/dundi-parser.h +++ b/pbx/dundi-parser.h @@ -60,7 +60,7 @@ struct dundi_ie_data { extern void dundi_set_output(void (*output)(const char *data)); /* Choose a different function for errors */ extern void dundi_set_error(void (*output)(const char *data)); -extern void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen); +extern void dundi_showframe(struct dundi_hdr *fhi, int rx, struct ast_sockaddr *sin, int datalen); extern const char *dundi_ie2str(int ie); diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c index a94d71cc42..7fcf8cfa7c 100644 --- a/pbx/pbx_dundi.c +++ b/pbx/pbx_dundi.c @@ -242,7 +242,7 @@ struct dundi_precache_queue { struct dundi_request; struct dundi_transaction { - struct sockaddr_in addr; /*!< Other end of transaction */ + struct ast_sockaddr addr; /*!< Other end of transaction */ struct timeval start; /*!< When this transaction was created */ dundi_eid eids[DUNDI_MAX_STACK + 1]; int eidcount; /*!< Number of eids in eids */ @@ -301,7 +301,7 @@ struct dundi_mapping { struct dundi_peer { dundi_eid eid; - struct sockaddr_in addr; /*!< Address of DUNDi peer */ + struct ast_sockaddr addr; /*!< Address of DUNDi peer */ AST_LIST_HEAD_NOLOCK(permissionlist, permission) permit; struct permissionlist include; dundi_eid us_eid; @@ -407,18 +407,20 @@ static int str2tech(char *str) static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[]); static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]); static struct dundi_transaction *create_transaction(struct dundi_peer *p); -static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct sockaddr_in *sin) + +static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct ast_sockaddr *sin) { struct dundi_transaction *trans; /* Look for an exact match first */ AST_LIST_TRAVERSE(&alltrans, trans, all) { - if (!inaddrcmp(&trans->addr, sin) && - ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ || - ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) { - if (hdr->strans) - trans->dtrans = ntohs(hdr->strans) & 32767; - return trans; + if (!ast_sockaddr_cmp(&trans->addr, sin) && + ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ || + ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) { + if (hdr->strans) { + trans->dtrans = ntohs(hdr->strans) & 32767; + } + return trans; } } @@ -434,7 +436,7 @@ static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct /* Create new transaction */ if (!(trans = create_transaction(NULL))) break; - memcpy(&trans->addr, sin, sizeof(trans->addr)); + ast_sockaddr_copy(&trans->addr, sin); trans->dtrans = ntohs(hdr->strans) & 32767; default: break; @@ -449,7 +451,7 @@ static int dundi_ack(struct dundi_transaction *trans, int final) { return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL); } -static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin) +static void dundi_reject(struct dundi_hdr *h, struct ast_sockaddr *sin) { struct { struct dundi_packet pack; @@ -461,7 +463,7 @@ static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin) return; memset(&tmp, 0, sizeof(tmp)); memset(&trans, 0, sizeof(trans)); - memcpy(&trans.addr, sin, sizeof(trans.addr)); + ast_sockaddr_copy(&trans.addr, sin); tmp.hdr.strans = h->dtrans; tmp.hdr.dtrans = h->strans; tmp.hdr.iseqno = h->oseqno; @@ -1291,8 +1293,9 @@ static void qualify_peer(struct dundi_peer *peer, int schedonly); static void apply_peer(struct dundi_transaction *trans, struct dundi_peer *p) { - if (!trans->addr.sin_addr.s_addr) - memcpy(&trans->addr, &p->addr, sizeof(trans->addr)); + if (ast_sockaddr_isnull(&trans->addr)) { + ast_sockaddr_copy(&trans->addr, &p->addr); + } trans->us_eid = p->us_eid; trans->them_eid = p->eid; /* Enable encryption if appropriate */ @@ -1321,7 +1324,7 @@ static int do_register_expire(const void *data) ast_debug(1, "Register expired for '%s'\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); peer->registerexpire = -1; peer->lastms = 0; - memset(&peer->addr, 0, sizeof(peer->addr)); + ast_sockaddr_setnull(&peer->addr); return 0; } @@ -1706,17 +1709,16 @@ static int handle_command_response(struct dundi_transaction *trans, struct dundi int needqual = 0; AST_SCHED_DEL(sched, peer->registerexpire); peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); - snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.sin_addr), - ntohs(trans->addr.sin_port), expire); + snprintf(data, sizeof(data), "%s:%d", ast_sockaddr_stringify(&trans->addr), expire); ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data); - if (inaddrcmp(&peer->addr, &trans->addr)) { - ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n", - ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), - ast_inet_ntoa(trans->addr.sin_addr), ntohs(trans->addr.sin_port)); + if (ast_sockaddr_cmp(&peer->addr, &trans->addr)) { + ast_verb(3, "Registered DUNDi peer '%s' at '%s'\n", + ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), + ast_sockaddr_stringify(&trans->addr)); needqual = 1; } - memcpy(&peer->addr, &trans->addr, sizeof(peer->addr)); + ast_sockaddr_copy(&peer->addr, &trans->addr); dundi_ie_append_short(ied, DUNDI_IE_EXPIRATION, default_expiration); dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied); if (needqual) @@ -1840,7 +1842,7 @@ static int handle_command_response(struct dundi_transaction *trans, struct dundi ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr)); if (!ast_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) { /* If it's them, update our address */ - ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.sin_addr), sizeof(trans->parent->dei->ipaddr)); + ast_copy_string(trans->parent->dei->ipaddr, ast_sockaddr_stringify_addr(&trans->addr), sizeof(trans->parent->dei->ipaddr)); } } if (ies.hint) { @@ -2023,7 +2025,7 @@ static int ack_trans(struct dundi_transaction *trans, int iseqno) return 0; } -static int handle_frame(struct dundi_hdr *h, struct sockaddr_in *sin, int datalen) +static int handle_frame(struct dundi_hdr *h, struct ast_sockaddr *sin, int datalen) { struct dundi_transaction *trans; trans = find_transaction(h, sin); @@ -2066,13 +2068,12 @@ static int handle_frame(struct dundi_hdr *h, struct sockaddr_in *sin, int datale static int socket_read(int *id, int fd, short events, void *cbdata) { - struct sockaddr_in sin; + struct ast_sockaddr sin; int res; struct dundi_hdr *h; char buf[MAX_PACKET_SIZE]; - socklen_t len = sizeof(sin); - res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len); + res = ast_recvfrom(netsocket, buf, sizeof(buf), 0, &sin); if (res < 0) { if (errno != ECONNREFUSED) ast_log(LOG_WARNING, "Error: %s\n", strerror(errno)); @@ -2580,6 +2581,26 @@ static char *dundi_do_query(struct ast_cli_entry *e, int cmd, struct ast_cli_arg return CLI_SUCCESS; } +static char *dundi_sockaddr_stringify_host(const struct ast_sockaddr *addr) +{ + if (ast_sockaddr_isnull(addr)) { + return "(Unspecified)"; + } + return ast_sockaddr_stringify_host(addr); +} + +static uint16_t dundi_sockaddr_port(const struct ast_sockaddr *addr) +{ + /* + * Test to avoid a debug message complaining about addr + * not being an IPv4 or IPv6 address. + */ + if (ast_sockaddr_isnull(addr)) { + return 0; + } + return ast_sockaddr_port(addr); +} + static char *dundi_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct dundi_peer *peer; @@ -2625,8 +2646,8 @@ static char *dundi_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_ar ast_cli(a->fd, "Peer: %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); ast_cli(a->fd, "Model: %s\n", model2str(peer->model)); ast_cli(a->fd, "Order: %s\n", order); - ast_cli(a->fd, "Host: %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : ""); - ast_cli(a->fd, "Port: %d\n", ntohs(peer->addr.sin_port)); + ast_cli(a->fd, "Host: %s\n", ast_sockaddr_isnull(&peer->addr) ? "" : ast_sockaddr_stringify_host(&peer->addr)); + ast_cli(a->fd, "Port: %d\n", dundi_sockaddr_port(&peer->addr)); ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no"); ast_cli(a->fd, "Reg: %s\n", peer->registerid < 0 ? "No" : "Yes"); ast_cli(a->fd, "In Key: %s\n", ast_strlen_zero(peer->inkey) ? "" : peer->inkey); @@ -2658,8 +2679,8 @@ static char *dundi_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_ar static char *dundi_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { -#define FORMAT2 "%-20.20s %-15.15s %-6.6s %-10.10s %-8.8s %-15.15s\n" -#define FORMAT "%-20.20s %-15.15s %s %-6d %-10.10s %-8.8s %-15.15s\n" +#define FORMAT2 "%-20.20s %-41s %-6.6s %-10.10s %-8.8s %-15.15s\n" +#define FORMAT "%-20.20s %-41s %s %-6d %-10.10s %-8.8s %-15.15s\n" struct dundi_peer *peer; int registeredonly=0; char avgms[20]; @@ -2696,9 +2717,11 @@ static char *dundi_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_a char status[20]; int print_line = -1; char srch[2000]; + total_peers++; - if (registeredonly && !peer->addr.sin_addr.s_addr) + if (registeredonly && ast_sockaddr_isnull(&peer->addr)) { continue; + } if (peer->maxms) { if (peer->lastms < 0) { strcpy(status, "UNREACHABLE"); @@ -2724,9 +2747,9 @@ static char *dundi_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_a snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms); else strcpy(avgms, "Unavail"); - snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", - peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status); + snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), + &peer->eid), dundi_sockaddr_stringify_host(&peer->addr), + peer->dynamic ? "(D)" : "(S)", dundi_sockaddr_port(&peer->addr), model2str(peer->model), avgms, status); if (a->argc == 5) { if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) { @@ -2742,8 +2765,8 @@ static char *dundi_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_a if (print_line) { ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)", - peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status); + dundi_sockaddr_stringify_host(&peer->addr), + peer->dynamic ? "(D)" : "(S)", dundi_sockaddr_port(&peer->addr), model2str(peer->model), avgms, status); } } ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers); @@ -2755,8 +2778,8 @@ static char *dundi_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_a static char *dundi_show_trans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { -#define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" -#define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n" +#define FORMAT2 "%-47s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" +#define FORMAT "%-41s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n" struct dundi_transaction *trans; switch (cmd) { case CLI_INIT: @@ -2774,8 +2797,9 @@ static char *dundi_show_trans(struct ast_cli_entry *e, int cmd, struct ast_cli_a AST_LIST_LOCK(&peers); ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack"); AST_LIST_TRAVERSE(&alltrans, trans, all) { - ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr), - ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno); + ast_cli(a->fd, FORMAT, ast_sockaddr_stringify_host(&trans->addr), + ast_sockaddr_port(&trans->addr), trans->strans, trans->dtrans, + trans->oseqno, trans->iseqno, trans->aseqno); } AST_LIST_UNLOCK(&peers); return CLI_SUCCESS; @@ -3095,8 +3119,9 @@ static struct dundi_transaction *create_transaction(struct dundi_peer *p) int tid; /* Don't allow creation of transactions to non-registered peers */ - if (p && !p->addr.sin_addr.s_addr) + if (p && ast_sockaddr_isnull(&p->addr)) { return NULL; + } tid = get_trans_id(); if (tid < 1) return NULL; @@ -3125,11 +3150,10 @@ static int dundi_xmit(struct dundi_packet *pack) int res; if (dundidebug) dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr)); - res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr)); + res = ast_sendto(netsocket, pack->data, pack->datalen, 0, &pack->parent->addr); if (res < 0) { - ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", - ast_inet_ntoa(pack->parent->addr.sin_addr), - ntohs(pack->parent->addr.sin_port), strerror(errno)); + ast_log(LOG_WARNING, "Failed to transmit to '%s': %s\n", + ast_sockaddr_stringify(&pack->parent->addr), strerror(errno)); } if (res > 0) res = 0; @@ -3235,10 +3259,10 @@ static int dundi_rexmit(const void *data) AST_LIST_LOCK(&peers); if (pack->retrans < 1) { pack->retransid = -1; - if (!ast_test_flag(pack->parent, FLAG_ISQUAL)) - ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", - ast_inet_ntoa(pack->parent->addr.sin_addr), - ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans)); + if (!ast_test_flag(pack->parent, FLAG_ISQUAL)) { + ast_log(LOG_NOTICE, "Max retries exceeded to host '%s' msg %d on call %d\n", + ast_sockaddr_stringify(&pack->parent->addr), pack->h->oseqno, ntohs(pack->h->strans)); + } destroy_trans(pack->parent, 1); res = 0; } else { @@ -3593,8 +3617,9 @@ static int append_transaction(struct dundi_request *dr, struct dundi_peer *p, in char eid_str2[20]; /* Ignore if not registered */ - if (!p->addr.sin_addr.s_addr) + if (ast_sockaddr_isnull(&p->addr)) { return 0; + } if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms))) return 0; @@ -4527,15 +4552,31 @@ static void populate_addr(struct dundi_peer *peer, dundi_eid *eid) char eid_str[20]; ast_eid_to_str(eid_str, sizeof(eid_str), eid); if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) { - c = strchr(data, ':'); + /* + * data is in the form: + * IPv6 address: [ffff:ffff::ffff:ffff]:port:expire + * IPv4 address: a.b.c.d:port:expire + */ + c = data; + if (*c == '[') { + /* Need to skip over the IPv6 address. */ + c = strchr(c, ']'); + } + if (c) { + c = strchr(c, ':'); + } if (c) { *c = '\0'; c++; if (sscanf(c, "%5d:%30d", &port, &expire) == 2) { /* Got it! */ - inet_aton(data, &peer->addr.sin_addr); - peer->addr.sin_family = AF_INET; - peer->addr.sin_port = htons(port); + struct ast_sockaddr *addrs; + + if (ast_sockaddr_resolve(&addrs, data, PARSE_PORT_FORBID, AF_UNSPEC) > 0){ + ast_sockaddr_copy(&peer->addr, &addrs[0]); + ast_free(addrs); + } + ast_sockaddr_set_port(&peer->addr, port); peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); } } @@ -4546,11 +4587,10 @@ static void populate_addr(struct dundi_peer *peer, dundi_eid *eid) static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode) { struct dundi_peer *peer; - struct ast_hostent he; - struct hostent *hp; dundi_eid testeid; int needregister=0; char eid_str[20]; + int port = 0; AST_LIST_LOCK(&peers); AST_LIST_TRAVERSE(&peers, peer, list) { @@ -4567,8 +4607,6 @@ static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode peer->registerid = -1; peer->registerexpire = -1; peer->qualifyid = -1; - peer->addr.sin_family = AF_INET; - peer->addr.sin_port = htons(DUNDI_PORT); populate_addr(peer, eid); AST_LIST_INSERT_HEAD(&peers, peer, list); } @@ -4584,15 +4622,17 @@ static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode } else if (!strcasecmp(v->name, "outkey")) { ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey)); } else if (!strcasecmp(v->name, "port")) { - peer->addr.sin_port = htons(atoi(v->value)); + port = atoi(v->value); } else if (!strcasecmp(v->name, "host")) { if (!strcasecmp(v->value, "dynamic")) { peer->dynamic = 1; } else { - hp = ast_gethostbyname(v->value, &he); - if (hp) { - memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr)); + struct ast_sockaddr *addrs; + + if (ast_sockaddr_resolve(&addrs, v->value, PARSE_PORT_FORBID, AF_UNSPEC) > 0) { + ast_sockaddr_copy(&peer->addr, &addrs[0]); peer->dynamic = 0; + ast_free(addrs); } else { ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno); peer->dead = 1; @@ -4663,6 +4703,11 @@ static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode } } } + + if (!ast_sockaddr_isnull(&peer->addr)) { + ast_sockaddr_set_port(&peer->addr, (0 < port) ? port : DUNDI_PORT); + } + (*globalpcmode) |= peer->pcmodel; if (!peer->model && !peer->pcmodel) { ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", @@ -4811,20 +4856,54 @@ static struct ast_switch dundi_switch = { .matchmore = dundi_matchmore, }; -static int set_config(char *config_file, struct sockaddr_in* sin, int reload) +static int get_ipaddress(char *ip, size_t size, const char *str, int family) +{ + struct ast_sockaddr *addrs; + + if (!ast_sockaddr_resolve(&addrs, str, 0, family)) { + return -1; + } + + ast_copy_string(ip, ast_sockaddr_stringify_host(&addrs[0]), size); + ast_free(addrs); + + return 0; +} + +static void set_host_ipaddr(struct ast_sockaddr *sin) +{ + char hn[MAXHOSTNAMELEN]; + struct addrinfo hints; + int family; + + memset(&hints, 0, sizeof(hints)); + + if (ast_sockaddr_is_ipv6(sin)) { + family = AF_INET6; + } else { + family = AF_INET; + } + + if (gethostname(hn, sizeof(hn) - 1) < 0) { + ast_log(LOG_WARNING, "Unable to get host name!\n"); + return; + } + + get_ipaddress(ipaddr, sizeof(ipaddr), hn, family); +} + +static int set_config(char *config_file, struct ast_sockaddr *sin, int reload) { struct ast_config *cfg; struct ast_variable *v; char *cat; int x; struct ast_flags config_flags = { 0 }; - char hn[MAXHOSTNAMELEN] = ""; - struct ast_hostent he; - struct hostent *hp; - struct sockaddr_in sin2; static int last_port = 0; + int port = 0; int globalpcmodel = 0; dundi_eid testeid; + char bind_addr[80]; if (!(cfg = ast_config_load(config_file, config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) { ast_log(LOG_ERROR, "Unable to load config %s\n", config_file); @@ -4835,16 +4914,6 @@ static int set_config(char *config_file, struct sockaddr_in* sin, int reload) dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME; any_peer = NULL; - ipaddr[0] = '\0'; - if (!gethostname(hn, sizeof(hn)-1)) { - hp = ast_gethostbyname(hn, &he); - if (hp) { - memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr)); - ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr)); - } else - ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn); - } else - ast_log(LOG_WARNING, "Unable to get host name!\n"); AST_LIST_LOCK(&peers); if (ast_eid_is_empty(&ast_eid_default)) { @@ -4857,19 +4926,13 @@ static int set_config(char *config_file, struct sockaddr_in* sin, int reload) v = ast_variable_browse(cfg, "general"); while(v) { if (!strcasecmp(v->name, "port")){ - sin->sin_port = htons(atoi(v->value)); - if(last_port==0){ - last_port=sin->sin_port; - } else if(sin->sin_port != last_port) - ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n"); + port = atoi(v->value); } else if (!strcasecmp(v->name, "bindaddr")) { - struct hostent *hep; - struct ast_hostent hent; - hep = ast_gethostbyname(v->value, &hent); - if (hep) { - memcpy(&sin->sin_addr, hep->h_addr, sizeof(sin->sin_addr)); - } else - ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value); + if (get_ipaddress(bind_addr, sizeof(bind_addr), v->value, AF_UNSPEC) == 0) { + if (!ast_sockaddr_parse(sin, bind_addr, 0)) { + ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value); + } + } } else if (!strcasecmp(v->name, "authdebug")) { authdebug = ast_true(v->value); } else if (!strcasecmp(v->name, "ttl")) { @@ -4924,6 +4987,26 @@ static int set_config(char *config_file, struct sockaddr_in* sin, int reload) } v = v->next; } + + if (port == 0) { + port = DUNDI_PORT; + } + + if (ast_sockaddr_isnull(sin)) { + sprintf(bind_addr, "0.0.0.0:%d", port); + ast_sockaddr_parse(sin, bind_addr, 0); + } else { + ast_sockaddr_set_port(sin, port); + } + + if (last_port == 0) { + last_port = port; + } else if (last_port != port) { + ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n"); + } + + set_host_ipaddr(sin); + AST_LIST_UNLOCK(&peers); mark_mappings(); v = ast_variable_browse(cfg, "mappings"); @@ -4995,7 +5078,9 @@ static int unload_module(void) static int reload(void) { - struct sockaddr_in sin; + struct ast_sockaddr sin; + + ast_sockaddr_setnull(&sin); if (set_config("dundi.conf", &sin, 1)) return AST_MODULE_LOAD_FAILURE; @@ -5005,15 +5090,11 @@ static int reload(void) static int load_module(void) { - struct sockaddr_in sin; + struct ast_sockaddr sin; dundi_set_output(dundi_debug_output); dundi_set_error(dundi_error_output); - sin.sin_family = AF_INET; - sin.sin_port = htons(DUNDI_PORT); - sin.sin_addr.s_addr = INADDR_ANY; - /* Make a UDP socket */ io = io_context_create(); sched = ast_sched_context_create(); @@ -5022,19 +5103,25 @@ static int load_module(void) goto declined; } + ast_sockaddr_setnull(&sin); + if (set_config("dundi.conf", &sin, 0)) { goto declined; } - netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (ast_sockaddr_is_ipv6(&sin)) { + netsocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP); + } else { + netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + } if (netsocket < 0) { ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); goto declined; } - if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) { - ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", - ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno)); + if (ast_bind(netsocket, &sin)) { + ast_log(LOG_ERROR, "Unable to bind to %s : %s\n", + ast_sockaddr_stringify(&sin), strerror(errno)); goto declined; } @@ -5052,7 +5139,7 @@ static int load_module(void) ast_custom_function_register(&dundi_query_function); ast_custom_function_register(&dundi_result_function); - ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + ast_verb(2, "DUNDi Ready and Listening on %s\n", ast_sockaddr_stringify(&sin)); return AST_MODULE_LOAD_SUCCESS;