<p>Adam Secombe has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6173">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">pbx_dundi: Added IPv6 support for dundi<br><br>ASTERISK-27164<br>Reported-by: Adam Secombe<br><br>Change-Id: Ifbe298afc6416ba400db7be404a25994ad23968a<br>---<br>M include/asterisk/dundi.h<br>M pbx/dundi-parser.c<br>M pbx/dundi-parser.h<br>M pbx/pbx_dundi.c<br>4 files changed, 463 insertions(+), 115 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/73/6173/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/include/asterisk/dundi.h b/include/asterisk/dundi.h<br>index 2bffd02..b36aa5d 100644<br>--- a/include/asterisk/dundi.h<br>+++ b/include/asterisk/dundi.h<br>@@ -259,4 +259,10 @@<br> /*! \brief Pre-cache to push upstream peers */<br> int dundi_precache(const char *dcontext, const char *number);<br> <br>+union ip_addr<br>+{<br>+    struct sockaddr_in6 i6;                      <br>+    struct sockaddr_in i4;                    <br>+};<br>+<br> #endif /* _ASTERISK_DUNDI_H */<br>diff --git a/pbx/dundi-parser.c b/pbx/dundi-parser.c<br>index c178fd6..e3b04fa 100644<br>--- a/pbx/dundi-parser.c<br>+++ b/pbx/dundi-parser.c<br>@@ -39,6 +39,8 @@<br> #include "asterisk/dundi.h"<br> #include "dundi-parser.h"<br> <br>+<br>+extern int netsock_ai_family ;<br> static void internaloutput(const char *str)<br> {<br>    fputs(str, stdout);<br>@@ -430,7 +432,7 @@<br>      outputf("\n");<br> }<br> <br>-void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)<br>+void dundi_showframe(struct dundi_hdr *fhi, int rx, union ip_addr *sin, int datalen)<br> {<br>        char *pref[] = {<br>              "Tx",<br>@@ -471,11 +473,25 @@<br>                pref[rx],<br>             fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command");<br>      outputf(tmp);<br>-        snprintf(tmp, (int)sizeof(tmp), <br>-             "%s     Flags: %s STrans: %5.5d  DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? "     " : "",<br>-               subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,<br>-         ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),<br>-            fhi->cmdresp & 0x80 ? " (Final)" : "");<br>+<br>+    if ( netsock_ai_family == AF_INET6)<br>+    {<br>+        char str[INET6_ADDRSTRLEN];<br>+        inet_ntop(AF_INET6, &(sin->i6.sin6_addr), str, INET6_ADDRSTRLEN);<br>+        snprintf(tmp, (int)sizeof(tmp), <br>+            "%s     Flags: %s STrans: %5.5d  DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? "     " : "",<br>+            subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,<br>+            str, ntohs(sin->i6.sin6_port),<br>+            fhi->cmdresp & 0x80 ? " (Final)" : "");<br>+    }<br>+    else<br>+    {<br>+        snprintf(tmp, (int)sizeof(tmp), <br>+            "%s     Flags: %s STrans: %5.5d  DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? "     " : "",<br>+            subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS,<br>+            ast_inet_ntoa(sin->i4.sin_addr), ntohs(sin->i4.sin_port),<br>+            fhi->cmdresp & 0x80 ? " (Final)" : "");<br>+    }<br>     outputf(tmp);<br>         dump_ies(fhi->ies, rx > 1, datalen);<br> }<br>@@ -582,9 +598,13 @@<br>  return 0;<br> }<br> <br>-int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin)<br>+int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, union ip_addr *sin)<br> {<br>-    return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));<br>+#ifdef IPV6<br>+     return dundi_ie_append_raw(ied, ie, &sin->i6, (int)sizeof(sin->i6));<br>+#else<br>+       return dundi_ie_append_raw(ied, ie, &sin->i4, (int)sizeof(sin->i4));<br>+#endif<br> }<br> <br> int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value) <br>diff --git a/pbx/dundi-parser.h b/pbx/dundi-parser.h<br>index b24d486..7174b69 100644<br>--- a/pbx/dundi-parser.h<br>+++ b/pbx/dundi-parser.h<br>@@ -60,12 +60,12 @@<br> extern void dundi_set_output(void (*output)(const char *data));<br> /* Choose a different function for errors */<br> extern void dundi_set_error(void (*output)(const char *data));<br>-extern void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);<br>+extern void dundi_showframe(struct dundi_hdr *fhi, int rx, union ip_addr *sin, int datalen);<br> <br> extern const char *dundi_ie2str(int ie);<br> <br> extern int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen);<br>-extern int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin);<br>+extern int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, union ip_addr *sin);<br> extern int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value);<br> extern int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value);<br> extern int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str);<br>diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c<br>index ff4fa3f..0627797 100644<br>--- a/pbx/pbx_dundi.c<br>+++ b/pbx/pbx_dundi.c<br>@@ -182,6 +182,8 @@<br> #define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME<br> #endif<br> <br>+<br>+<br> static struct io_context *io;<br> static struct ast_sched_context *sched;<br> static int netsocket = -1;<br>@@ -211,6 +213,10 @@<br> static time_t rotatetime;<br> static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } };<br> static int dundi_shutdown = 0;<br>+<br>+<br>+int netsock_ai_family = AF_INET;<br>+<br> <br> struct permission {<br>      AST_LIST_ENTRY(permission) list;<br>@@ -242,8 +248,9 @@<br> <br> struct dundi_request;<br> <br>+<br> struct dundi_transaction {<br>-  struct sockaddr_in addr;                       /*!< Other end of transaction */<br>+    union ip_addr  addr;                            /*!< Other end of transaction */<br>  struct timeval start;                          /*!< When this transaction was created */<br>   dundi_eid eids[DUNDI_MAX_STACK + 1];<br>  int eidcount;                                  /*!< Number of eids in eids */<br>@@ -302,7 +309,7 @@<br> <br> struct dundi_peer {<br>        dundi_eid eid;<br>-       struct sockaddr_in addr;               /*!< Address of DUNDi peer */<br>+    union ip_addr  addr;                    /*!< Address of DUNDi peer */    <br>    AST_LIST_HEAD_NOLOCK(permissionlist, permission) permit;<br>      struct permissionlist include;<br>        dundi_eid us_eid;<br>@@ -352,6 +359,8 @@<br> static struct dundi_peer *any_peer;<br> <br> static int dundi_xmit(struct dundi_packet *pack);<br>+<br>+static int get_ai_family(const char *address);<br> <br> static void dundi_debug_output(const char *data)<br> {<br>@@ -405,16 +414,38 @@<br>              return -1;<br> }<br> <br>+<br>+static force_inline int inaddrcmp6(const struct sockaddr_in6 *sin1, const struct sockaddr_in6 *sin2)<br>+{<br>+    char str1[INET6_ADDRSTRLEN];<br>+    char str2[INET6_ADDRSTRLEN];<br>+<br>+    inet_ntop(AF_INET6, &(sin1->sin6_addr), str1, INET6_ADDRSTRLEN);<br>+    inet_ntop(AF_INET6, &(sin2->sin6_addr), str2, INET6_ADDRSTRLEN);<br>+<br>+    return ((strcmp(str1,str2) != 0) || (sin1->sin6_port != sin2->sin6_port));<br>+}<br>+<br> 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[]);<br> static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]);<br> static struct dundi_transaction *create_transaction(struct dundi_peer *p);<br>-static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct sockaddr_in *sin)<br>+static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, union ip_addr *sin)<br> {<br>     struct dundi_transaction *trans;<br> <br>+    int cmp;<br>    /* Look for an exact match first */<br>   AST_LIST_TRAVERSE(&alltrans, trans, all) {<br>-               if (!inaddrcmp(&trans->addr, sin) &&<br>+        if ( netsock_ai_family == AF_INET6)<br>+        {<br>+            cmp = inaddrcmp6(&trans->addr.i6, &sin->i6);<br>+        }<br>+        else<br>+        {<br>+            cmp = inaddrcmp(&trans->addr.i4, &sin->i4);<br>+        }<br>+<br>+         if (  !cmp &&<br>                      ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ ||<br>                        ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) {<br>                         if (hdr->strans)<br>@@ -450,7 +481,7 @@<br> {<br>        return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL);<br> }<br>-static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin)<br>+static void dundi_reject(struct dundi_hdr *h, union ip_addr *sin)<br> {<br>     struct {<br>              struct dundi_packet pack;<br>@@ -462,7 +493,14 @@<br>               return;<br>       memset(&tmp, 0, sizeof(tmp));<br>     memset(&trans, 0, sizeof(trans));<br>-        memcpy(&trans.addr, sin, sizeof(trans.addr));<br>+    if ( netsock_ai_family == AF_INET6)<br>+    {<br>+      memcpy(&trans.addr, &sin->i6, sizeof(trans.addr.i6));<br>+    }<br>+    else<br>+    {<br>+          memcpy(&trans.addr, &sin->i4, sizeof(trans.addr.i4));<br>+    }<br>  tmp.hdr.strans = h->dtrans;<br>        tmp.hdr.dtrans = h->strans;<br>        tmp.hdr.iseqno = h->oseqno;<br>@@ -1291,8 +1329,16 @@<br> <br> static void apply_peer(struct dundi_transaction *trans, struct dundi_peer *p)<br> {<br>-        if (!trans->addr.sin_addr.s_addr)<br>-         memcpy(&trans->addr, &p->addr, sizeof(trans->addr));<br>+    if ( netsock_ai_family == AF_INET6)<br>+    {<br>+        if (!trans->addr.i6.sin6_addr.s6_addr[0])<br>+            memcpy(&trans->addr.i6, &p->addr.i6, sizeof(struct sockaddr_in6));<br>+    }<br>+    else<br>+    {<br>+        if (!trans->addr.i4.sin_addr.s_addr)<br>+            memcpy(&trans->addr.i4, &p->addr.i4, sizeof(trans->addr.i4));<br>+    }<br>       trans->us_eid = p->us_eid;<br>      trans->them_eid = p->eid;<br>       /* Enable encryption if appropriate */<br>@@ -1706,16 +1752,31 @@<br>                               int needqual = 0;<br>                             AST_SCHED_DEL(sched, peer->registerexpire);<br>                                peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);<br>-                              snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.sin_addr),<br>-                                   ntohs(trans->addr.sin_port), expire);<br>+                if ( netsock_ai_family == AF_INET6)<br>+                {<br>+                    char str[128]={0,};<br>+                    inet_ntop(AF_INET6, &(trans->addr.i6.sin6_addr), str, INET6_ADDRSTRLEN);<br>+                    snprintf(data, sizeof(data), "%s:%d:%d", str,<br>+                        ntohs(trans->addr.i6.sin6_port), expire);<br>+                    if (inaddrcmp6(&peer->addr.i6, &trans->addr.i6)) {<br>+                        ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n",<br>+                                ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>+                                str, ntohs(trans->addr.i6.sin6_port));<br>+                        needqual = 1;<br>+                    }<br>+                }<br>+                else<br>+                {<br>+                    snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(trans->addr.i4.sin_addr),<br>+                        ntohs(trans->addr.i4.sin_port), expire);<br>+                    if (inaddrcmp(&peer->addr.i4, &trans->addr.i4)) {<br>+                        ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n",<br>+                                ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>+                                ast_inet_ntoa(trans->addr.i4.sin_addr), ntohs(trans->addr.i4.sin_port));<br>+                        needqual = 1;<br>+                    }<br>+                }<br>                            ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data);<br>-                             if (inaddrcmp(&peer->addr, &trans->addr)) {<br>-                                    ast_verb(3, "Registered DUNDi peer '%s' at '%s:%d'\n",<br>-                                                     ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>-                                                 ast_inet_ntoa(trans->addr.sin_addr), ntohs(trans->addr.sin_port));<br>-                                     needqual = 1;<br>-                                }<br>-<br>                          memcpy(&peer->addr, &trans->addr, sizeof(peer->addr));<br>                               dundi_ie_append_short(ied, DUNDI_IE_EXPIRATION, default_expiration);<br>                          dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, ied);<br>@@ -1840,7 +1901,16 @@<br>                                                      ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr));<br>                                              if (!ast_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) {<br>                                                     /* If it's them, update our address */<br>-                                                   ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.sin_addr), sizeof(trans->parent->dei->ipaddr));<br>+                            if ( netsock_ai_family == AF_INET6)<br>+                            {<br>+                                char str[80]={0,};<br>+                                inet_ntop(AF_INET6, &(trans->addr.i6.sin6_addr), str, INET6_ADDRSTRLEN);<br>+                                ast_copy_string(trans->parent->dei->ipaddr, str, sizeof(trans->parent->dei->ipaddr));<br>+                            }<br>+                            else<br>+                            {<br>+                                                         ast_copy_string(trans->parent->dei->ipaddr, ast_inet_ntoa(trans->addr.i4.sin_addr), sizeof(trans->parent->dei->ipaddr));<br>+                            }<br>                                             }<br>                                     }<br>                                     if (ies.hint) {<br>@@ -2023,7 +2093,7 @@<br>        return 0;<br> }<br> <br>-static int handle_frame(struct dundi_hdr *h, struct sockaddr_in *sin, int datalen)<br>+static int handle_frame(struct dundi_hdr *h, union ip_addr *sin, int datalen)<br> {<br>     struct dundi_transaction *trans;<br>      trans = find_transaction(h, sin);<br>@@ -2066,13 +2136,20 @@<br> <br> static int socket_read(int *id, int fd, short events, void *cbdata)<br> {<br>-      struct sockaddr_in sin;<br>+    union ip_addr sin;<br>      int res;<br>      struct dundi_hdr *h;<br>  char buf[MAX_PACKET_SIZE];<br>    socklen_t len = sizeof(sin);<br> <br>-      res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len);<br>+    if (netsock_ai_family == AF_INET6)<br>+    {<br>+      res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin.i6, &len);<br>+    }<br>+    else<br>+    {<br>+     res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin.i4, &len);<br>+    }<br>     if (res < 0) {<br>             if (errno != ECONNREFUSED)<br>                    ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));<br>@@ -2625,8 +2702,18 @@<br>               ast_cli(a->fd, "Peer:    %s\n", ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));<br>            ast_cli(a->fd, "Model:   %s\n", model2str(peer->model));<br>              ast_cli(a->fd, "Order:   %s\n", order);<br>-         ast_cli(a->fd, "Host:    %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "<Unspecified>");<br>-               ast_cli(a->fd, "Port:    %d\n", ntohs(peer->addr.sin_port));<br>+        if ( netsock_ai_family == AF_INET6)<br>+        {<br>+            char host[INET6_ADDRSTRLEN]={0,};<br>+            peer->addr.i6.sin6_addr.s6_addr ?  inet_ntop(AF_INET6, &(peer->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN):strcpy(host,"<Unspecified>");<br>+            ast_cli(a->fd, "Host:    %s\n", host);<br>+            ast_cli(a->fd, "Port:     %d\n", ntohs(peer->addr.i6.sin6_port));<br>+        }<br>+        else<br>+        {<br>+            ast_cli(a->fd, "Host:    %s\n", peer->addr.i4.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.i4.sin_addr) : "<Unspecified>");<br>+            ast_cli(a->fd, "Port:    %d\n", ntohs(peer->addr.i4.sin_port));<br>+        }<br>                 ast_cli(a->fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no");<br>            ast_cli(a->fd, "Reg:     %s\n", peer->registerid < 0 ? "No" : "Yes");<br>          ast_cli(a->fd, "In Key:  %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey);<br>@@ -2668,6 +2755,7 @@<br>     int offline_peers = 0;<br>        int unmonitored_peers = 0;<br>    int total_peers = 0;<br>+    char host[INET6_ADDRSTRLEN]={0,};<br>  switch (cmd) {<br>        case CLI_INIT:<br>                e->command = "dundi show peers [registered|include|exclude|begin]";<br>@@ -2697,8 +2785,17 @@<br>              int print_line = -1;<br>          char srch[2000];<br>              total_peers++;<br>-               if (registeredonly && !peer->addr.sin_addr.s_addr)<br>-                        continue;<br>+<br>+        if ( netsock_ai_family == AF_INET6 && registeredonly && !peer->addr.i6.sin6_addr.s6_addr)<br>+        {<br>+            continue;<br>+        }<br>+<br>+        if ( netsock_ai_family == AF_INET && registeredonly && !peer->addr.i4.sin_addr.s_addr)<br>+        {<br>+            continue;<br>+        }<br>+<br>                 if (peer->maxms) {<br>                         if (peer->lastms < 0) {<br>                                 strcpy(status, "UNREACHABLE");<br>@@ -2724,9 +2821,18 @@<br>                      snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms);<br>            else<br>                  strcpy(avgms, "Unavail");<br>-          snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>-                                    peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",<br>-                                   peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status);<br>+        if (netsock_ai_family == AF_INET6)<br>+        {<br>+            peer->addr.i6.sin6_addr.s6_addr ? inet_ntop(AF_INET6, &(peer->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN) : strcpy(host,"(Unspecified)");<br>+            snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),host,<br>+                        peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i6.sin6_port), model2str(peer->model), avgms, status);<br>+        }<br>+        else<br>+        {<br>+            snprintf(srch, sizeof(srch), FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>+                        peer->addr.i4.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.i4.sin_addr) : "(Unspecified)",<br>+                        peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i4.sin_port), model2str(peer->model), avgms, status);<br>+        }<br> <br>                 if (a->argc == 5) {<br>                   if (!strcasecmp(a->argv[3],"include") && strstr(srch,a->argv[4])) {<br>@@ -2741,9 +2847,18 @@<br>                 }<br> <br>         if (print_line) {<br>-                    ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>-                                       peer->addr.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.sin_addr) : "(Unspecified)",<br>-                                   peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.sin_port), model2str(peer->model), avgms, status);<br>+            if ( netsock_ai_family == AF_INET6)<br>+            {<br>+                ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>+                        host,<br>+                        peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i6.sin6_port), model2str(peer->model), avgms, status);<br>+            }<br>+            else<br>+            {<br>+                ast_cli(a->fd, FORMAT, ast_eid_to_str(eid_str, sizeof(eid_str), &peer->eid),<br>+                        peer->addr.i4.sin_addr.s_addr ? ast_inet_ntoa(peer->addr.i4.sin_addr) : "(Unspecified)",<br>+                        peer->dynamic ? "(D)" : "(S)", ntohs(peer->addr.i4.sin_port), model2str(peer->model), avgms, status);<br>+            }<br>          }<br>     }<br>     ast_cli(a->fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers);<br>@@ -2774,8 +2889,19 @@<br>         AST_LIST_LOCK(&peers);<br>    ast_cli(a->fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack");<br>    AST_LIST_TRAVERSE(&alltrans, trans, all) {<br>-               ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.sin_addr),<br>-                    ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);<br>+        if ( netsock_ai_family == AF_INET6)<br>+        {<br>+            char host[INET6_ADDRSTRLEN]={0,};<br>+            inet_ntop(AF_INET6, &(trans->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN);<br>+            ast_cli(a->fd, FORMAT, host,<br>+                ntohs(trans->addr.i6.sin6_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);<br>+        }<br>+        else<br>+        {<br>+            ast_cli(a->fd, FORMAT, ast_inet_ntoa(trans->addr.i4.sin_addr),<br>+                ntohs(trans->addr.i4.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno);<br>+<br>+        }<br>   }<br>     AST_LIST_UNLOCK(&peers);<br>  return CLI_SUCCESS;<br>@@ -3067,7 +3193,7 @@<br>    ast_db_freetree(db_tree);<br> <br>  return CLI_SUCCESS;<br>-#undef FORMAT<br>+#undef FORMATEID<br> #undef FORMAT2<br> }<br> <br>@@ -3095,8 +3221,18 @@<br>        int tid;<br> <br>   /* Don't allow creation of transactions to non-registered peers */<br>-       if (p && !p->addr.sin_addr.s_addr)<br>-                return NULL;<br>+<br>+    if ( netsock_ai_family == AF_INET6)<br>+    {<br>+        if (p && !p->addr.i6.sin6_addr.s6_addr[0])<br>+            return NULL;<br>+    }<br>+    else<br>+    {<br>+          if (p && !p->addr.i4.sin_addr.s_addr)<br>+            return NULL;<br>+    }<br>+<br>    tid = get_trans_id();<br>         if (tid < 1)<br>               return NULL;<br>@@ -3127,9 +3263,20 @@<br>          dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr));<br>   res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr));<br>      if (res < 0) {<br>-            ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n",<br>-                        ast_inet_ntoa(pack->parent->addr.sin_addr),<br>-                    ntohs(pack->parent->addr.sin_port), strerror(errno));<br>+        if ( netsock_ai_family == AF_INET6)<br>+        {<br>+            char host[INET6_ADDRSTRLEN]={0,};<br>+            inet_ntop(AF_INET6, &(pack->parent->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN);<br>+            ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n",<br>+                host,<br>+                ntohs(pack->parent->addr.i6.sin6_port), strerror(errno));<br>+        }<br>+        else<br>+        {<br>+            ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n",<br>+                ast_inet_ntoa(pack->parent->addr.i4.sin_addr),<br>+                ntohs(pack->parent->addr.i4.sin_port), strerror(errno));<br>+         }<br>  }<br>     if (res > 0)<br>               res = 0;<br>@@ -3236,9 +3383,23 @@<br>      if (pack->retrans < 1) {<br>                pack->retransid = -1;<br>              if (!ast_test_flag(pack->parent, FLAG_ISQUAL))<br>-                    ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n",<br>-                            ast_inet_ntoa(pack->parent->addr.sin_addr),<br>-                            ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans));<br>+        {<br>+            if ( netsock_ai_family == AF_INET6)<br>+            {<br>+                char host[INET6_ADDRSTRLEN]={0,};<br>+                inet_ntop(AF_INET6, &(pack->parent->addr.i6.sin6_addr), host, INET6_ADDRSTRLEN);<br>+                ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n",<br>+                    host,<br>+                    ntohs(pack->parent->addr.i6.sin6_port), pack->h->oseqno, ntohs(pack->h->strans));<br>+<br>+            }<br>+            else<br>+            {<br>+                ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n",<br>+                    ast_inet_ntoa(pack->parent->addr.i4.sin_addr),<br>+                    ntohs(pack->parent->addr.i4.sin_port), pack->h->oseqno, ntohs(pack->h->strans));<br>+            }<br>+        }<br>            destroy_trans(pack->parent, 1);<br>            res = 0;<br>      } else {<br>@@ -3593,8 +3754,17 @@<br>      char eid_str2[20];<br> <br>         /* Ignore if not registered */<br>-       if (!p->addr.sin_addr.s_addr)<br>-             return 0;<br>+    if ( netsock_ai_family == AF_INET6)<br>+    {<br>+      if (!p->addr.i6.sin6_addr.s6_addr)<br>+            return 0;<br>+    }<br>+    else<br>+    {<br>+     if (!p->addr.i4.sin_addr.s_addr)<br>+            return 0;<br>+    }<br>+<br>    if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms)))<br>               return 0;<br> <br>@@ -4519,6 +4689,8 @@<br>           }<br>     }<br> }<br>+<br>+// TODO : check address population<br> static void populate_addr(struct dundi_peer *peer, dundi_eid *eid)<br> {<br>        char data[256];<br>@@ -4533,9 +4705,19 @@<br>                       c++;<br>                  if (sscanf(c, "%5d:%30d", &port, &expire) == 2) {<br>                           /* Got it! */<br>-                                inet_aton(data, &peer->addr.sin_addr);<br>-                                peer->addr.sin_family = AF_INET;<br>-                          peer->addr.sin_port = htons(port);<br>+                if ( netsock_ai_family == AF_INET6)<br>+                {<br>+                    inet_pton(AF_INET6, data, &(peer->addr.i6.sin6_addr));<br>+                    peer->addr.i6.sin6_family = AF_INET6;<br>+                    peer->addr.i6.sin6_port = htons(port);<br>+                }<br>+                else<br>+                {<br>+                    inet_aton(data, &peer->addr.i4.sin_addr);<br>+                    peer->addr.i4.sin_family = AF_INET;<br>+                    peer->addr.i4.sin_port = htons(port);<br>+<br>+                }<br>                           peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer);<br>                       }<br>             }<br>@@ -4546,7 +4728,6 @@<br> static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode)<br> {<br>      struct dundi_peer *peer;<br>-     struct ast_hostent he;<br>        struct hostent *hp;<br>   dundi_eid testeid;<br>    int needregister=0;<br>@@ -4567,8 +4748,18 @@<br>           peer->registerid = -1;<br>             peer->registerexpire = -1;<br>                 peer->qualifyid = -1;<br>-             peer->addr.sin_family = AF_INET;<br>-          peer->addr.sin_port = htons(DUNDI_PORT);<br>+<br>+        if ( netsock_ai_family == AF_INET6)<br>+        {<br>+            peer->addr.i6.sin6_family = AF_INET6;<br>+            peer->addr.i6.sin6_port = htons(DUNDI_PORT);<br>+        }<br>+        else<br>+        {<br>+            peer->addr.i4.sin_family = AF_INET;<br>+            peer->addr.i4.sin_port = htons(DUNDI_PORT);<br>+        }<br>+<br>                 populate_addr(peer, eid);<br>             AST_LIST_INSERT_HEAD(&peers, peer, list);<br>         }<br>@@ -4584,19 +4775,36 @@<br>            } else if (!strcasecmp(v->name, "outkey")) {<br>                     ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey));<br>               } else if (!strcasecmp(v->name, "port")) {<br>-                      peer->addr.sin_port = htons(atoi(v->value));<br>+<br>+        if ( netsock_ai_family == AF_INET6)<br>+        {<br>+                      peer->addr.i6.sin6_port = htons(atoi(v->value));<br>+        }<br>+        else<br>+        {<br>+                        peer->addr.i4.sin_port = htons(atoi(v->value));<br>+        }<br>             } else if (!strcasecmp(v->name, "host")) {<br>                       if (!strcasecmp(v->value, "dynamic")) {<br>                          peer->dynamic = 1;<br>                         } else {<br>-                             hp = ast_gethostbyname(v->value, &he);<br>-                                if (hp) {<br>-                                    memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr));<br>-                                  peer->dynamic = 0;<br>-                                } else {<br>-                                     ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);<br>-                                  peer->dead = 1;<br>-                           }<br>+                if ( netsock_ai_family == AF_INET6)<br>+                {<br>+                    inet_pton(AF_INET6, v->value, &(peer->addr.i6.sin6_addr));<br>+                    peer->dynamic = 0;<br>+                }<br>+                else<br>+                {<br>+                    struct ast_hostent  he;<br>+                    hp = ast_gethostbyname(v->value, &he);<br>+                    if (hp) {<br>+                            memcpy(&peer->addr.i4.sin_addr, hp->h_addr, sizeof(peer->addr.i4.sin_addr));<br>+                            peer->dynamic = 0;<br>+                    } else {<br>+                            ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno);<br>+                            peer->dead = 1;<br>+                    }<br>+                }<br>                         }<br>             } else if (!strcasecmp(v->name, "ustothem")) {<br>                   if (!ast_str_to_eid(&testeid, v->value))<br>@@ -4811,7 +5019,32 @@<br>       .matchmore   = dundi_matchmore,<br> };<br> <br>-static int set_config(char *config_file, struct sockaddr_in* sin, int reload)<br>+<br>+static int get_ai_family(const char *address)<br>+{<br>+    struct addrinfo hint, *res = NULL;<br>+    int ret;<br>+<br>+    memset(&hint, '\0', sizeof hint);<br>+<br>+    hint.ai_family = PF_UNSPEC;<br>+    hint.ai_flags = AI_NUMERICHOST;<br>+<br>+    ret = getaddrinfo(address, NULL, &hint, &res);<br>+    if (ret) {<br>+            ast_log(LOG_ERROR, "Invalid address %s \n", address);<br>+        return -1;<br>+    }<br>+<br>+   ret = res->ai_family;<br>+<br>+   freeaddrinfo(res);<br>+<br>+   return ret;<br>+}<br>+<br>+<br>+static int set_config(char *config_file, union ip_addr* sin, int reload)<br> {<br>         struct ast_config *cfg;<br>       struct ast_variable *v;<br>@@ -4819,9 +5052,11 @@<br>       int x;<br>        struct ast_flags config_flags = { 0 };<br>        char hn[MAXHOSTNAMELEN] = "";<br>+    struct hostent *hp;<br>     struct ast_hostent he;<br>-       struct hostent *hp;<br>-  struct sockaddr_in sin2;<br>+     <br>+    union ip_addr sin2;<br>+<br>         static int last_port = 0;<br>     int globalpcmodel = 0;<br>        dundi_eid testeid;<br>@@ -4836,15 +5071,30 @@<br>   any_peer = NULL;<br> <br>   ipaddr[0] = '\0';<br>+<br>  if (!gethostname(hn, sizeof(hn)-1)) {<br>-                hp = ast_gethostbyname(hn, &he);<br>-         if (hp) {<br>-                    memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr));<br>-                    ast_copy_string(ipaddr, ast_inet_ntoa(sin2.sin_addr), sizeof(ipaddr));<br>-               } else<br>-                       ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);<br>+        if ( netsock_ai_family == AF_INET6)<br>+        {<br>+            struct in6_addr ipv6addr;<br>+            strcpy(ipaddr,"::1"); // localaddress<br>+            inet_pton(AF_INET6,ipaddr,&ipv6addr);<br>+            hp =   gethostbyaddr(&ipv6addr, sizeof ipv6addr, AF_INET6);              <br>+            if ( hp) {<br>+                memcpy(&sin2.i6.sin6_addr, hp->h_addr, sizeof(sin2.i6.sin6_addr));<br>+            }<br>+        }<br>+        else<br>+        {<br>+            hp = ast_gethostbyname(hn, &he);<br>+            if (hp) {<br>+                memcpy(&sin2.i4.sin_addr, hp->h_addr, sizeof(sin2.i4.sin_addr));<br>+                ast_copy_string(ipaddr, ast_inet_ntoa(sin2.i4.sin_addr), sizeof(ipaddr));<br>+            }<br>+<br>+        }<br>  } else<br>-               ast_log(LOG_WARNING, "Unable to get host name!\n");<br>+                ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn);<br>+<br>       AST_LIST_LOCK(&peers);<br> <br>         if (ast_eid_is_empty(&ast_eid_default)) {<br>@@ -4857,19 +5107,48 @@<br>        v = ast_variable_browse(cfg, "general");<br>    while(v) {<br>            if (!strcasecmp(v->name, "port")){<br>-                      sin->sin_port = htons(atoi(v->value));<br>-                 if(last_port==0){<br>-                            last_port=sin->sin_port;<br>-                  } else if(sin->sin_port != last_port)<br>-                             ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");<br>+            if ( netsock_ai_family == AF_INET6)<br>+            {<br>+                sin->i6.sin6_port = htons(atoi(v->value));<br>+                if(last_port==0){<br>+                    last_port=sin->i6.sin6_port;<br>+                } else if(sin->i6.sin6_port != last_port)<br>+                    ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");<br>+            }<br>+            else<br>+            {<br>+                sin->i4.sin_port = htons(atoi(v->value));<br>+                if(last_port==0){<br>+                    last_port=sin->i4.sin_port;<br>+                } else if(sin->i4.sin_port != last_port)<br>+                    ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n");<br>+            }<br>              } else if (!strcasecmp(v->name, "bindaddr")) {<br>                   struct hostent *hep;<br>-                 struct ast_hostent hent;<br>-                     hep = ast_gethostbyname(v->value, &hent);<br>-                     if (hep) {<br>-                           memcpy(&sin->sin_addr, hep->h_addr, sizeof(sin->sin_addr));<br>-                     } else<br>-                               ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);<br>+<br>+            netsock_ai_family = get_ai_family(v->value);<br>+            if ( netsock_ai_family == -1)<br>+            {<br>+                return -1;<br>+            }<br>+            <br>+            if( netsock_ai_family == AF_INET6)<br>+            {<br>+                if ( inet_pton(AF_INET6,v->value, &(sin->i6.sin6_addr)) < 0 )<br>+                {<br>+                    ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);<br>+                }<br>+            }<br>+            else<br>+            {<br>+                struct ast_hostent hent;<br>+                hep = ast_gethostbyname(v->value, &hent);<br>+                if (hep) {<br>+                    memcpy(&sin->i4.sin_addr, hep->h_addr, sizeof(sin->i4.sin_addr));<br>+                } else<br>+                    ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value);<br>+            }<br>+<br>                } else if (!strcasecmp(v->name, "authdebug")) {<br>                  authdebug = ast_true(v->value);<br>            } else if (!strcasecmp(v->name, "ttl")) {<br>@@ -4994,7 +5273,7 @@<br> <br> static int reload(void)<br> {<br>-       struct sockaddr_in sin;<br>+    union ip_addr sin;<br> <br>   if (set_config("dundi.conf", &sin, 1))<br>          return AST_MODULE_LOAD_FAILURE;<br>@@ -5004,44 +5283,81 @@<br> <br> static int load_module(void)<br> {<br>-       struct sockaddr_in sin;<br>+    union ip_addr sin;<br> <br>   dundi_set_output(dundi_debug_output);<br>         dundi_set_error(dundi_error_output);<br>-<br>-      sin.sin_family = AF_INET;<br>-    sin.sin_port = htons(DUNDI_PORT);<br>-    sin.sin_addr.s_addr = INADDR_ANY;<br> <br>  /* Make a UDP socket */<br>       io = io_context_create();<br>     sched = ast_sched_context_create();<br> <br>-       if (!io || !sched) {<br>-         goto declined;<br>-       }<br>+    if (!io || !sched)<br>+           return AST_MODULE_LOAD_DECLINE;<br> <br>-   if (set_config("dundi.conf", &sin, 0)) {<br>-               goto declined;<br>-       }<br>+    memset(&sin,0,sizeof(union ip_addr));<br> <br>- netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);<br>+ if (set_config("dundi.conf", &sin, 0))<br>+         return AST_MODULE_LOAD_DECLINE;<br>+<br>+    if ( netsock_ai_family == AF_INET6)<br>+    {<br>+        sin.i6.sin6_family = AF_INET6;<br>+        if ( sin.i6.sin6_port == 0 )<br>+        {<br>+            sin.i6.sin6_port = htons(DUNDI_PORT);<br>+        }<br>+        if ( sin.i6.sin6_addr.s6_addr[0] == 0)<br>+        {<br>+            sin.i6.sin6_addr = in6addr_any;<br>+        }<br>+          netsocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);<br>+    }<br>+    else<br>+    {<br>+        sin.i4.sin_family = AF_INET;<br>+        if ( sin.i4.sin_port == 0 )<br>+        {<br>+            sin.i4.sin_port = htons(DUNDI_PORT);<br>+        }<br>+        if ( !sin.i4.sin_addr.s_addr)<br>+        {<br>+            sin.i4.sin_addr.s_addr = INADDR_ANY;<br>+        }<br>+          netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);<br>+    }<br> <br>   if (netsocket < 0) {<br>               ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));<br>-              goto declined;<br>+               return AST_MODULE_LOAD_DECLINE;<br>       }<br>-    if (bind(netsocket, (struct sockaddr *) &sin, sizeof(sin))) {<br>-            ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n",<br>-                   ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), strerror(errno));<br>-          goto declined;<br>-       }<br>+<br>+    if ( netsock_ai_family == AF_INET6)<br>+    {<br>+       char str[128]={0,};<br>+        inet_ntop(AF_INET6, &(sin.i6.sin6_addr), str, INET6_ADDRSTRLEN);<br>+        if (bind(netsocket, (struct sockaddr_in6 *) &sin.i6, sizeof(sin.i6))) {<br>+            ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n",<br>+                str, ntohs(sin.i6.sin6_port), strerror(errno));<br>+            return AST_MODULE_LOAD_DECLINE;<br>+        }<br>+    }<br>+    else<br>+    {<br>+        if (bind(netsocket, (struct sockaddr *) &sin.i4, sizeof(sin.i4))) {<br>+            ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n",<br>+                ast_inet_ntoa(sin.i4.sin_addr), ntohs(sin.i4.sin_port), strerror(errno));<br>+            return AST_MODULE_LOAD_DECLINE;<br>+        }<br>+    }<br>+<br> <br>       ast_set_qos(netsocket, tos, 0, "DUNDi");<br> <br>         if (start_network_thread()) {<br>                 ast_log(LOG_ERROR, "Unable to start network thread\n");<br>-            goto declined;<br>+               close(netsocket);<br>+            return AST_MODULE_LOAD_DECLINE;<br>       }<br> <br>  ast_cli_register_multiple(cli_dundi, ARRAY_LEN(cli_dundi));<br>@@ -5051,13 +5367,19 @@<br>  ast_custom_function_register(&dundi_query_function);<br>      ast_custom_function_register(&dundi_result_function);<br> <br>- ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));<br>+    if (netsock_ai_family == AF_INET6)<br>+    {<br>+        char str[128]={0,};<br>+        inet_ntop(AF_INET6, &(sin.i6.sin6_addr), str, INET6_ADDRSTRLEN);<br>+        ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", str, ntohs(sin.i6.sin6_port));<br>+    }<br>+    else<br>+    {<br>+       ast_verb(2, "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(sin.i4.sin_addr), ntohs(sin.i4.sin_port));<br>+    }   <br>+<br> <br>      return AST_MODULE_LOAD_SUCCESS;<br>-<br>-declined:<br>-       unload_module();<br>-     return AST_MODULE_LOAD_DECLINE;<br> }<br> <br> AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Distributed Universal Number Discovery (DUNDi)",<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6173">change 6173</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6173"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 13 </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ifbe298afc6416ba400db7be404a25994ad23968a </div>
<div style="display:none"> Gerrit-Change-Number: 6173 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Adam Secombe <adam.j.secombe@boeing.com> </div>