diff -Nur asterisk-13.9.1-orig/include/asterisk/dundi.h asterisk-13.9.1-patched/include/asterisk/dundi.h --- asterisk-13.9.1-orig/include/asterisk/dundi.h 2017-05-05 09:15:25.409702138 +1000 +++ asterisk-13.9.1-patched/include/asterisk/dundi.h 2017-05-08 10:34:22.669052340 +1000 @@ -259,4 +259,10 @@ /*! \brief Pre-cache to push upstream peers */ int dundi_precache(const char *dcontext, const char *number); +union ip_addr +{ + struct sockaddr_in6 i6; + struct sockaddr_in i4; +}; + #endif /* _ASTERISK_DUNDI_H */ diff -Nur asterisk-13.9.1-orig/pbx/dundi-parser.c asterisk-13.9.1-patched/pbx/dundi-parser.c --- asterisk-13.9.1-orig/pbx/dundi-parser.c 2017-05-05 09:15:25.403702138 +1000 +++ asterisk-13.9.1-patched/pbx/dundi-parser.c 2017-05-08 10:30:41.765055395 +1000 @@ -39,6 +39,8 @@ #include "asterisk/dundi.h" #include "dundi-parser.h" + +extern int netsock_ai_family ; static void internaloutput(const char *str) { fputs(str, stdout); @@ -430,7 +432,7 @@ 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, union ip_addr *sin, int datalen) { char *pref[] = { "Tx", @@ -471,11 +473,25 @@ 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) ? " " : "", - subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS, - ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), - fhi->cmdresp & 0x80 ? " (Final)" : ""); + + if ( netsock_ai_family == AF_INET6) + { + char str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(sin->i6.sin6_addr), str, INET6_ADDRSTRLEN); + snprintf(tmp, (int)sizeof(tmp), + "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "", + subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS, + str, ntohs(sin->i6.sin6_port), + fhi->cmdresp & 0x80 ? " (Final)" : ""); + } + else + { + snprintf(tmp, (int)sizeof(tmp), + "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "", + subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS, + ast_inet_ntoa(sin->i4.sin_addr), ntohs(sin->i4.sin_port), + fhi->cmdresp & 0x80 ? " (Final)" : ""); + } outputf(tmp); dump_ies(fhi->ies, rx > 1, datalen); } @@ -582,9 +598,13 @@ return 0; } -int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin) +int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, union ip_addr *sin) { - return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in)); +#ifdef IPV6 + return dundi_ie_append_raw(ied, ie, &sin->i6, (int)sizeof(sin->i6)); +#else + return dundi_ie_append_raw(ied, ie, &sin->i4, (int)sizeof(sin->i4)); +#endif } int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value) diff -Nur asterisk-13.9.1-orig/pbx/dundi-parser.h asterisk-13.9.1-patched/pbx/dundi-parser.h --- asterisk-13.9.1-orig/pbx/dundi-parser.h 2017-05-05 09:15:25.403702138 +1000 +++ asterisk-13.9.1-patched/pbx/dundi-parser.h 2017-05-08 10:37:52.537049438 +1000 @@ -60,12 +60,12 @@ 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, union ip_addr *sin, int datalen); extern const char *dundi_ie2str(int ie); extern int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen); -extern int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin); +extern int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, union ip_addr *sin); extern int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value); extern int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value); extern int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str); diff -Nur asterisk-13.9.1-orig/pbx/pbx_dundi.c asterisk-13.9.1-patched/pbx/pbx_dundi.c --- asterisk-13.9.1-orig/pbx/pbx_dundi.c 2017-05-05 09:15:25.403702138 +1000 +++ asterisk-13.9.1-patched/pbx/pbx_dundi.c 2017-05-10 10:59:28.788511651 +1000 @@ -182,6 +182,8 @@ #define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME #endif + + static struct io_context *io; static struct ast_sched_context *sched; static int netsocket = -1; @@ -212,6 +214,10 @@ static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } }; static int dundi_shutdown = 0; + +int netsock_ai_family = AF_INET; + + struct permission { AST_LIST_ENTRY(permission) list; int allow; @@ -242,8 +248,9 @@ struct dundi_request; + struct dundi_transaction { - struct sockaddr_in addr; /*!< Other end of transaction */ + union ip_addr 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 */ @@ -302,7 +309,7 @@ struct dundi_peer { dundi_eid eid; - struct sockaddr_in addr; /*!< Address of DUNDi peer */ + union ip_addr addr; /*!< Address of DUNDi peer */ AST_LIST_HEAD_NOLOCK(permissionlist, permission) permit; struct permissionlist include; dundi_eid us_eid; @@ -353,6 +360,8 @@ static int dundi_xmit(struct dundi_packet *pack); +static int get_ai_family(const char *address); + static void dundi_debug_output(const char *data) { if (dundidebug) @@ -405,16 +414,38 @@ return -1; } + +static force_inline int inaddrcmp6(const struct sockaddr_in6 *sin1, const struct sockaddr_in6 *sin2) +{ + char str1[INET6_ADDRSTRLEN]; + char str2[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, &(sin1->sin6_addr), str1, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &(sin2->sin6_addr), str2, INET6_ADDRSTRLEN); + + return ((strcmp(str1,str2) != 0) || (sin1->sin6_port != sin2->sin6_port)); +} + 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, union ip_addr *sin) { struct dundi_transaction *trans; + int cmp; /* Look for an exact match first */ AST_LIST_TRAVERSE(&alltrans, trans, all) { - if (!inaddrcmp(&trans->addr, sin) && + if ( netsock_ai_family == AF_INET6) + { + cmp = inaddrcmp6(&trans->addr.i6, &sin->i6); + } + else + { + cmp = inaddrcmp(&trans->addr.i4, &sin->i4); + } + + if ( !cmp && ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ || ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) { if (hdr->strans) @@ -450,7 +481,7 @@ { 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, union ip_addr *sin) { struct { struct dundi_packet pack; @@ -462,7 +493,14 @@ return; memset(&tmp, 0, sizeof(tmp)); memset(&trans, 0, sizeof(trans)); - memcpy(&trans.addr, sin, sizeof(trans.addr)); + if ( netsock_ai_family == AF_INET6) + { + memcpy(&trans.addr, &sin->i6, sizeof(trans.addr.i6)); + } + else + { + memcpy(&trans.addr, &sin->i4, sizeof(trans.addr.i4)); + } tmp.hdr.strans = h->dtrans; tmp.hdr.dtrans = h->strans; tmp.hdr.iseqno = h->oseqno; @@ -1291,8 +1329,16 @@ 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 ( netsock_ai_family == AF_INET6) + { + if (!trans->addr.i6.sin6_addr.s6_addr[0]) + memcpy(&trans->addr.i6, &p->addr.i6, sizeof(struct sockaddr_in6)); + } + else + { + if (!trans->addr.i4.sin_addr.s_addr) + memcpy(&trans->addr.i4, &p->addr.i4, sizeof(trans->addr.i4)); + } trans->us_eid = p->us_eid; trans->them_eid = p->eid; /* Enable encryption if appropriate */ @@ -1706,16 +1752,31 @@ 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); + if ( netsock_ai_family == AF_INET6) + { + char str[128]={0,}; + inet_ntop(AF_INET6, &(trans->addr.i6.sin6_addr), str, INET6_ADDRSTRLEN); + snprintf(data, sizeof(data), "%s:%d:%d", str, + ntohs(trans->addr.i6.sin6_port), expire); + if (inaddrcmp6(&peer->addr.i6, &trans->addr.i6)) { + ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n", + ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), + str, ntohs(trans->addr.i6.sin6_port)); + needqual = 1; + } + } + else + { + snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.i4.sin_addr), + ntohs(trans->addr.i4.sin_port), expire); + if (inaddrcmp(&peer->addr.i4, &trans->addr.i4)) { + 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.i4.sin_addr), ntohs(trans->addr.i4.sin_port)); + needqual = 1; + } + } 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)); - needqual = 1; - } - memcpy(&peer->addr, &trans->addr, sizeof(peer->addr)); dundi_ie_append_short(ied, DUNDI_IE_EXPIRATION, default_expiration); dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied); @@ -1840,7 +1901,16 @@ 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)); + if ( netsock_ai_family == AF_INET6) + { + char str[80]={0,}; + inet_ntop(AF_INET6, &(trans->addr.i6.sin6_addr), str, INET6_ADDRSTRLEN); + ast_copy_string(trans->parent->dei->ipaddr, str, sizeof(trans->parent->dei->ipaddr)); + } + else + { + ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.i4.sin_addr), sizeof(trans->parent->dei->ipaddr)); + } } } if (ies.hint) { @@ -2023,7 +2093,7 @@ return 0; } -static int handle_frame(struct dundi_hdr *h, struct sockaddr_in *sin, int datalen) +static int handle_frame(struct dundi_hdr *h, union ip_addr *sin, int datalen) { struct dundi_transaction *trans; trans = find_transaction(h, sin); @@ -2066,13 +2136,20 @@ static int socket_read(int *id, int fd, short events, void *cbdata) { - struct sockaddr_in sin; + union ip_addr 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); + if (netsock_ai_family == AF_INET6) + { + res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin.i6, &len); + } + else + { + res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin.i4, &len); + } if (res < 0) { if (errno != ECONNREFUSED) ast_log(LOG_WARNING, "Error: %s\n", strerror(errno)); @@ -2625,8 +2702,18 @@ 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)); + if ( netsock_ai_family == AF_INET6) + { + char host[INET6_ADDRSTRLEN]={0,}; + peer->addr.i6.sin6_addr.s6_addr ? inet_ntop(AF_INET6, &(peer->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN):strcpy(host,""); + ast_cli(a->fd, "Host: %s\n", host); + ast_cli(a->fd, "Port: %d\n", ntohs(peer->addr.i6.sin6_port)); + } + else + { + ast_cli(a->fd, "Host: %s\n", peer->addr.i4.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.i4.sin_addr) : ""); + ast_cli(a->fd, "Port: %d\n", ntohs(peer->addr.i4.sin_port)); + } 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); @@ -2668,6 +2755,7 @@ int offline_peers = 0; int unmonitored_peers = 0; int total_peers = 0; + char host[INET6_ADDRSTRLEN]={0,}; switch (cmd) { case CLI_INIT: e->command = "dundi show peers [registered|include|exclude|begin]"; @@ -2697,8 +2785,17 @@ int print_line = -1; char srch[2000]; total_peers++; - if (registeredonly && !peer->addr.sin_addr.s_addr) - continue; + + if ( netsock_ai_family == AF_INET6 && registeredonly && !peer->addr.i6.sin6_addr.s6_addr) + { + continue; + } + + if ( netsock_ai_family == AF_INET && registeredonly && !peer->addr.i4.sin_addr.s_addr) + { + continue; + } + if (peer->maxms) { if (peer->lastms < 0) { strcpy(status, "UNREACHABLE"); @@ -2724,9 +2821,18 @@ 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); + if (netsock_ai_family == AF_INET6) + { + peer->addr.i6.sin6_addr.s6_addr ? inet_ntop(AF_INET6, &(peer->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN) : strcpy(host,"(Unspecified)"); + snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),host, + peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i6.sin6_port), model2str(peer->model), avgms, status); + } + else + { + snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), + peer->addr.i4.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.i4.sin_addr) : "(Unspecified)", + peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i4.sin_port), model2str(peer->model), avgms, status); + } if (a->argc == 5) { if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) { @@ -2741,9 +2847,18 @@ } 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); + if ( netsock_ai_family == AF_INET6) + { + ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), + host, + peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i6.sin6_port), model2str(peer->model), avgms, status); + } + else + { + ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), + peer->addr.i4.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.i4.sin_addr) : "(Unspecified)", + peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i4.sin_port), 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); @@ -2774,8 +2889,19 @@ 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); + if ( netsock_ai_family == AF_INET6) + { + char host[INET6_ADDRSTRLEN]={0,}; + inet_ntop(AF_INET6, &(trans->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN); + ast_cli(a->fd, FORMAT, host, + ntohs(trans->addr.i6.sin6_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno); + } + else + { + ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.i4.sin_addr), + ntohs(trans->addr.i4.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno); + + } } AST_LIST_UNLOCK(&peers); return CLI_SUCCESS; @@ -3067,7 +3193,7 @@ ast_db_freetree(db_tree); return CLI_SUCCESS; -#undef FORMAT +#undef FORMATEID #undef FORMAT2 } @@ -3095,8 +3221,18 @@ int tid; /* Don't allow creation of transactions to non-registered peers */ - if (p && !p->addr.sin_addr.s_addr) - return NULL; + + if ( netsock_ai_family == AF_INET6) + { + if (p && !p->addr.i6.sin6_addr.s6_addr[0]) + return NULL; + } + else + { + if (p && !p->addr.i4.sin_addr.s_addr) + return NULL; + } + tid = get_trans_id(); if (tid < 1) return NULL; @@ -3127,9 +3263,20 @@ 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)); 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)); + if ( netsock_ai_family == AF_INET6) + { + char host[INET6_ADDRSTRLEN]={0,}; + inet_ntop(AF_INET6, &(pack->parent->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN); + ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", + host, + ntohs(pack->parent->addr.i6.sin6_port), strerror(errno)); + } + else + { + ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", + ast_inet_ntoa(pack->parent->addr.i4.sin_addr), + ntohs(pack->parent->addr.i4.sin_port), strerror(errno)); + } } if (res > 0) res = 0; @@ -3236,9 +3383,23 @@ 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 ( netsock_ai_family == AF_INET6) + { + char host[INET6_ADDRSTRLEN]={0,}; + inet_ntop(AF_INET6, &(pack->parent->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN); + ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", + host, + ntohs(pack->parent->addr.i6.sin6_port), pack->h->oseqno, ntohs(pack->h->strans)); + + } + else + { + ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", + ast_inet_ntoa(pack->parent->addr.i4.sin_addr), + ntohs(pack->parent->addr.i4.sin_port), pack->h->oseqno, ntohs(pack->h->strans)); + } + } destroy_trans(pack->parent, 1); res = 0; } else { @@ -3593,8 +3754,17 @@ char eid_str2[20]; /* Ignore if not registered */ - if (!p->addr.sin_addr.s_addr) - return 0; + if ( netsock_ai_family == AF_INET6) + { + if (!p->addr.i6.sin6_addr.s6_addr) + return 0; + } + else + { + if (!p->addr.i4.sin_addr.s_addr) + return 0; + } + if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms))) return 0; @@ -4519,6 +4689,8 @@ } } } + +// TODO : check address population static void populate_addr(struct dundi_peer *peer, dundi_eid *eid) { char data[256]; @@ -4533,9 +4705,19 @@ 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); + if ( netsock_ai_family == AF_INET6) + { + inet_pton(AF_INET6, data, &(peer->addr.i6.sin6_addr)); + peer->addr.i6.sin6_family = AF_INET6; + peer->addr.i6.sin6_port = htons(port); + } + else + { + inet_aton(data, &peer->addr.i4.sin_addr); + peer->addr.i4.sin_family = AF_INET; + peer->addr.i4.sin_port = htons(port); + + } peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); } } @@ -4546,7 +4728,6 @@ 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; @@ -4567,8 +4748,18 @@ peer->registerid = -1; peer->registerexpire = -1; peer->qualifyid = -1; - peer->addr.sin_family = AF_INET; - peer->addr.sin_port = htons(DUNDI_PORT); + + if ( netsock_ai_family == AF_INET6) + { + peer->addr.i6.sin6_family = AF_INET6; + peer->addr.i6.sin6_port = htons(DUNDI_PORT); + } + else + { + peer->addr.i4.sin_family = AF_INET; + peer->addr.i4.sin_port = htons(DUNDI_PORT); + } + populate_addr(peer, eid); AST_LIST_INSERT_HEAD(&peers, peer, list); } @@ -4584,19 +4775,36 @@ } 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)); + + if ( netsock_ai_family == AF_INET6) + { + peer->addr.i6.sin6_port = htons(atoi(v->value)); + } + else + { + peer->addr.i4.sin_port = htons(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)); - peer->dynamic = 0; - } else { - ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno); - peer->dead = 1; - } + if ( netsock_ai_family == AF_INET6) + { + inet_pton(AF_INET6, v->value, &(peer->addr.i6.sin6_addr)); + peer->dynamic = 0; + } + else + { + struct ast_hostent he; + hp = ast_gethostbyname(v->value, &he); + if (hp) { + memcpy(&peer->addr.i4.sin_addr, hp->h_addr, sizeof(peer->addr.i4.sin_addr)); + peer->dynamic = 0; + } else { + ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno); + peer->dead = 1; + } + } } } else if (!strcasecmp(v->name, "ustothem")) { if (!ast_str_to_eid(&testeid, v->value)) @@ -4811,7 +5019,32 @@ .matchmore = dundi_matchmore, }; -static int set_config(char *config_file, struct sockaddr_in* sin, int reload) + +static int get_ai_family(const char *address) +{ + struct addrinfo hint, *res = NULL; + int ret; + + memset(&hint, '\0', sizeof hint); + + hint.ai_family = PF_UNSPEC; + hint.ai_flags = AI_NUMERICHOST; + + ret = getaddrinfo(address, NULL, &hint, &res); + if (ret) { + ast_log(LOG_ERROR, "Invalid address %s \n", address); + return -1; + } + + ret = res->ai_family; + + freeaddrinfo(res); + + return ret; +} + + +static int set_config(char *config_file, union ip_addr* sin, int reload) { struct ast_config *cfg; struct ast_variable *v; @@ -4819,9 +5052,11 @@ int x; struct ast_flags config_flags = { 0 }; char hn[MAXHOSTNAMELEN] = ""; + struct hostent *hp; struct ast_hostent he; - struct hostent *hp; - struct sockaddr_in sin2; + + union ip_addr sin2; + static int last_port = 0; int globalpcmodel = 0; dundi_eid testeid; @@ -4836,15 +5071,30 @@ 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); + if ( netsock_ai_family == AF_INET6) + { + struct in6_addr ipv6addr; + strcpy(ipaddr,"::1"); // localaddress + inet_pton(AF_INET6,ipaddr,&ipv6addr); + hp = gethostbyaddr(&ipv6addr, sizeof ipv6addr, AF_INET6); + if ( hp) { + memcpy(&sin2.i6.sin6_addr, hp->h_addr, sizeof(sin2.i6.sin6_addr)); + } + } + else + { + hp = ast_gethostbyname(hn, &he); + if (hp) { + memcpy(&sin2.i4.sin_addr, hp->h_addr, sizeof(sin2.i4.sin_addr)); + ast_copy_string(ipaddr, ast_inet_ntoa(sin2.i4.sin_addr), sizeof(ipaddr)); + } + + } } else - ast_log(LOG_WARNING, "Unable to get host name!\n"); + ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn); + AST_LIST_LOCK(&peers); memcpy(&global_eid, &ast_eid_default, sizeof(global_eid)); @@ -4854,19 +5104,48 @@ 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"); + if ( netsock_ai_family == AF_INET6) + { + sin->i6.sin6_port = htons(atoi(v->value)); + if(last_port==0){ + last_port=sin->i6.sin6_port; + } else if(sin->i6.sin6_port != last_port) + ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n"); + } + else + { + sin->i4.sin_port = htons(atoi(v->value)); + if(last_port==0){ + last_port=sin->i4.sin_port; + } else if(sin->i4.sin_port != last_port) + ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n"); + } } 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); + + netsock_ai_family = get_ai_family(v->value); + if ( netsock_ai_family == -1) + { + return -1; + } + + if( netsock_ai_family == AF_INET6) + { + if ( inet_pton(AF_INET6,v->value, &(sin->i6.sin6_addr)) < 0 ) + { + ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value); + } + } + else + { + struct ast_hostent hent; + hep = ast_gethostbyname(v->value, &hent); + if (hep) { + memcpy(&sin->i4.sin_addr, hep->h_addr, sizeof(sin->i4.sin_addr)); + } else + 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")) { @@ -4991,7 +5270,7 @@ static int reload(void) { - struct sockaddr_in sin; + union ip_addr sin; if (set_config("dundi.conf", &sin, 1)) return AST_MODULE_LOAD_FAILURE; @@ -5001,44 +5280,81 @@ static int load_module(void) { - struct sockaddr_in sin; + union ip_addr 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(); - if (!io || !sched) { - goto declined; - } + if (!io || !sched) + return AST_MODULE_LOAD_DECLINE; - if (set_config("dundi.conf", &sin, 0)) { - goto declined; - } + memset(&sin,0,sizeof(union ip_addr)); - netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (set_config("dundi.conf", &sin, 0)) + return AST_MODULE_LOAD_DECLINE; + + if ( netsock_ai_family == AF_INET6) + { + sin.i6.sin6_family = AF_INET6; + if ( sin.i6.sin6_port == 0 ) + { + sin.i6.sin6_port = htons(DUNDI_PORT); + } + if ( sin.i6.sin6_addr.s6_addr[0] == 0) + { + sin.i6.sin6_addr = in6addr_any; + } + netsocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP); + } + else + { + sin.i4.sin_family = AF_INET; + if ( sin.i4.sin_port == 0 ) + { + sin.i4.sin_port = htons(DUNDI_PORT); + } + if ( !sin.i4.sin_addr.s_addr) + { + sin.i4.sin_addr.s_addr = INADDR_ANY; + } + 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)); - goto declined; + return AST_MODULE_LOAD_DECLINE; } + if ( netsock_ai_family == AF_INET6) + { + char str[128]={0,}; + inet_ntop(AF_INET6, &(sin.i6.sin6_addr), str, INET6_ADDRSTRLEN); + if (bind(netsocket, (struct sockaddr_in6 *) &sin.i6, sizeof(sin.i6))) { + ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", + str, ntohs(sin.i6.sin6_port), strerror(errno)); + return AST_MODULE_LOAD_DECLINE; + } + } + else + { + if (bind(netsocket, (struct sockaddr *) &sin.i4, sizeof(sin.i4))) { + ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", + ast_inet_ntoa(sin.i4.sin_addr), ntohs(sin.i4.sin_port), strerror(errno)); + return AST_MODULE_LOAD_DECLINE; + } + } + + ast_set_qos(netsocket, tos, 0, "DUNDi"); if (start_network_thread()) { ast_log(LOG_ERROR, "Unable to start network thread\n"); - goto declined; + close(netsocket); + return AST_MODULE_LOAD_DECLINE; } ast_cli_register_multiple(cli_dundi, ARRAY_LEN(cli_dundi)); @@ -5048,13 +5364,19 @@ 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)); + if (netsock_ai_family == AF_INET6) + { + char str[128]={0,}; + inet_ntop(AF_INET6, &(sin.i6.sin6_addr), str, INET6_ADDRSTRLEN); + ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", str, ntohs(sin.i6.sin6_port)); + } + else + { + ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.i4.sin_addr), ntohs(sin.i4.sin_port)); + } - return AST_MODULE_LOAD_SUCCESS; -declined: - unload_module(); - return AST_MODULE_LOAD_DECLINE; + return AST_MODULE_LOAD_SUCCESS; } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Distributed Universal Number Discovery (DUNDi)", Binary files asterisk-13.9.1-orig/pbx/.pbx_dundi.c.swp and asterisk-13.9.1-patched/pbx/.pbx_dundi.c.swp differ