Add IPv6 Support To chan_iax2
authorMichael L. Young <elgueromexicano@gmail.com>
Fri, 4 Oct 2013 21:41:58 +0000 (21:41 +0000)
committerMichael L. Young <elgueromexicano@gmail.com>
Fri, 4 Oct 2013 21:41:58 +0000 (21:41 +0000)
This patch adds IPv6 support to chan_iax2.  Yay!

(closes issue ASTERISK-22025)
Patches:
  iax2-ipv6-v5-reviewboard.diff by Michael L. Young (license 5026)

Review: https://reviewboard.asterisk.org/r/2660/
........

Merged revisions 400567 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400568 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
channels/chan_iax2.c
channels/iax2/include/parser.h
channels/iax2/parser.c
include/asterisk/netsock2.h
main/acl.c
main/netsock.c
main/netsock2.c

diff --git a/CHANGES b/CHANGES
index 9f91afe..6fc2b37 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -770,7 +770,6 @@ Stasis Message Bus
    Stasis can be configured in stasis.conf. Note that these parameters operate
    at a very low level in Asterisk, and generally will not require changes.
 
-
 Channel Drivers
 ------------------
  * When a channel driver is configured to enable jiterbuffers, they are now
@@ -815,6 +814,11 @@ chan_dahdi
    specified to be created, or the keyword 'new' can be used to add channels
    not yet created.
 
+chan_iax2
+------------------
+ * IPv6 support has been added.  We are now able to bind to and
+   communicate using IPv6 addresses.
+
 chan_local
 ------------------
  * The /b option has been removed.
index 77fd442..1bbf18e 100644 (file)
@@ -110,7 +110,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/taskprocessor.h"
 #include "asterisk/test.h"
 #include "asterisk/data.h"
-#include "asterisk/netsock2.h"
 #include "asterisk/security_events.h"
 #include "asterisk/stasis_endpoints.h"
 #include "asterisk/bridge.h"
@@ -538,12 +537,12 @@ struct iax2_peer {
        struct ast_sockaddr addr;
        int formats;
        int sockfd;                                     /*!< Socket to use for transmission */
-       struct in_addr mask;
+       struct ast_sockaddr mask;
        int adsi;
        uint64_t flags;
 
        /* Dynamic Registration fields */
-       struct sockaddr_in defaddr;                     /*!< Default address if there is one */
+       struct ast_sockaddr defaddr;                    /*!< Default address if there is one */
        int authmethods;                                /*!< Authentication methods (IAX_AUTH_*) */
        int encmethods;                                 /*!< Encryption methods (IAX_ENCRYPT_*) */
 
@@ -576,7 +575,7 @@ struct iax2_peer {
 struct iax2_trunk_peer {
        ast_mutex_t lock;
        int sockfd;
-       struct sockaddr_in addr;
+       struct ast_sockaddr addr;
        struct timeval txtrunktime;             /*!< Transmit trunktime */
        struct timeval rxtrunktime;             /*!< Receive trunktime */
        struct timeval lasttxtime;              /*!< Last transmitted trunktime */
@@ -627,7 +626,7 @@ struct iax2_registry {
        enum iax_reg_state regstate;
        int messages;                           /*!< Message count, low 8 bits = new, high 8 bits = old */
        int callno;                             /*!< Associated call number if applicable */
-       struct sockaddr_in us;                  /*!< Who the server thinks we are */
+       struct ast_sockaddr us;                 /*!< Who the server thinks we are */
        struct ast_dnsmgr_entry *dnsmgr;        /*!< DNS refresh manager */
        AST_LIST_ENTRY(iax2_registry) entry;
 };
@@ -707,7 +706,7 @@ struct chan_iax2_pvt {
        /*! Max time for initial response */
        int maxtime;
        /*! Peer Address */
-       struct sockaddr_in addr;
+       struct ast_sockaddr addr;
        /*! Actual used codec preferences */
        struct ast_codec_pref prefs;
        /*! Requested codec preferences */
@@ -823,7 +822,7 @@ struct chan_iax2_pvt {
        /*! Transfer identifier */
        int transferid;
        /*! Who we are IAX transferring to */
-       struct sockaddr_in transfer;
+       struct ast_sockaddr transfer;
        /*! What's the new call number for the transfer */
        unsigned short transfercallno;
        /*! Transfer encrypt AES-128 Key */
@@ -955,7 +954,7 @@ static uint16_t total_nonval_callno_used = 0;
  *  consumed by a single ip address */
 struct peercnt {
        /*! ip address consuming call numbers */
-       unsigned long addr;
+       struct ast_sockaddr addr;
        /*! Number of call numbers currently used by this ip address */
        uint16_t cur;
        /*! Max call numbers allowed for this ip address */
@@ -1009,8 +1008,8 @@ struct iax2_dpcache {
 static AST_LIST_HEAD_STATIC(dpcache, iax2_dpcache);
 
 static void reg_source_db(struct iax2_peer *p);
-static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
-static struct iax2_user *realtime_user(const char *username, struct sockaddr_in *sin);
+static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr *addr);
+static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr *addr);
 
 static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt);
 static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, uint64_t flags);
@@ -1048,7 +1047,7 @@ struct iax2_thread {
        int actions;
        pthread_t threadid;
        int threadnum;
-       struct sockaddr_in iosin;
+       struct ast_sockaddr ioaddr;
        unsigned char readbuf[4096];
        unsigned char *buf;
        ssize_t buf_len;
@@ -1065,7 +1064,7 @@ struct iax2_thread {
          frames for that callno to other threads */
        struct {
                unsigned short callno;
-               struct sockaddr_in sin;
+               struct ast_sockaddr addr;
                unsigned char type;
                unsigned char csub;
        } ffinfo;
@@ -1159,20 +1158,21 @@ static struct ao2_container *iax_transfercallno_pvts;
 #define TRUNK_CALL_START       (IAX_MAX_CALLS / 2)
 
 /* Debug routines... */
-static struct sockaddr_in debugaddr;
+static struct ast_sockaddr debugaddr;
 
-static void iax_outputframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
+static void iax_outputframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen)
 {
        if (iaxdebug ||
-           (sin && debugaddr.sin_addr.s_addr &&
-            (!ntohs(debugaddr.sin_port) ||
-             debugaddr.sin_port == sin->sin_port) &&
-            debugaddr.sin_addr.s_addr == sin->sin_addr.s_addr)) {
+           (addr && !ast_sockaddr_isnull(&debugaddr) &&
+               (!ast_sockaddr_port(&debugaddr) ||
+                 ast_sockaddr_port(&debugaddr) == ast_sockaddr_port(addr)) &&
+                 !ast_sockaddr_cmp_addr(&debugaddr, addr))) {
+
                if (iaxdebug) {
-                       iax_showframe(f, fhi, rx, sin, datalen);
+                       iax_showframe(f, fhi, rx, addr, datalen);
                } else {
                        iaxdebug = 1;
-                       iax_showframe(f, fhi, rx, sin, datalen);
+                       iax_showframe(f, fhi, rx, addr, datalen);
                        iaxdebug = 0;
                }
        }
@@ -1236,7 +1236,7 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
 static int iax2_hangup(struct ast_channel *c);
 static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-static int iax2_provision(struct sockaddr_in *end, int sockfd, const char *dest, const char *template, int force);
+static int iax2_provision(struct ast_sockaddr *end, int sockfd, const char *dest, const char *template, int force);
 static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
 static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen);
 static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
@@ -1270,7 +1270,7 @@ static void build_ecx_key(const unsigned char *digest, struct chan_iax2_pvt *pvt
 static void build_rand_pad(unsigned char *buf, ssize_t len);
 static int get_unused_callno(enum callno_type type, int validated, callno_entry *entry);
 static int replace_callno(const void *obj);
-static void sched_delay_remove(struct sockaddr_in *sin, callno_entry entry);
+static void sched_delay_remove(struct ast_sockaddr *addr, callno_entry entry);
 static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
 
@@ -1853,9 +1853,9 @@ static struct iax2_peer *find_peer(const char *name, int realtime)
        peer = ao2_find(peers, name, OBJ_KEY);
 
        /* Now go for realtime if applicable */
-       if(!peer && realtime)
+       if (!peer && realtime) {
                peer = realtime_peer(name, NULL);
-
+       }
        return peer;
 }
 
@@ -1887,7 +1887,7 @@ static inline struct iax2_user *user_unref(struct iax2_user *user)
        return NULL;
 }
 
-static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
+static int iax2_getpeername(struct ast_sockaddr addr, char *host, int len)
 {
        struct iax2_peer *peer = NULL;
        int res = 0;
@@ -1895,12 +1895,8 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
 
        i = ao2_iterator_init(peers, 0);
        while ((peer = ao2_iterator_next(&i))) {
-               struct sockaddr_in peer_addr;
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
-               if ((peer_addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
-                   (peer_addr.sin_port == sin.sin_port)) {
+               if (!ast_sockaddr_cmp(&peer->addr, &addr)) {
                        ast_copy_string(host, peer->name, len);
                        peer_unref(peer);
                        res = 1;
@@ -1911,7 +1907,7 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
        ao2_iterator_destroy(&i);
 
        if (!peer) {
-               peer = realtime_peer(NULL, &sin);
+               peer = realtime_peer(NULL, &addr);
                if (peer) {
                        ast_copy_string(host, peer->name, len);
                        peer_unref(peer);
@@ -2068,7 +2064,7 @@ static void pvt_destructor(void *obj)
 
 }
 
-static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
+static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host)
 {
        struct chan_iax2_pvt *tmp;
        jb_conf jbconf;
@@ -2139,10 +2135,9 @@ enum {
        NEW_ALLOW_CALLTOKEN_VALIDATED = 3,
 };
 
-static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
+static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
 {
-       if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
-               (cur->addr.sin_port == sin->sin_port)) {
+       if (!ast_sockaddr_cmp(&cur->addr, addr)) {
                /* This is the main host */
                if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
                         (check_dcallno ? dcallno == cur->callno : 1) ) {
@@ -2150,8 +2145,7 @@ static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short
                        return 1;
                }
        }
-       if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
-           (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+       if (!ast_sockaddr_cmp(&cur->transfer, addr) && cur->transferring) {
                /* We're transferring */
                if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
                        return 1;
@@ -2274,9 +2268,7 @@ static int addr_range_delme_cb(void *obj, void *arg, int flags)
 static int addr_range_hash_cb(const void *obj, const int flags)
 {
        const struct addr_range *lim = obj;
-       struct sockaddr_in sin;
-       ast_sockaddr_to_sin(&lim->ha.addr, &sin);
-       return abs((int) sin.sin_addr.s_addr);
+       return abs(ast_sockaddr_hash(&lim->ha.addr));
 }
 
 static int addr_range_cmp_cb(void *obj, void *arg, int flags)
@@ -2290,26 +2282,28 @@ static int addr_range_cmp_cb(void *obj, void *arg, int flags)
 static int peercnt_hash_cb(const void *obj, const int flags)
 {
        const struct peercnt *peercnt = obj;
-       return abs((int) peercnt->addr);
+
+       if (ast_sockaddr_isnull(&peercnt->addr)) {
+               return 0;
+       }
+       return ast_sockaddr_hash(&peercnt->addr);
 }
 
 static int peercnt_cmp_cb(void *obj, void *arg, int flags)
 {
        struct peercnt *peercnt1 = obj, *peercnt2 = arg;
-       return (peercnt1->addr == peercnt2->addr) ? CMP_MATCH | CMP_STOP : 0;
+       return !ast_sockaddr_cmp_addr(&peercnt1->addr, &peercnt2->addr) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 static int addr_range_match_address_cb(void *obj, void *arg, int flags)
 {
        struct addr_range *addr_range = obj;
-       struct sockaddr_in *sin = arg;
-       struct sockaddr_in ha_netmask_sin;
-       struct sockaddr_in ha_addr_sin;
+       struct ast_sockaddr *addr = arg;
+       struct ast_sockaddr tmp_addr;
 
-       ast_sockaddr_to_sin(&addr_range->ha.netmask, &ha_netmask_sin);
-       ast_sockaddr_to_sin(&addr_range->ha.addr, &ha_addr_sin);
+       ast_sockaddr_apply_netmask(addr, &addr_range->ha.netmask, &tmp_addr);
 
-       if ((sin->sin_addr.s_addr & ha_netmask_sin.sin_addr.s_addr) == ha_addr_sin.sin_addr.s_addr) {
+       if (!ast_sockaddr_cmp_addr(&tmp_addr, &addr_range->ha.addr)) {
                return CMP_MATCH | CMP_STOP;
        }
        return 0;
@@ -2318,9 +2312,9 @@ static int addr_range_match_address_cb(void *obj, void *arg, int flags)
 /*!
  * \internal
  *
- * \brief compares sin to calltoken_ignores table to determine if validation is required.
+ * \brief compares addr to calltoken_ignores table to determine if validation is required.
  */
-static int calltoken_required(struct sockaddr_in *sin, const char *name, int subclass)
+static int calltoken_required(struct ast_sockaddr *addr, const char *name, int subclass)
 {
        struct addr_range *addr_range;
        struct iax2_peer *peer = NULL;
@@ -2337,7 +2331,7 @@ static int calltoken_required(struct sockaddr_in *sin, const char *name, int sub
         */
 
        /* ----- Case 1 ----- */
-       if ((addr_range = ao2_callback(calltoken_ignores, 0, addr_range_match_address_cb, sin))) {
+       if ((addr_range = ao2_callback(calltoken_ignores, 0, addr_range_match_address_cb, addr))) {
                ao2_ref(addr_range, -1);
                optional = 1;
        }
@@ -2345,11 +2339,11 @@ static int calltoken_required(struct sockaddr_in *sin, const char *name, int sub
        /* ----- Case 2 ----- */
        if ((subclass == IAX_COMMAND_NEW) && (user = find_user(find))) {
                calltoken_required = user->calltoken_required;
-       } else if ((subclass == IAX_COMMAND_NEW) && (user = realtime_user(find, sin))) {
+       } else if ((subclass == IAX_COMMAND_NEW) && (user = realtime_user(find, addr))) {
                calltoken_required = user->calltoken_required;
        } else if ((subclass != IAX_COMMAND_NEW) && (peer = find_peer(find, 0))) {
                calltoken_required = peer->calltoken_required;
-       } else if ((subclass != IAX_COMMAND_NEW) && (peer = realtime_peer(find, sin))) {
+       } else if ((subclass != IAX_COMMAND_NEW) && (peer = realtime_peer(find, addr))) {
                calltoken_required = peer->calltoken_required;
        }
 
@@ -2360,7 +2354,7 @@ static int calltoken_required(struct sockaddr_in *sin, const char *name, int sub
                user_unref(user);
        }
 
-       ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %d \n", ast_inet_ntoa(sin->sin_addr), name, optional, calltoken_required);
+       ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %d \n", ast_sockaddr_stringify_addr(addr), name, optional, calltoken_required);
        if (((calltoken_required == CALLTOKEN_NO) || (calltoken_required == CALLTOKEN_AUTO)) ||
                (optional && (calltoken_required == CALLTOKEN_DEFAULT))) {
                res = 0;
@@ -2383,18 +2377,17 @@ static void set_peercnt_limit(struct peercnt *peercnt)
 {
        uint16_t limit = global_maxcallno;
        struct addr_range *addr_range;
-       struct sockaddr_in sin = {
-               .sin_addr.s_addr = peercnt->addr,
-       };
+       struct ast_sockaddr addr;
 
+       ast_sockaddr_copy(&addr, &peercnt->addr);
 
        if (peercnt->reg && peercnt->limit) {
                return; /* this peercnt has a custom limit set by a registration */
        }
 
-       if ((addr_range = ao2_callback(callno_limits, 0, addr_range_match_address_cb, &sin))) {
+       if ((addr_range = ao2_callback(callno_limits, 0, addr_range_match_address_cb, &addr))) {
                limit = addr_range->limit;
-               ast_debug(1, "custom addr_range %d found for %s\n", limit, ast_inet_ntoa(sin.sin_addr));
+               ast_debug(1, "custom addr_range %d found for %s\n", limit, ast_sockaddr_stringify(&addr));
                ao2_ref(addr_range, -1);
        }
 
@@ -2434,14 +2427,9 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
 {
        /* this function turns off and on custom callno limits set by peer registration */
        struct peercnt *peercnt;
-       struct peercnt tmp = {
-               .addr = 0,
-       };
-       struct sockaddr_in sin;
-
-       ast_sockaddr_to_sin(sockaddr, &sin);
+       struct peercnt tmp;
 
-       tmp.addr = sin.sin_addr.s_addr;
+       ast_sockaddr_copy(&tmp.addr, sockaddr);
 
        if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
                peercnt->reg = reg;
@@ -2450,7 +2438,7 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
                } else {
                        set_peercnt_limit(peercnt);
                }
-               ast_debug(1, "peercnt entry %s modified limit:%d registered:%d", ast_inet_ntoa(sin.sin_addr), peercnt->limit, peercnt->reg);
+               ast_debug(1, "peercnt entry %s modified limit:%d registered:%d", ast_sockaddr_stringify_addr(sockaddr), peercnt->limit, peercnt->reg);
                ao2_ref(peercnt, -1); /* decrement ref from find */
        }
 }
@@ -2463,14 +2451,13 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
  * the current count is incremented.  If not found a new peercnt is allocated
  * and linked into the peercnts table with a call number count of 1.
  */
-static int peercnt_add(struct sockaddr_in *sin)
+static int peercnt_add(struct ast_sockaddr *addr)
 {
        struct peercnt *peercnt;
-       unsigned long addr = sin->sin_addr.s_addr;
        int res = 0;
-       struct peercnt tmp = {
-               .addr = addr,
-       };
+       struct peercnt tmp;
+
+       ast_sockaddr_copy(&tmp.addr, addr);
 
        /* Reasoning for peercnts container lock:  Two identical ip addresses
         * could be added by different threads at the "same time". Without the container
@@ -2484,7 +2471,7 @@ static int peercnt_add(struct sockaddr_in *sin)
        } else if ((peercnt = ao2_alloc(sizeof(*peercnt), NULL))) {
                ao2_lock(peercnt);
                /* create and set defaults */
-               peercnt->addr = addr;
+               ast_sockaddr_copy(&peercnt->addr, addr);
                set_peercnt_limit(peercnt);
                /* guarantees it does not go away after unlocking table
                 * ao2_find automatically adds this */
@@ -2497,9 +2484,9 @@ static int peercnt_add(struct sockaddr_in *sin)
        /* check to see if the address has hit its callno limit.  If not increment cur. */
        if (peercnt->limit > peercnt->cur) {
                peercnt->cur++;
-               ast_debug(1, "ip callno count incremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin->sin_addr));
+               ast_debug(1, "ip callno count incremented to %d for %s\n", peercnt->cur, ast_sockaddr_stringify_addr(addr));
        } else { /* max num call numbers for this peer has been reached! */
-               ast_log(LOG_ERROR, "maxcallnumber limit of %d for %s has been reached!\n", peercnt->limit, ast_inet_ntoa(sin->sin_addr));
+               ast_log(LOG_ERROR, "maxcallnumber limit of %d for %s has been reached!\n", peercnt->limit, ast_sockaddr_stringify_addr(addr));
                res = -1;
        }
 
@@ -2517,9 +2504,9 @@ static int peercnt_add(struct sockaddr_in *sin)
  */
 static void peercnt_remove(struct peercnt *peercnt)
 {
-       struct sockaddr_in sin = {
-               .sin_addr.s_addr = peercnt->addr,
-       };
+       struct ast_sockaddr addr;
+
+       ast_sockaddr_copy(&addr, &peercnt->addr);
 
        /*
         * Container locked here since peercnt may be unlinked from
@@ -2529,7 +2516,7 @@ static void peercnt_remove(struct peercnt *peercnt)
         */
        ao2_lock(peercnts);
        peercnt->cur--;
-       ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin.sin_addr));
+       ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_sockaddr_stringify_addr(&addr));
        /* if this was the last connection from the peer remove it from table */
        if (peercnt->cur == 0) {
                ao2_unlink(peercnts, peercnt);/* decrements ref from table, last ref is left to scheduler */
@@ -2555,12 +2542,12 @@ static int peercnt_remove_cb(const void *obj)
  * \internal
  * \brief decrements peercnts connection count, finds by addr
  */
-static int peercnt_remove_by_addr(struct sockaddr_in *sin)
+static int peercnt_remove_by_addr(struct ast_sockaddr *addr)
 {
        struct peercnt *peercnt;
-       struct peercnt tmp = {
-               .addr = sin->sin_addr.s_addr,
-       };
+       struct peercnt tmp;
+
+       ast_sockaddr_copy(&tmp.addr, addr);
 
        if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
                peercnt_remove(peercnt);
@@ -2673,7 +2660,7 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
 {
        struct ao2_iterator i;
        struct peercnt *peercnt;
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        int found = 0;
 
        switch (cmd) {
@@ -2690,22 +2677,23 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
                        return CLI_SHOWUSAGE;
 
                if (a->argc == 4) {
-                       ast_cli(a->fd, "%-15s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
+                       ast_cli(a->fd, "%-45s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
                }
 
                i = ao2_iterator_init(peercnts, 0);
                while ((peercnt = ao2_iterator_next(&i))) {
-                       sin.sin_addr.s_addr = peercnt->addr;
+                       ast_sockaddr_copy(&addr, &peercnt->addr);
+
                        if (a->argc == 5) {
-                               if (!strcasecmp(a->argv[4], ast_inet_ntoa(sin.sin_addr))) {
-                                       ast_cli(a->fd, "%-15s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
-                                       ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
+                               if (!strcasecmp(a->argv[4], ast_sockaddr_stringify(&addr))) {
+                                       ast_cli(a->fd, "%-45s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
+                                       ast_cli(a->fd, "%-45s %-12d %-12d\n", ast_sockaddr_stringify(&addr), peercnt->cur, peercnt->limit);
                                        ao2_ref(peercnt, -1);
                                        found = 1;
                                        break;
                                }
                        } else {
-                               ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
+                               ast_cli(a->fd, "%-45s %-12d %-12d\n", ast_sockaddr_stringify(&addr), peercnt->cur, peercnt->limit);
                        }
                        ao2_ref(peercnt, -1);
                }
@@ -2886,17 +2874,17 @@ static int create_callno_pools(void)
  * avaliable again, and the address from the previous connection must be decremented
  * from the peercnts table.  This function schedules these operations to take place.
  */
-static void sched_delay_remove(struct sockaddr_in *sin, callno_entry entry)
+static void sched_delay_remove(struct ast_sockaddr *addr, callno_entry entry)
 {
        int i;
        struct peercnt *peercnt;
-       struct peercnt tmp = {
-               .addr = sin->sin_addr.s_addr,
-       };
+       struct peercnt tmp;
+
+       ast_sockaddr_copy(&tmp.addr, addr);
 
        if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
                /* refcount is incremented with ao2_find.  keep that ref for the scheduler */
-               ast_debug(1, "schedule decrement of callno used for %s in %d seconds\n", ast_inet_ntoa(sin->sin_addr), MIN_REUSE_TIME);
+               ast_debug(1, "schedule decrement of callno used for %s in %d seconds\n", ast_sockaddr_stringify_addr(addr), MIN_REUSE_TIME);
                i = iax2_sched_add(sched, MIN_REUSE_TIME * 1000, peercnt_remove_cb, peercnt);
                if (i == -1) {
                        ao2_ref(peercnt, -1);
@@ -2940,7 +2928,7 @@ static inline int attribute_pure iax2_allow_new(int frametype, int subclass, int
 /*
  * \note Calling this function while holding another pvt lock can cause a deadlock.
  */
-static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno)
+static int __find_callno(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int return_locked, int check_dcallno)
 {
        int res = 0;
        int x;
@@ -2960,7 +2948,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                                .frames_received = check_dcallno,
                        };
 
-                       memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
+                       ast_sockaddr_copy(&tmp_pvt.addr, addr);
                        /* this works for finding normal call numbers not involving transfering */
                        if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
                                if (return_locked) {
@@ -2973,7 +2961,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                        }
                        /* this searches for transfer call numbers that might not get caught otherwise */
                        memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr));
-                       memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.transfer));
+                       ast_sockaddr_copy(&tmp_pvt.transfer, addr);
                        if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
                                if (return_locked) {
                                        ast_mutex_lock(&iaxsl[pvt->callno]);
@@ -2989,7 +2977,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                if (dcallno) {
                        ast_mutex_lock(&iaxsl[dcallno]);
                }
-               if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(sin, callno, dcallno, iaxs[dcallno], check_dcallno)) {
+               if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(addr, callno, dcallno, iaxs[dcallno], check_dcallno)) {
                        iaxs[dcallno]->peercallno = callno;
                        res = dcallno;
                        store_by_peercallno(iaxs[dcallno]);
@@ -3004,16 +2992,17 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
        }
        if (!res && (new >= NEW_ALLOW)) {
                callno_entry entry;
+
                /* It may seem odd that we look through the peer list for a name for
                 * this *incoming* call.  Well, it is weird.  However, users don't
                 * have an IP address/port number that we can match against.  So,
                 * this is just checking for a peer that has that IP/port and
                 * assuming that we have a user of the same name.  This isn't always
                 * correct, but it will be changed if needed after authentication. */
-               if (!iax2_getpeername(*sin, host, sizeof(host)))
-                       snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               if (!iax2_getpeername(*addr, host, sizeof(host)))
+                       snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(addr));
 
-               if (peercnt_add(sin)) {
+               if (peercnt_add(addr)) {
                        /* This address has hit its callnumber limit.  When the limit
                         * is reached, the connection is not added to the peercnts table.*/
                        return 0;
@@ -3022,22 +3011,20 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                if (get_unused_callno(CALLNO_TYPE_NORMAL, validated, &entry)) {
                        /* since we ran out of space, remove the peercnt
                         * entry we added earlier */
-                       peercnt_remove_by_addr(sin);
+                       peercnt_remove_by_addr(addr);
                        ast_log(LOG_WARNING, "No more space\n");
                        return 0;
                }
                x = CALLNO_ENTRY_GET_CALLNO(entry);
                ast_mutex_lock(&iaxsl[x]);
 
-               iaxs[x] = new_iax(sin, host);
+               iaxs[x] = new_iax(addr, host);
                if (iaxs[x]) {
                        if (iaxdebug)
                                ast_debug(1, "Creating new call structure %d\n", x);
                        iaxs[x]->callno_entry = entry;
                        iaxs[x]->sockfd = sockfd;
-                       iaxs[x]->addr.sin_port = sin->sin_port;
-                       iaxs[x]->addr.sin_family = sin->sin_family;
-                       iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;
+                       ast_sockaddr_copy(&iaxs[x]->addr, addr);
                        iaxs[x]->peercallno = callno;
                        iaxs[x]->callno = x;
                        iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
@@ -3067,13 +3054,13 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
        return res;
 }
 
-static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
-       return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);
+static int find_callno(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int full_frame) {
+       return __find_callno(callno, dcallno, addr, new, sockfd, 0, full_frame);
 }
 
-static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
+static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int full_frame) {
 
-       return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
+       return __find_callno(callno, dcallno, addr, new, sockfd, 1, full_frame);
 }
 
 /*!
@@ -3222,11 +3209,11 @@ static int handle_error(void)
        return 0;
 }
 
-static int transmit_trunk(struct iax_frame *f, struct sockaddr_in *sin, int sockfd)
+static int transmit_trunk(struct iax_frame *f, struct ast_sockaddr *addr, int sockfd)
 {
        int res;
-       res = sendto(sockfd, f->data, f->datalen, 0,(struct sockaddr *)sin,
-                                       sizeof(*sin));
+       res = ast_sendto(sockfd, f->data, f->datalen, 0, addr);
+
        if (res < 0) {
                ast_debug(1, "Received error: %s\n", strerror(errno));
                handle_error();
@@ -3245,15 +3232,15 @@ static int send_packet(struct iax_frame *f)
            return -1;
 
        /* Called with iaxsl held */
-       if (iaxdebug)
-               ast_debug(3, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));
-
+       if (iaxdebug) {
+               ast_debug(3, "Sending %d on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
+       }
        if (f->transfer) {
                iax_outputframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
-               res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer, sizeof(iaxs[callno]->transfer));
+               res = ast_sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0, &iaxs[callno]->transfer);
        } else {
                iax_outputframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr));
-               res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr, sizeof(iaxs[callno]->addr));
+               res = ast_sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0, &iaxs[callno]->addr);
        }
        if (res < 0) {
                if (iaxdebug)
@@ -3406,7 +3393,7 @@ static void __attempt_transmit(const void *data)
                        } else {
                                if (iaxs[callno]->owner) {
                                        ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %u, ts=%d, seqno=%d)\n",
-                                               ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),
+                                               ast_sockaddr_stringify_addr(&iaxs[f->callno]->addr),
                                                ast_channel_name(iaxs[f->callno]->owner),
                                                f->af.frametype,
                                                f->af.subclass.integer,
@@ -3677,9 +3664,13 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
 
        peer = find_peer(a->argv[3], load_realtime);
        if (peer) {
-               struct sockaddr_in peer_addr;
+               char *str_addr, *str_defaddr;
+               char *str_port, *str_defport;
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+               str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&peer->addr));
+               str_port = ast_strdupa(ast_sockaddr_stringify_port(&peer->addr));
+               str_defaddr = ast_strdupa(ast_sockaddr_stringify_addr(&peer->defaddr));
+               str_defport = ast_strdupa(ast_sockaddr_stringify_port(&peer->defaddr));
 
                encmethods_to_str(peer->encmethods, &encmethods);
                ast_cli(a->fd, "\n\n");
@@ -3697,8 +3688,8 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
                ast_cli(a->fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
                ast_cli(a->fd, "  Expire       : %d\n", peer->expire);
                ast_cli(a->fd, "  ACL          : %s\n", (ast_acl_list_is_empty(peer->acl) ? "No" : "Yes"));
-               ast_cli(a->fd, "  Addr->IP     : %s Port %d\n",  peer_addr.sin_addr.s_addr ? ast_inet_ntoa(peer_addr.sin_addr) : "(Unspecified)", ntohs(peer_addr.sin_port));
-               ast_cli(a->fd, "  Defaddr->IP  : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
+               ast_cli(a->fd, "  Addr->IP     : %s Port %s\n",  str_addr ? str_addr : "(Unspecified)", str_port);
+               ast_cli(a->fd, "  Defaddr->IP  : %s Port %s\n", str_defaddr, str_defport);
                ast_cli(a->fd, "  Username     : %s\n", peer->username);
                ast_cli(a->fd, "  Codecs       : ");
                iax2_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
@@ -4241,22 +4232,25 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
  * \note This function calls reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call this with a pvt lock held.
  */
-static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
+static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr *addr)
 {
        struct ast_variable *var = NULL;
        struct ast_variable *tmp;
        struct iax2_peer *peer=NULL;
        time_t regseconds = 0, nowtime;
        int dynamic=0;
+       char *str_addr, *str_port;
+
+       str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+       str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
 
        if (peername) {
                var = ast_load_realtime("iaxpeers", "name", peername, "host", "dynamic", SENTINEL);
-               if (!var && sin)
-                       var = ast_load_realtime("iaxpeers", "name", peername, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
-       } else if (sin) {
-               char porta[25];
-               sprintf(porta, "%d", ntohs(sin->sin_port));
-               var = ast_load_realtime("iaxpeers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
+               if (!var && !ast_sockaddr_isnull(addr)) {
+                       var = ast_load_realtime("iaxpeers", "name", peername, "host", str_addr, SENTINEL);
+               }
+       } else if (!ast_sockaddr_isnull(addr)) {
+               var = ast_load_realtime("iaxpeers", "ipaddr", str_addr, "port", str_port, SENTINEL);
                if (var) {
                        /* We'll need the peer name in order to build the structure! */
                        for (tmp = var; tmp; tmp = tmp->next) {
@@ -4273,12 +4267,13 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
                 * is because we only have the IP address and the host field might be
                 * set as a name (and the reverse PTR might not match).
                 */
-               if (var && sin) {
+               if (var && !ast_sockaddr_isnull(addr)) {
                        for (tmp = var; tmp; tmp = tmp->next) {
                                if (!strcasecmp(tmp->name, "host")) {
-                                       struct ast_hostent ahp;
-                                       struct hostent *hp;
-                                       if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &sin->sin_addr, hp->h_length)) {
+                                       struct ast_sockaddr *hostaddr;
+
+                                       if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, 0)
+                                               || ast_sockaddr_cmp_addr(hostaddr, addr)) {
                                                /* No match */
                                                ast_variables_destroy(var);
                                                var = NULL;
@@ -4310,11 +4305,19 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
                } else if (!strcasecmp(tmp->name, "regseconds")) {
                        ast_get_time_t(tmp->value, &regseconds, 0, NULL);
                } else if (!strcasecmp(tmp->name, "ipaddr")) {
-                       if (!ast_sockaddr_parse(&peer->addr, tmp->value, PARSE_PORT_IGNORE)) {
+                       int setport = ast_sockaddr_port(&peer->addr);
+                       if (ast_parse_arg(tmp->value, PARSE_ADDR | PARSE_PORT_FORBID, NULL)) {
                                ast_log(LOG_WARNING, "Failed to parse sockaddr '%s' for ipaddr of realtime peer '%s'\n", tmp->value, tmp->name);
+                       } else {
+                               ast_sockaddr_parse(&peer->addr, tmp->value, 0);
                        }
+                       ast_sockaddr_set_port(&peer->addr, setport);
                } else if (!strcasecmp(tmp->name, "port")) {
-                       ast_sockaddr_set_port(&peer->addr, atoi(tmp->value));
+                       int bindport;
+                       if (ast_parse_arg(tmp->value, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
+                               bindport = IAX_DEFAULT_PORTNO;
+                       }
+                       ast_sockaddr_set_port(&peer->addr, bindport);
                } else if (!strcasecmp(tmp->name, "host")) {
                        if (!strcasecmp(tmp->value, "dynamic"))
                                dynamic = 1;
@@ -4323,9 +4326,6 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
 
        ast_variables_destroy(var);
 
-       if (!peer)
-               return NULL;
-
        if (ast_test_flag64((&globalflags), IAX_RTCACHEFRIENDS)) {
                ast_copy_flags64(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
                if (ast_test_flag64(peer, IAX_RTAUTOCLEAR)) {
@@ -4363,21 +4363,23 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
        return peer;
 }
 
-static struct iax2_user *realtime_user(const char *username, struct sockaddr_in *sin)
+static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr *addr)
 {
        struct ast_variable *var;
        struct ast_variable *tmp;
        struct iax2_user *user=NULL;
+       char *str_addr, *str_port;
+
+       str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+       str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
 
        var = ast_load_realtime("iaxusers", "name", username, "host", "dynamic", SENTINEL);
        if (!var)
-               var = ast_load_realtime("iaxusers", "name", username, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
-       if (!var && sin) {
-               char porta[6];
-               snprintf(porta, sizeof(porta), "%d", ntohs(sin->sin_port));
-               var = ast_load_realtime("iaxusers", "name", username, "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
+               var = ast_load_realtime("iaxusers", "name", username, "host", str_addr, SENTINEL);
+       if (!var && !ast_sockaddr_isnull(addr)) {
+               var = ast_load_realtime("iaxusers", "name", username, "ipaddr", str_addr, "port", str_port, SENTINEL);
                if (!var)
-                       var = ast_load_realtime("iaxusers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
+                       var = ast_load_realtime("iaxusers", "ipaddr", str_addr, "port", str_port, SENTINEL);
        }
        if (!var) { /* Last ditch effort */
                var = ast_load_realtime("iaxusers", "name", username, SENTINEL);
@@ -4390,9 +4392,10 @@ static struct iax2_user *realtime_user(const char *username, struct sockaddr_in
                if (var) {
                        for (tmp = var; tmp; tmp = tmp->next) {
                                if (!strcasecmp(tmp->name, "host")) {
-                                       struct ast_hostent ahp;
-                                       struct hostent *hp;
-                                       if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &sin->sin_addr, hp->h_length)) {
+                                       struct ast_sockaddr *hostaddr;
+
+                                       if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, 0)
+                                               || ast_sockaddr_cmp_addr(hostaddr, addr)) {
                                                /* No match */
                                                ast_variables_destroy(var);
                                                var = NULL;
@@ -4436,10 +4439,10 @@ static struct iax2_user *realtime_user(const char *username, struct sockaddr_in
 
 static void realtime_update_peer(const char *peername, struct ast_sockaddr *sockaddr, time_t regtime)
 {
-       char port[10];
        char regseconds[20];
        const char *sysname = ast_config_AST_SYSTEM_NAME;
        char *syslabel = NULL;
+       char *port;
 
        if (ast_strlen_zero(sysname))   /* No system name, disable this */
                sysname = NULL;
@@ -4447,9 +4450,10 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *sock
                syslabel = "regserver";
 
        snprintf(regseconds, sizeof(regseconds), "%d", (int)regtime);
-       snprintf(port, sizeof(port), "%d", ast_sockaddr_port(sockaddr));
+       port = ast_strdupa(ast_sockaddr_stringify_port(sockaddr));
        ast_update_realtime("iaxpeers", "name", peername,
-               "ipaddr", ast_sockaddr_stringify_addr(sockaddr), "port", port,
+               "ipaddr", ast_sockaddr_isnull(sockaddr) ? "" : ast_sockaddr_stringify_addr(sockaddr),
+               "port", ast_sockaddr_isnull(sockaddr) ? "" : port,
                "regseconds", regseconds, syslabel, sysname, SENTINEL); /* note syslable can be NULL */
 }
 
@@ -4474,31 +4478,30 @@ struct create_addr_info {
        char mohsuggest[MAX_MUSICCLASS];
 };
 
-static int create_addr(const char *peername, struct ast_channel *c, struct sockaddr_in *sin, struct create_addr_info *cai)
+static int create_addr(const char *peername, struct ast_channel *c, struct ast_sockaddr *addr, struct create_addr_info *cai)
 {
        struct iax2_peer *peer;
        int res = -1;
        struct ast_codec_pref ourprefs;
-       struct sockaddr_in peer_addr;
 
        ast_clear_flag64(cai, IAX_SENDANI | IAX_TRUNK);
        cai->sockfd = defaultsockfd;
        cai->maxtime = 0;
-       sin->sin_family = AF_INET;
 
        if (!(peer = find_peer(peername, 1))) {
-               struct ast_sockaddr sin_tmp;
+               struct ast_sockaddr peer_addr;
 
                cai->found = 0;
-               sin_tmp.ss.ss_family = AF_INET;
-               if (ast_get_ip_or_srv(&sin_tmp, peername, srvlookup ? "_iax._udp" : NULL)) {
+               if (ast_get_ip_or_srv(&peer_addr, peername, srvlookup ? "_iax._udp" : NULL)) {
                        ast_log(LOG_WARNING, "No such host: %s\n", peername);
                        return -1;
                }
-               ast_sockaddr_to_sin(&sin_tmp, sin);
-               if (sin->sin_port == 0) {
-                       sin->sin_port = htons(IAX_DEFAULT_PORTNO);
+
+               if (!ast_sockaddr_port(&peer_addr)) {
+                       ast_sockaddr_set_port(&peer_addr, IAX_DEFAULT_PORTNO);
                }
+
+               ast_sockaddr_copy(addr, &peer_addr);
                /* use global iax prefs for unknown peer/user */
                /* But move the calling channel's native codec to the top of the preference list */
                memcpy(&ourprefs, &prefs, sizeof(ourprefs));
@@ -4516,10 +4519,8 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
 
        cai->found = 1;
 
-       ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
        /* if the peer has no address (current or default), return failure */
-       if (!(peer_addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr)) {
+       if (ast_sockaddr_isnull(&peer->addr) && ast_sockaddr_isnull(&peer->defaddr)) {
                goto return_unref;
        }
 
@@ -4570,12 +4571,10 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
                }
        }
 
-       if (peer_addr.sin_addr.s_addr) {
-               sin->sin_addr = peer_addr.sin_addr;
-               sin->sin_port = peer_addr.sin_port;
+       if (!ast_sockaddr_isnull(&peer->addr)) {
+               ast_sockaddr_copy(addr, &peer->addr);
        } else {
-               sin->sin_addr = peer->defaddr.sin_addr;
-               sin->sin_port = peer->defaddr.sin_port;
+               ast_sockaddr_copy(addr, &peer->defaddr);
        }
 
        res = 0;
@@ -4635,7 +4634,7 @@ struct parsed_dial_string {
 };
 
 static int send_apathetic_reply(unsigned short callno, unsigned short dcallno,
-               struct sockaddr_in *sin, int command, int ts, unsigned char seqno,
+               struct ast_sockaddr *addr, int command, int ts, unsigned char seqno,
                int sockfd, struct iax_ie_data *ied)
 {
        struct {
@@ -4657,9 +4656,9 @@ static int send_apathetic_reply(unsigned short callno, unsigned short dcallno,
        data.f.type = AST_FRAME_IAX;
        data.f.csub = compress_subclass(command);
 
-       iax_outputframe(NULL, &data.f, 0, sin, size - sizeof(struct ast_iax2_full_hdr));
+       iax_outputframe(NULL, &data.f, 0, addr, size - sizeof(struct ast_iax2_full_hdr));
 
-       return sendto(sockfd, &data, size, 0, (struct sockaddr *)sin, sizeof(*sin));
+       return ast_sendto(sockfd, &data, size, 0, addr);
 }
 
 static void add_empty_calltoken_ie(struct chan_iax2_pvt *pvt, struct iax_ie_data *ied)
@@ -4795,9 +4794,9 @@ static void requirecalltoken_mark_auto(const char *name, int subclass)
  *         to decide how this should be handled (reject or permit without calltoken)
  */
 static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
-               struct sockaddr_in *sin, int fd)
+               struct ast_sockaddr *addr, int fd)
 {
-#define CALLTOKEN_HASH_FORMAT "%s%d%u%d"  /* address + port + ts + randomcalldata */
+#define CALLTOKEN_HASH_FORMAT "%s%u%d"  /* address + port + ts + randomcalldata */
 #define CALLTOKEN_IE_FORMAT   "%u?%s"     /* time + ? + (40 char hash) */
        struct ast_str *buf = ast_str_alloca(256);
        time_t t = time(NULL);
@@ -4812,12 +4811,12 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
                };
 
                /* create the hash with their address data and our timestamp */
-               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) t, randomcalltokendata);
+               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_sockaddr_stringify(addr), (unsigned int) t, randomcalltokendata);
                ast_sha1_hash(hash, ast_str_buffer(buf));
 
                ast_str_set(&buf, 0, CALLTOKEN_IE_FORMAT, (unsigned int) t, hash);
                iax_ie_append_str(&ied, IAX_IE_CALLTOKEN, ast_str_buffer(buf));
-               send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_CALLTOKEN, ntohl(fh->ts), fh->iseqno + 1, fd, &ied);
+               send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_CALLTOKEN, ntohl(fh->ts), fh->iseqno + 1, fd, &ied);
 
                return 1;
 
@@ -4842,15 +4841,15 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
                }
 
                /* create a hash with their address and the _TOKEN'S_ timestamp */
-               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) rec_time, randomcalltokendata);
+               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_sockaddr_stringify(addr), (unsigned int) rec_time, randomcalltokendata);
                ast_sha1_hash(hash, ast_str_buffer(buf));
 
                /* compare hashes and then check timestamp delay */
                if (strcmp(hash, rec_hash)) {
-                       ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_sockaddr_stringify(addr));
                        goto reject; /* received hash does not match ours, reject */
                } else if ((t < rec_time) || ((t - rec_time) >= MAX_CALLTOKEN_DELAY)) {
-                       ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_sockaddr_stringify(addr));
                        goto reject; /* too much delay, reject */
                }
 
@@ -4861,8 +4860,8 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
 
        /* ----- Case 3 ----- */
        } else { /* calltokens are not supported for this client, how do we respond? */
-               if (calltoken_required(sin, ies->username, subclass)) {
-                       ast_log(LOG_ERROR, "Call rejected, CallToken Support required. If unexpected, resolve by placing address %s in the calltokenoptional list or setting user %s requirecalltoken=no\n", ast_inet_ntoa(sin->sin_addr), S_OR(ies->username, "guest"));
+               if (calltoken_required(addr, ies->username, subclass)) {
+                       ast_log(LOG_ERROR, "Call rejected, CallToken Support required. If unexpected, resolve by placing address %s in the calltokenoptional list or setting user %s requirecalltoken=no\n", ast_sockaddr_stringify(addr), S_OR(ies->username, "guest"));
                        goto reject;
                }
                return 0; /* calltoken is not required for this addr, so permit it. */
@@ -4871,9 +4870,9 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
 reject:
        /* received frame has failed calltoken inspection, send apathetic reject messages */
        if (subclass == IAX_COMMAND_REGREQ || subclass == IAX_COMMAND_REGREL) {
-               send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+               send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
        } else {
-               send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+               send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
        }
 
        return 1;
@@ -4939,7 +4938,7 @@ static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 
 static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 {
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        char *l=NULL, *n=NULL, *tmpstr;
        struct iax_ie_data ied;
        char *defaultrdest = "s";
@@ -4974,7 +4973,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        if (!pds.exten) {
                pds.exten = defaultrdest;
        }
-       if (create_addr(pds.peer, c, &sin, &cai)) {
+       if (create_addr(pds.peer, c, &addr, &cai)) {
                ast_log(LOG_WARNING, "No address associated with '%s'\n", pds.peer);
                return -1;
        }
@@ -4999,8 +4998,12 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        /* Keep track of the context for outgoing calls too */
        ast_channel_context_set(c, cai.context);
 
-       if (pds.port)
-               sin.sin_port = htons(atoi(pds.port));
+       if (pds.port) {
+               int bindport;
+               if (ast_parse_arg(pds.port, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
+                       ast_sockaddr_set_port(&addr, bindport);
+               }
+       }
 
        l = ast_channel_connected(c)->id.number.valid ? ast_channel_connected(c)->id.number.str : NULL;
        n = ast_channel_connected(c)->id.name.valid ? ast_channel_connected(c)->id.name.str : NULL;
@@ -5647,7 +5650,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest)
        return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
 }
 
-static int iax2_getpeertrunk(struct sockaddr_in sin)
+static int iax2_getpeertrunk(struct ast_sockaddr addr)
 {
        struct iax2_peer *peer;
        int res = 0;
@@ -5655,12 +5658,8 @@ static int iax2_getpeertrunk(struct sockaddr_in sin)
 
        i = ao2_iterator_init(peers, 0);
        while ((peer = ao2_iterator_next(&i))) {
-               struct sockaddr_in peer_addr;
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
-               if ((peer_addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
-                   (peer_addr.sin_port == sin.sin_port)) {
+               if (!ast_sockaddr_cmp(&peer->addr, &addr)) {
                        res = ast_test_flag64(peer, IAX_TRUNK);
                        peer_unref(peer);
                        break;
@@ -6033,7 +6032,7 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
        return ms;
 }
 
-static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
+static struct iax2_trunk_peer *find_tpeer(struct ast_sockaddr *addr, int fd)
 {
        struct iax2_trunk_peer *tpeer = NULL;
 
@@ -6041,7 +6040,7 @@ static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
        AST_LIST_LOCK(&tpeers);
 
        AST_LIST_TRAVERSE(&tpeers, tpeer, list) {
-               if (!inaddrcmp(&tpeer->addr, sin)) {
+               if (!ast_sockaddr_cmp(&tpeer->addr, addr)) {
                        ast_mutex_lock(&tpeer->lock);
                        break;
                }
@@ -6051,14 +6050,15 @@ static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
                if ((tpeer = ast_calloc(1, sizeof(*tpeer)))) {
                        ast_mutex_init(&tpeer->lock);
                        tpeer->lastsent = 9999;
-                       memcpy(&tpeer->addr, sin, sizeof(tpeer->addr));
+                       ast_sockaddr_copy(&tpeer->addr, addr);
                        tpeer->trunkact = ast_tvnow();
                        ast_mutex_lock(&tpeer->lock);
                        tpeer->sockfd = fd;
+
 #ifdef SO_NO_CHECK
                        setsockopt(tpeer->sockfd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
 #endif
-                       ast_debug(1, "Created trunk peer for '%s:%d'\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
+                       ast_debug(1, "Created trunk peer for '%s'\n", ast_sockaddr_stringify(&tpeer->addr));
                        AST_LIST_INSERT_TAIL(&tpeers, tpeer, list);
                }
        }
@@ -6080,6 +6080,7 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
        f = &fr->af;
        tpeer = find_tpeer(&pvt->addr, pvt->sockfd);
        if (tpeer) {
+
                if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) {
                        /* Need to reallocate space */
                        if (tpeer->trunkdataalloc < trunkmaxsize) {
@@ -6090,9 +6091,9 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
 
                                tpeer->trunkdataalloc += DEFAULT_TRUNKDATA;
                                tpeer->trunkdata = tmp;
-                               ast_debug(1, "Expanded trunk '%s:%d' to %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), tpeer->trunkdataalloc);
+                               ast_debug(1, "Expanded trunk '%s' to %d bytes\n", ast_sockaddr_stringify(&tpeer->addr), tpeer->trunkdataalloc);
                        } else {
-                               ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s:%d\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
+                               ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s\n", ast_sockaddr_stringify(&tpeer->addr));
                                ast_mutex_unlock(&tpeer->lock);
                                return -1;
                        }
@@ -6613,50 +6614,190 @@ static char *handle_cli_iax2_show_users(struct ast_cli_entry *e, int cmd, struct
 #undef FORMAT2
 }
 
+struct show_peers_context {
+       regex_t regexbuf;
+       int havepattern;
+       char idtext[256];
+       int registeredonly;
+       int peerlist;
+       int total_peers;
+       int online_peers;
+       int offline_peers;
+       int unmonitored_peers;
+};
+
+#define PEERS_FORMAT2 "%-15.15s  %-40.40s %s   %-40.40s  %-9s %s  %-11s %-32.32s\n"
+#define PEERS_FORMAT "%-15.15s  %-40.40s %s  %-40.40s  %-6s%s %s  %-11s %-32.32s\n"
+
+static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers_context *cont, struct iax2_peer *peer)
+{
+       char name[256] = "";
+       char status[20];
+       int retstatus;
+       struct ast_str *encmethods = ast_str_alloca(256);
+
+       char *tmp_host, *tmp_mask, *tmp_port;
+
+       tmp_host = ast_strdupa(ast_sockaddr_stringify_addr(&peer->addr));
+       tmp_mask = ast_strdupa(ast_sockaddr_stringify_addr(&peer->mask));
+       tmp_port = ast_strdupa(ast_sockaddr_stringify_port(&peer->addr));
+
+       if (!ast_strlen_zero(peer->username)) {
+               snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
+       } else {
+               ast_copy_string(name, peer->name, sizeof(name));
+       }
+
+       encmethods_to_str(peer->encmethods, &encmethods);
+       retstatus = peer_status(peer, status, sizeof(status));
+       if (retstatus > 0) {
+               cont->online_peers++;
+       } else if (!retstatus) {
+               cont->offline_peers++;
+       } else {
+               cont->unmonitored_peers++;
+       }
+
+       if (s) {
+
+               if (cont->peerlist) { /* IAXpeerlist */
+
+                       astman_append(s,
+                               "Event: PeerEntry\r\n%s"
+                               "Channeltype: IAX\r\n",
+                               cont->idtext);
+
+                       if (!ast_strlen_zero(peer->username)) {
+
+                               astman_append(s,
+                                       "ObjectName: %s\r\n"
+                                       "ObjectUsername: %s\r\n",
+                                       peer->name,
+                                       peer->username);
+
+                       } else {
+
+                               astman_append(s,
+                                       "ObjectName: %s\r\n",
+                                       name);
+                       }
+
+               } else { /* IAXpeers */
+
+                       astman_append(s,
+                               "Event: PeerEntry\r\n%s"
+                               "Channeltype: IAX2\r\n"
+                               "ObjectName: %s\r\n",
+                               cont->idtext,
+                               name);
+               }
+
+               astman_append(s,
+                       "ChanObjectType: peer\r\n"
+                       "IPaddress: %s\r\n",
+                       tmp_host);
+
+               if (cont->peerlist) { /* IAXpeerlist */
+
+                       astman_append(s,
+                               "Mask: %s\r\n"
+                               "Port: %s\r\n",
+                               tmp_mask,
+                               tmp_port);
+
+               } else { /* IAXpeers */
+
+                       astman_append(s,
+                               "IPport: %s\r\n",
+                               tmp_port);
+
+               }
+
+               astman_append(s,
+                       "Dynamic: %s\r\n"
+                       "Trunk: %s\r\n"
+                       "Encryption: %s\r\n"
+                       "Status: %s\r\n",
+                       ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
+                       ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
+                       peer->encmethods ? ast_str_buffer(encmethods) : "no",
+                       status);
+
+               if (cont->peerlist) { /* IAXpeerlist */
+
+                       astman_append(s, "\r\n");
+
+               } else { /* IAXpeers */
+
+                       astman_append(s,
+                               "Description: %s\r\n\r\n",
+                               peer->description);
+
+               }
+
+       } else {
+               ast_cli(fd, PEERS_FORMAT,
+                       name,
+                       tmp_host,
+                       ast_test_flag64(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
+                       tmp_mask,
+                       tmp_port,
+                       ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : "   ",
+                       peer->encmethods ? "(E)" : "   ",
+                       status,
+                       peer->description);
+       }
+
+       cont->total_peers++;
+
+}
+
 static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int argc, const char * const argv[])
 {
-       regex_t regexbuf;
-       int havepattern = 0;
-       int total_peers = 0;
-       int online_peers = 0;
-       int offline_peers = 0;
-       int unmonitored_peers = 0;
-       struct ao2_iterator i;
+       struct show_peers_context cont = {
+               .havepattern = 0,
+               .idtext = "",
+               .registeredonly = 0,
 
-#define FORMAT2 "%-15.15s  %-15.15s %s  %-15.15s  %-8s  %s %-11s %-32.32s\n"
-#define FORMAT "%-15.15s  %-15.15s %s  %-15.15s  %-5d%s  %s %-11s %-32.32s\n"
+               .peerlist = 0,
+
+               .total_peers = 0,
+               .online_peers = 0,
+               .offline_peers = 0,
+               .unmonitored_peers = 0,
+       };
+
+       struct ao2_iterator i;
 
        struct iax2_peer *peer = NULL;
-       char name[256];
-       struct ast_str *encmethods = ast_str_alloca(256);
-       int registeredonly=0;
-       char idtext[256] = "";
+
        switch (argc) {
        case 6:
                if (!strcasecmp(argv[3], "registered"))
-                       registeredonly = 1;
+                       cont.registeredonly = 1;
                else
                        return RESULT_SHOWUSAGE;
                if (!strcasecmp(argv[4], "like")) {
-                       if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
+                       if (regcomp(&cont.regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
                                return RESULT_SHOWUSAGE;
-                       havepattern = 1;
+                       cont.havepattern = 1;
                } else
                        return RESULT_SHOWUSAGE;
                break;
        case 5:
                if (!strcasecmp(argv[3], "like")) {
-                       if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
+                       if (regcomp(&cont.regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
                                return RESULT_SHOWUSAGE;
-                       havepattern = 1;
+                       cont.havepattern = 1;
                } else
                        return RESULT_SHOWUSAGE;
                break;
        case 4:
-               if (!strcasecmp(argv[3], "registered"))
-                       registeredonly = 1;
-               else
+               if (!strcasecmp(argv[3], "registered")) {
+                       cont.registeredonly = 1;
+               } else {
                        return RESULT_SHOWUSAGE;
+               }
                break;
        case 3:
                break;
@@ -6665,92 +6806,43 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
        }
 
 
-       if (!s)
-               ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", "Description");
+       if (!s) {
+               ast_cli(fd, PEERS_FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", "Description");
+       }
 
        i = ao2_iterator_init(peers, 0);
        for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
-               char nm[20];
-               char status[20];
-               int retstatus;
-               struct sockaddr_in peer_addr;
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
-               if (registeredonly && !peer_addr.sin_addr.s_addr) {
+               if (cont.registeredonly && ast_sockaddr_isnull(&peer->addr)) {
                        continue;
                }
-               if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0)) {
+               if (cont.havepattern && regexec(&cont.regexbuf, peer->name, 0, NULL, 0)) {
                        continue;
                }
 
-               if (!ast_strlen_zero(peer->username))
-                       snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
-               else
-                       ast_copy_string(name, peer->name, sizeof(name));
+               _iax2_show_peers_one(fd, s, &cont, peer);
 
-               encmethods_to_str(peer->encmethods, &encmethods);
-               retstatus = peer_status(peer, status, sizeof(status));
-               if (retstatus > 0)
-                       online_peers++;
-               else if (!retstatus)
-                       offline_peers++;
-               else
-                       unmonitored_peers++;
-
-               ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
-
-               if (s) {
-                       astman_append(s,
-                               "Event: PeerEntry\r\n%s"
-                               "Channeltype: IAX2\r\n"
-                               "ObjectName: %s\r\n"
-                               "ChanObjectType: peer\r\n"
-                               "IPaddress: %s\r\n"
-                               "IPport: %d\r\n"
-                               "Dynamic: %s\r\n"
-                               "Trunk: %s\r\n"
-                               "Encryption: %s\r\n"
-                               "Status: %s\r\n"
-                               "Description: %s\r\n\r\n",
-                               idtext,
-                               name,
-                               ast_sockaddr_stringify_addr(&peer->addr),
-                               ast_sockaddr_port(&peer->addr),
-                               ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
-                               ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
-                               peer->encmethods ? ast_str_buffer(encmethods) : "no",
-                               status,
-                               peer->description);
-               } else {
-                       ast_cli(fd, FORMAT, name,
-                               ast_sockaddr_stringify_addr(&peer->addr),
-                               ast_test_flag64(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
-                               nm,
-                               ast_sockaddr_port(&peer->addr),
-                               ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : "   ",
-                               peer->encmethods ? "(E)" : "   ",
-                               status,
-                               peer->description);
-               }
-               total_peers++;
        }
        ao2_iterator_destroy(&i);
 
-       if (!s)
+       if (!s) {
                ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]\n",
-                       total_peers, online_peers, offline_peers, unmonitored_peers);
+                       cont.total_peers, cont.online_peers, cont.offline_peers, cont.unmonitored_peers);
+       }
 
-       if (havepattern)
-               regfree(&regexbuf);
+       if (cont.havepattern) {
+               regfree(&cont.regexbuf);
+       }
 
-       if (total)
-               *total = total_peers;
+       if (total) {
+               *total = cont.total_peers;
+       }
 
        return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
+
 }
+#undef PEERS_FORMAT2
+#undef PEERS_FORMAT
 
 static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -6985,45 +7077,48 @@ static int manager_iax2_show_peers(struct mansession *s, const struct message *m
 /*! \brief callback to display iax peers in manager format */
 static int manager_iax2_show_peer_list(struct mansession *s, const struct message *m)
 {
+       struct show_peers_context cont = {
+               .havepattern = 0,
+               .idtext = "",
+               .registeredonly = 0,
+
+               .peerlist = 1,
+
+               .total_peers = 0,
+               .online_peers = 0,
+               .offline_peers = 0,
+               .unmonitored_peers = 0,
+       };
+
        struct iax2_peer *peer = NULL;
-       int peer_count = 0;
-       char nm[20];
-       char status[20];
-       const char *id = astman_get_header(m,"ActionID");
-       char idtext[256] = "";
-       struct ast_str *encmethods = ast_str_alloca(256);
        struct ao2_iterator i;
 
-       if (!ast_strlen_zero(id))
-               snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
+       const char *id = astman_get_header(m,"ActionID");
+
+       if (!ast_strlen_zero(id)) {
+               snprintf(cont.idtext, sizeof(cont.idtext), "ActionID: %s\r\n", id);
+       }
 
-       astman_append(s, "Response: Success\r\n%sMessage: IAX Peer status list will follow\r\n\r\n", idtext);
+       astman_append(s,
+               "Response: Success\r\n"
+               "%sMessage: IAX Peer status list will follow\r\n\r\n",
+               cont.idtext);
 
 
        i = ao2_iterator_init(peers, 0);
        for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
-               encmethods_to_str(peer->encmethods, &encmethods);
-               astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext);
-               if (!ast_strlen_zero(peer->username)) {
-                       astman_append(s, "ObjectName: %s\r\nObjectUsername: %s\r\n", peer->name, peer->username);
-               } else {
-                       astman_append(s, "ObjectName: %s\r\n", peer->name);
-               }
-               astman_append(s, "ChanObjectType: peer\r\n");
-               astman_append(s, "IPaddress: %s\r\n", ast_sockaddr_stringify_addr(&peer->addr));
-               ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
-               astman_append(s, "Mask: %s\r\n", nm);
-               astman_append(s, "Port: %d\r\n", ast_sockaddr_port(&peer->addr));
-               astman_append(s, "Dynamic: %s\r\n", ast_test_flag64(peer, IAX_DYNAMIC) ? "Yes" : "No");
-               astman_append(s, "Trunk: %s\r\n", ast_test_flag64(peer, IAX_TRUNK) ? "Yes" : "No");
-               astman_append(s, "Encryption: %s\r\n", peer->encmethods ? ast_str_buffer(encmethods) : "No");
-               peer_status(peer, status, sizeof(status));
-               astman_append(s, "Status: %s\r\n\r\n", status);
-               peer_count++;
+
+               _iax2_show_peers_one(-1, s, &cont, peer);
+
        }
        ao2_iterator_destroy(&i);
 
-       astman_append(s, "Event: PeerlistComplete\r\n%sListItems: %d\r\n\r\n", idtext, peer_count);
+       astman_append(s,
+               "Event: PeerlistComplete\r\n"
+               "%sListItems: %d\r\n\r\n",
+               cont.idtext,
+               cont.total_peers);
+
        return RESULT_SUCCESS;
 }
 
@@ -7052,8 +7147,9 @@ static char *regstate2str(int regstate)
 
 static char *handle_cli_iax2_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT2 "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8.8s  %s\n"
-#define FORMAT  "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8d  %s\n"
+#define FORMAT2 "%-45.45s  %-6.6s  %-10.10s  %-45.45s %8.8s  %s\n"
+#define FORMAT  "%-45.45s  %-6.6s  %-10.10s  %-45.45s %8d  %s\n"
+
        struct iax2_registry *reg = NULL;
        char host[80];
        char perceived[80];
@@ -7075,13 +7171,12 @@ static char *handle_cli_iax2_show_registry(struct ast_cli_entry *e, int cmd, str
        AST_LIST_LOCK(&registrations);
        AST_LIST_TRAVERSE(&registrations, reg, entry) {
                snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(&reg->addr));
-               if (reg->us.sin_addr.s_addr)
-                       snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
-               else
-                       ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
+
+               snprintf(perceived, sizeof(perceived), "%s", ast_sockaddr_isnull(&reg->addr) ? "<Unregistered>" : ast_sockaddr_stringify(&reg->addr));
+
                ast_cli(a->fd, FORMAT, host,
-                                       (reg->dnsmgr) ? "Y" : "N",
-                                       reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
+                               (reg->dnsmgr) ? "Y" : "N",
+                               reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
                counter++;
        }
        AST_LIST_UNLOCK(&registrations);
@@ -7109,11 +7204,7 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
        AST_LIST_TRAVERSE(&registrations, reg, entry) {
                snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(&reg->addr));
 
-               if (reg->us.sin_addr.s_addr) {
-                       snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
-               } else {
-                       ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
-               }
+               snprintf(perceived, sizeof(perceived), "%s", ast_sockaddr_isnull(&reg->addr) ? "<Unregistered>" : ast_sockaddr_stringify(&reg->addr));
 
                astman_append(s,
                        "Event: RegistryEntry\r\n"
@@ -7143,9 +7234,9 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
 
 static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT2 "%-20.20s  %-15.15s  %-10.10s  %-11.11s  %-11.11s  %-7.7s  %-6.6s  %-6.6s  %s  %s  %9s\n"
-#define FORMAT  "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  %-5.5dms  %-4.4dms  %-4.4dms  %-6.6s  %s%s  %3s%s\n"
-#define FORMATB "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  [Native Bridged to ID=%5.5d]\n"
+#define FORMAT2 "%-20.20s  %-40.40s  %-10.10s  %-11.11s  %-11.11s  %-7.7s  %-6.6s  %-6.6s  %s  %s  %9s\n"
+#define FORMAT  "%-20.20s  %-40.40s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  %-5.5dms  %-4.4dms  %-4.4dms  %-6.6s  %s%s  %3s%s\n"
+#define FORMATB "%-20.20s  %-40.40s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  [Native Bridged to ID=%5.5d]\n"
        int x;
        int numchans = 0;
        char first_message[10] = { 0, };
@@ -7184,7 +7275,7 @@ static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, str
                        lag = iaxs[x]->remote_rr.delay;
                        ast_cli(a->fd, FORMAT,
                                iaxs[x]->owner ? ast_channel_name(iaxs[x]->owner) : "(None)",
-                               ast_inet_ntoa(iaxs[x]->addr.sin_addr),
+                               ast_sockaddr_stringify_addr(&iaxs[x]->addr),
                                S_OR(iaxs[x]->username, "(None)"),
                                iaxs[x]->callno, iaxs[x]->peercallno,
                                iaxs[x]->oseqno, iaxs[x]->iseqno,
@@ -7334,8 +7425,6 @@ static char *handle_cli_iax2_set_debug(struct ast_cli_entry *e, int cmd, struct
 
        if (!strcasecmp(a->argv[3], "peer")) {
                struct iax2_peer *peer;
-               struct sockaddr_in peer_addr;
-
 
                if (a->argc != e->args + 1)
                        return CLI_SHOWUSAGE;
@@ -7347,13 +7436,9 @@ static char *handle_cli_iax2_set_debug(struct ast_cli_entry *e, int cmd, struct
                        return CLI_FAILURE;
                }
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
-               debugaddr.sin_addr = peer_addr.sin_addr;
-               debugaddr.sin_port = peer_addr.sin_port;
+               ast_sockaddr_copy(&debugaddr, &peer->addr);
 
-               ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s:%d\n",
-                       ast_inet_ntoa(debugaddr.sin_addr), ntohs(debugaddr.sin_port));
+               ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s\n", ast_sockaddr_stringify_port(&debugaddr));
 
                ao2_ref(peer, -1);
        } else if (!strncasecmp(a->argv[3], "on", 2)) {
@@ -7517,7 +7602,7 @@ static int apply_context(struct iax2_context *con, const char *context)
 }
 
 
-static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
+static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *ies)
 {
        /* Start pessimistic */
        int res = -1;
@@ -7527,7 +7612,6 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
        int gotcapability = 0;
        struct ast_variable *v = NULL, *tmpvar = NULL;
        struct ao2_iterator i;
-       struct ast_sockaddr addr;
 
        if (!iaxs[callno])
                return res;
@@ -7576,20 +7660,20 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
                ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
        }
 
-       if (!gotcapability)
+       if (!gotcapability) {
                iaxs[callno]->peercapability = iaxs[callno]->peerformat;
+       }
        if (version > IAX_PROTO_VERSION) {
                ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n",
-                       ast_inet_ntoa(sin->sin_addr), version);
+                               ast_sockaddr_stringify_addr(addr), version);
                return res;
        }
        /* Search the userlist for a compatible entry, and fill in the rest */
-       ast_sockaddr_from_sin(&addr, sin);
        i = ao2_iterator_init(users, 0);
        while ((user = ao2_iterator_next(&i))) {
                if ((ast_strlen_zero(iaxs[callno]->username) ||                         /* No username specified */
                        !strcmp(iaxs[callno]->username, user->name))    /* Or this username specified */
-                       && (ast_apply_acl(user->acl, &addr, "IAX2 user ACL: ") == AST_SENSE_ALLOW)      /* Access is permitted from this IP */
+                       && (ast_apply_acl(user->acl, addr, "IAX2 user ACL: ") == AST_SENSE_ALLOW)       /* Access is permitted from this IP */
                        && (ast_strlen_zero(iaxs[callno]->context) ||                   /* No context specified */
                             apply_context(user->contexts, iaxs[callno]->context))) {                   /* Context is permitted */
                        if (!ast_strlen_zero(iaxs[callno]->username)) {
@@ -7646,8 +7730,8 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
        ao2_iterator_destroy(&i);
        user = best;
        if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
-               user = realtime_user(iaxs[callno]->username, sin);
-               if (user && (ast_apply_acl(user->acl, &addr, "IAX2 user ACL: ") == AST_SENSE_DENY               /* Access is denied from this IP */
+               user = realtime_user(iaxs[callno]->username, addr);
+               if (user && (ast_apply_acl(user->acl, addr, "IAX2 user ACL: ") == AST_SENSE_DENY                /* Access is denied from this IP */
                        || (!ast_strlen_zero(iaxs[callno]->context) &&                                  /* No context specified */
                                !apply_context(user->contexts, iaxs[callno]->context)))) {      /* Context is permitted */
                        user = user_unref(user);
@@ -7741,11 +7825,11 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
                        res = 0;
                }
        }
-       ast_set2_flag64(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);
+       ast_set2_flag64(iaxs[callno], iax2_getpeertrunk(*addr), IAX_TRUNK);
        return res;
 }
 
-static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned short dst, int sockfd)
+static int raw_hangup(struct ast_sockaddr *addr, unsigned short src, unsigned short dst, int sockfd)
 {
        struct ast_iax2_full_hdr fh;
        fh.scallno = htons(src | IAX_FLAG_FULL);
@@ -7755,10 +7839,10 @@ static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned shor
        fh.iseqno = 0;
        fh.type = AST_FRAME_IAX;
        fh.csub = compress_subclass(IAX_COMMAND_INVAL);
-       iax_outputframe(NULL, &fh, 0, sin, 0);
-       ast_debug(1, "Raw Hangup %s:%d, src=%d, dst=%d\n",
-               ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), src, dst);
-       return sendto(sockfd, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin));
+       iax_outputframe(NULL, &fh, 0, addr, 0);
+
+       ast_debug(1, "Raw Hangup %s, src=%d, dst=%d\n", ast_sockaddr_stringify(addr), src, dst);
+       return ast_sendto(sockfd, &fh, sizeof(fh), 0, addr);
 }
 
 static void merge_encryption(struct chan_iax2_pvt *p, unsigned int enc)
@@ -7846,6 +7930,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
        if (p->authrej) {
                return res;
        }
+
        user = ao2_find(users, p->username, OBJ_KEY);
        if (user) {
                if (ast_test_flag64(p, IAX_MAXAUTHREQ)) {
@@ -7892,7 +7977,6 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
                struct MD5Context md5;
                unsigned char digest[16];
                char *tmppw, *stringp;
-
                tmppw = ast_strdupa(p->secret);
                stringp = tmppw;
                while((tmppw = strsep(&stringp, ";"))) {
@@ -7916,7 +8000,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 }
 
 /*! \brief Verify inbound registration */
-static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
+static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies *ies)
 {
        char requeststr[256] = "";
        char peer[256] = "";
@@ -7929,7 +8013,6 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        int x;
        int expire = 0;
        int res = -1;
-       struct ast_sockaddr addr;
 
        ast_clear_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
        /* iaxs[callno]->peer[0] = '\0'; not necc. any more-- stringfield is pre-inited to null string */
@@ -7945,7 +8028,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                expire = ies->refresh;
 
        if (ast_strlen_zero(peer)) {
-               ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_inet_ntoa(sin->sin_addr));
+               ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_sockaddr_stringify_addr(addr));
                return -1;
        }
 
@@ -7974,20 +8057,19 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                        }
                }
                if (authdebug && !p)
-                       ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_sockaddr_stringify_addr(addr));
                goto return_unref;
        }
 
        if (!ast_test_flag64(p, IAX_DYNAMIC)) {
                if (authdebug)
-                       ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_sockaddr_stringify_addr(addr));
                goto return_unref;
        }
 
-       ast_sockaddr_from_sin(&addr, sin);
-       if (!ast_apply_acl(p->acl, &addr, "IAX2 Peer ACL: ")) {
+       if (!ast_apply_acl(p->acl, addr, "IAX2 Peer ACL: ")) {
                if (authdebug)
-                       ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
+                       ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_sockaddr_stringify_addr(addr), p->name);
                goto return_unref;
        }
        ast_string_field_set(iaxs[callno], secret, p->secret);
@@ -8044,14 +8126,14 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                        ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
                } else {
                        if (authdebug)
-                               ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
+                               ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_sockaddr_stringify_addr(addr), p->name, requeststr, md5secret);
                        goto return_unref;
                }
        } else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
                /* They've provided a plain text password and we support that */
                if (strcmp(secret, p->secret)) {
                        if (authdebug)
-                               ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
+                               ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_sockaddr_stringify_addr(addr), p->name);
                        goto return_unref;
                } else
                        ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
@@ -8080,16 +8162,17 @@ return_unref:
        return res;
 }
 
-static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, struct chan_iax2_pvt *pvt)
+static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct ast_sockaddr *addr, struct chan_iax2_pvt *pvt)
 {
        int res = -1;
        int x;
        if (!ast_strlen_zero(keyn)) {
                if (!(authmethods & IAX_AUTH_RSA)) {
-                       if (ast_strlen_zero(secret))
-                               ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_inet_ntoa(sin->sin_addr));
+                       if (ast_strlen_zero(secret)) {
+                               ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_sockaddr_stringify_addr(addr));
+                       }
                } else if (ast_strlen_zero(challenge)) {
-                       ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_sockaddr_stringify_addr(addr));
                } else {
                        char sig[256];
                        struct ast_key *key;
@@ -8129,7 +8212,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
                        iax_ie_append_str(ied, IAX_IE_PASSWORD, secret);
                        res = 0;
                } else
-                       ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_inet_ntoa(sin->sin_addr), authmethods);
+                       ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_sockaddr_stringify_addr(addr), authmethods);
        }
        return res;
 }
@@ -8138,7 +8221,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
  * \note This function calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call this function with a pvt lock held.
  */
-static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, const char *override, const char *okey)
+static int authenticate_reply(struct chan_iax2_pvt *p, struct ast_sockaddr *addr, struct iax_ies *ies, const char *override, const char *okey)
 {
        struct iax2_peer *peer = NULL;
        /* Start pessimistic */
@@ -8163,22 +8246,27 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
        /* Check for override RSA authentication first */
        if (!ast_strlen_zero(override) || !ast_strlen_zero(okey)) {
                /* Normal password authentication */
-               res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, p);
+               res = authenticate(p->challenge, override, okey, authmethods, &ied, addr, p);
        } else {
                struct ao2_iterator i = ao2_iterator_init(peers, 0);
                while ((peer = ao2_iterator_next(&i))) {
-                       struct sockaddr_in peer_addr;
+                       struct ast_sockaddr peer_addr;
+                       struct ast_sockaddr tmp_sockaddr1;
+                       struct ast_sockaddr tmp_sockaddr2;
 
-                       ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+                       ast_sockaddr_copy(&peer_addr, &peer->addr);
+
+                       ast_sockaddr_apply_netmask(addr, &peer->mask, &tmp_sockaddr1);
+                       ast_sockaddr_apply_netmask(&peer_addr, &peer->mask, &tmp_sockaddr2);
 
                        if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name))
-                           /* No peer specified at our end, or this is the peer */
+                               /* No peer specified at our end, or this is the peer */
                            && (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
                            /* No username specified in peer rule, or this is the right username */
-                           && (!peer_addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer_addr.sin_addr.s_addr & peer->mask.s_addr)))
+                           && (ast_sockaddr_isnull(&peer_addr) || !(ast_sockaddr_cmp_addr(&tmp_sockaddr1, &tmp_sockaddr2)))
                            /* No specified host, or this is our host */
                                ) {
-                               res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, p);
+                               res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, addr, p);
                                if (!res) {
                                        peer_unref(peer);
                                        break;
@@ -8198,7 +8286,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
                                        peer_unref(peer);
                                        return -1;
                                }
-                               res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, p);
+                               res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, addr, p);
                                peer_unref(peer);
                        }
                        if (!peer) {
@@ -8277,23 +8365,22 @@ static int iax2_do_register_s(const void *data)
 static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 {
        int newcall = 0;
-       char newip[256];
        struct iax_ie_data ied;
-       struct sockaddr_in new = { 0, };
+       struct ast_sockaddr new;
 
        memset(&ied, 0, sizeof(ied));
-       if (ies->apparent_addr)
-               memmove(&new, ies->apparent_addr, sizeof(new));
-       if (ies->callno)
+       if (!ast_sockaddr_isnull(&ies->apparent_addr)) {
+               ast_sockaddr_copy(&new, &ies->apparent_addr);
+       }
+       if (ies->callno) {
                newcall = ies->callno;
-       if (!newcall || !new.sin_addr.s_addr || !new.sin_port) {
+       }
+       if (!newcall || ast_sockaddr_isnull(&new)) {
                ast_log(LOG_WARNING, "Invalid transfer request\n");
                return -1;
        }
        pvt->transfercallno = newcall;
-       memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
-       inet_aton(newip, &pvt->transfer.sin_addr);
-       pvt->transfer.sin_family = AF_INET;
+       ast_sockaddr_copy(&pvt->transfer, &new);
        pvt->transferid = ies->transferid;
        /* only store by transfercallno if this is a new transfer,
         * just in case we get a duplicate TXREQ */
@@ -8302,8 +8389,9 @@ static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
        }
        pvt->transferring = TRANSFER_BEGIN;
 
-       if (ies->transferid)
+       if (ies->transferid) {
                iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
+       }
        send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
        return 0;
 }
@@ -8422,7 +8510,7 @@ static void iax2_publish_registry(const char *username, const char *domain, cons
 }
 
 /*! \brief Acknowledgment received for OUR registration */
-static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int callno)
+static int iax2_ack_registry(struct iax_ies *ies, struct ast_sockaddr *addr, int callno)
 {
        struct iax2_registry *reg;
        /* Start pessimistic */
@@ -8430,14 +8518,12 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        char msgstatus[60];
        int refresh = 60;
        char ourip[256] = "<Unspecified>";
-       struct sockaddr_in oldus;
-       struct sockaddr_in us;
+       struct ast_sockaddr oldus;
+       struct ast_sockaddr us;
        int oldmsgs;
-       struct sockaddr_in reg_addr;
 
-       memset(&us, 0, sizeof(us));
-       if (ies->apparent_addr) {
-               memmove(&us, ies->apparent_addr, sizeof(us));
+       if (!ast_sockaddr_isnull(&ies->apparent_addr)) {
+               ast_sockaddr_copy(&us, &ies->apparent_addr);
        }
        if (ies->username) {
                ast_copy_string(peer, ies->username, sizeof(peer));
@@ -8453,14 +8539,13 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
                ast_log(LOG_WARNING, "Registry acknowledge on unknown registry '%s'\n", peer);
                return -1;
        }
-       memcpy(&oldus, &reg->us, sizeof(oldus));
+       ast_sockaddr_copy(&oldus, &reg->us);
        oldmsgs = reg->messages;
-       ast_sockaddr_to_sin(&reg->addr, &reg_addr);
-       if (inaddrcmp(&reg_addr, sin)) {
-               ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_inet_ntoa(sin->sin_addr));
+       if (ast_sockaddr_cmp(&reg->addr, addr)) {
+               ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_sockaddr_stringify(addr));
                return -1;
        }
-       memcpy(&reg->us, &us, sizeof(reg->us));
+       ast_sockaddr_copy(&reg->us, &us);
        if (ies->msgcount >= 0) {
                reg->messages = ies->msgcount & 0xffff;         /* only low 16 bits are used in the transmission of the IE */
        }
@@ -8470,7 +8555,8 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        reg->refresh = refresh;
        reg->expire = iax2_sched_replace(reg->expire, sched,
                (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
-       if (inaddrcmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
+       if (ast_sockaddr_cmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
+
                if (reg->messages > 255) {
                        snprintf(msgstatus, sizeof(msgstatus), " with %d new and %d old messages waiting", reg->messages & 0xff, reg->messages >> 8);
                } else if (reg->messages > 1) {
@@ -8480,9 +8566,11 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
                } else {
                        ast_copy_string(msgstatus, " with no messages waiting", sizeof(msgstatus));
                }
-               snprintf(ourip, sizeof(ourip), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
-               ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", ast_inet_ntoa(sin->sin_addr), ourip, msgstatus);
-               iax2_publish_registry(reg->username, ast_inet_ntoa(sin->sin_addr), "Registered", NULL);
+
+               snprintf(ourip, sizeof(ourip), "%s", ast_sockaddr_stringify(&reg->us));
+
+               ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", ast_sockaddr_stringify(addr), ourip, msgstatus);
+               iax2_publish_registry(reg->username, ast_sockaddr_stringify(addr), "Registered", NULL);
        }
        reg->regstate = REG_STATE_REGISTERED;
        return 0;
@@ -8496,7 +8584,7 @@ static int iax2_append_register(const char *hostname, const char *username,
        if (!(reg = ast_calloc(1, sizeof(*reg))))
                return -1;
 
-       reg->addr.ss.ss_family = AF_INET;
+       reg->addr.ss.ss_family = AST_AF_UNSPEC;
        if (ast_dnsmgr_lookup(hostname, &reg->addr, &reg->dnsmgr, srvlookup ? "_iax._udp" : NULL) < 0) {
                ast_free(reg);
                return -1;
@@ -8617,7 +8705,7 @@ static void __expire_registry(const void *data)
        /* modify entry in peercnts table as _not_ registered */
        peercnt_modify((unsigned char) 0, 0, &peer->addr);
        /* Reset the address */
-       memset(&peer->addr, 0, sizeof(peer->addr));
+       ast_sockaddr_setnull(&peer->addr);
        /* Reset expiry value */
        peer->expiry = min_reg_expire;
        if (!ast_test_flag64(peer, IAX_TEMPONLY))
@@ -8696,8 +8784,9 @@ static void reg_source_db(struct iax2_peer *p)
  * \note Since this function calls send_command_final(), the pvt struct for
  *       the given call number may disappear while executing this function.
  */
-static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
+static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype, int fd, unsigned short refresh)
 {
+
        /* Called from IAX thread only, with proper iaxsl lock */
        struct iax_ie_data ied = {
                .pos = 0,
@@ -8708,9 +8797,7 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
        uint16_t version;
        const char *peer_name;
        int res = -1;
-       struct ast_sockaddr sockaddr;
-
-       ast_sockaddr_from_sin(&sockaddr, sin);
+       char *str_addr;
 
        peer_name = ast_strdupa(iaxs[callno]->peer);
 
@@ -8726,12 +8813,12 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                goto return_unref;
 
        if (ast_test_flag64((&globalflags), IAX_RTUPDATE) && (ast_test_flag64(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
-               if (sin->sin_addr.s_addr) {
+               if (!ast_sockaddr_isnull(addr)) {
                        time_t nowtime;
                        time(&nowtime);
-                       realtime_update_peer(peer_name, &sockaddr, nowtime);
+                       realtime_update_peer(peer_name, addr, nowtime);
                } else {
-                       realtime_update_peer(peer_name, &sockaddr, 0);
+                       realtime_update_peer(peer_name, addr, 0);
                }
        }
 
@@ -8751,7 +8838,7 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                p->expiry = refresh;
        }
 
-       if (ast_sockaddr_cmp(&p->addr, &sockaddr)) {
+       if (ast_sockaddr_cmp(&p->addr, addr)) {
                RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
                if (iax2_regfunk) {
@@ -8762,22 +8849,28 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                peercnt_modify((unsigned char) 0, 0, &p->addr);
 
                /* Stash the IP address from which they registered */
-               ast_sockaddr_from_sin(&p->addr, sin);
+               ast_sockaddr_copy(&p->addr, addr);
+
+               str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
 
-               snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), p->expiry);
-               if (!ast_test_flag64(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
+               snprintf(data, sizeof(data), "%s:%d", ast_sockaddr_stringify(addr), p->expiry);
+
+               if (!ast_test_flag64(p, IAX_TEMPONLY) && !ast_sockaddr_isnull(addr)) {
                        ast_db_put("IAX/Registry", p->name, data);
-                       ast_verb(3, "Registered IAX2 '%s' (%s) at %s:%d\n", p->name,
-                                           ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+                       ast_verb(3, "Registered IAX2 '%s' (%s) at %s\n",
+                                               p->name,
+                                           ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED",
+                                           ast_sockaddr_stringify(addr));
                        ast_endpoint_set_state(p->endpoint, AST_ENDPOINT_ONLINE);
                        blob = ast_json_pack("{s: s, s: s, s: i}",
                                "peer_status", "Registered",
-                               "address", ast_inet_ntoa(sin->sin_addr),
-                               "port", ntohs(sin->sin_port));
+                               "address", str_addr,
+                               "port", ast_sockaddr_port(addr));
                        register_peer_exten(p, 1);
                        ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
                } else if (!ast_test_flag64(p, IAX_TEMPONLY)) {
-                       ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
+                       ast_verb(3, "Unregistered IAX2 '%s' (%s)\n",
+                                               p->name,
                                            ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
                        ast_endpoint_set_state(p->endpoint, AST_ENDPOINT_OFFLINE);
                        blob = ast_json_pack("{s: s}",
@@ -8815,17 +8908,17 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                }
        }
 
-       if (p->expiry && sin->sin_addr.s_addr) {
+       if (p->expiry && !ast_sockaddr_isnull(addr)) {
                p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
                if (p->expire == -1)
                        peer_unref(p);
        }
        iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
        iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
-       if (sin->sin_addr.s_addr) {
-               struct sockaddr_in peer_addr;
+       if (!ast_sockaddr_isnull(addr)) {
+               struct ast_sockaddr peer_addr;
 
-               ast_sockaddr_to_sin(&p->addr, &peer_addr);
+               ast_sockaddr_copy(&peer_addr, &p->addr);
 
                iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expiry);
                iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &peer_addr);
@@ -8927,7 +9020,7 @@ return_unref:
        return iaxs[callno] ? send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1) : -1;
 }
 
-static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_in *sin)
+static int registry_rerequest(struct iax_ies *ies, int callno, struct ast_sockaddr *addr)
 {
        struct iax2_registry *reg;
        /* Start pessimistic */
@@ -8945,12 +9038,9 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_i
        memset(&ied, 0, sizeof(ied));
        reg = iaxs[callno]->reg;
        if (reg) {
-               struct sockaddr_in reg_addr;
-
-               ast_sockaddr_to_sin(&reg->addr, &reg_addr);
 
-               if (inaddrcmp(&reg_addr, sin)) {
-                       ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_inet_ntoa(sin->sin_addr));
+               if (ast_sockaddr_cmp(&reg->addr, addr)) {
+                       ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_sockaddr_stringify(addr));
                        return -1;
                }
                if (ast_strlen_zero(reg->secret)) {
@@ -8964,9 +9054,9 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_i
                        char tmpkey[256];
                        ast_copy_string(tmpkey, reg->secret + 1, sizeof(tmpkey));
                        tmpkey[strlen(tmpkey) - 1] = '\0';
-                       res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, sin, NULL);
+                       res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, addr, NULL);
                } else
-                       res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, sin, NULL);
+                       res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, addr, NULL);
                if (!res) {
                        reg->regstate = REG_STATE_AUTHSENT;
                        add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
@@ -9168,8 +9258,9 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
        struct iax2_trunk_peer *tpeer = NULL, *drop = NULL;
        struct timeval now = ast_tvnow();
 
-       if (iaxtrunkdebug)
+       if (iaxtrunkdebug) {
                ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
+       }
 
        if (timer) {
                if (ast_timer_ack(timer, 1) < 0) {
@@ -9194,8 +9285,14 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
                } else {
                        res = send_trunk(tpeer, &now);
                        trunk_timed++;
-                       if (iaxtrunkdebug)
-                               ast_verbose(" - Trunk peer (%s:%d) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), res, (res != 1) ? "s" : "", tpeer->trunkdatalen, tpeer->trunkdataalloc);
+                       if (iaxtrunkdebug) {
+                               ast_verbose(" - Trunk peer (%s) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n",
+                                                       ast_sockaddr_stringify(&tpeer->addr),
+                                                       res,
+                                                       (res != 1) ? "s" : "",
+                                                       tpeer->trunkdatalen,
+                                                       tpeer->trunkdataalloc);
+                       }
                }
                totalcalls += res;
                res = 0;
@@ -9206,9 +9303,9 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
 
        if (drop) {
                ast_mutex_lock(&drop->lock);
-               /* Once we have this lock, we're sure nobody else is using it or could use it once we release it,
-                  because by the time they could get tpeerlock, we've already grabbed it */
-               ast_debug(1, "Dropping unused iax2 trunk peer '%s:%d'\n", ast_inet_ntoa(drop->addr.sin_addr), ntohs(drop->addr.sin_port));
+               /*  Once we have this lock, we're sure nobody else is using it or could use it once we release it,
+                       because by the time they could get tpeerlock, we've already grabbed it */
+               ast_debug(1, "Dropping unused iax2 trunk peer '%s'\n", ast_sockaddr_stringify(&drop->addr));
                if (drop->trunkdata) {
                        ast_free(drop->trunkdata);
                        drop->trunkdata = NULL;
@@ -9218,8 +9315,9 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
                ast_free(drop);
        }
 
-       if (iaxtrunkdebug)
+       if (iaxtrunkdebug) {
                ast_verbose("Ending trunk processing with %d peers and %d call chunks processed\n", processed, totalcalls);
+       }
        iaxtrunkdebug = 0;
 
        return 1;
@@ -9293,7 +9391,7 @@ static void spawn_dp_lookup(int callno, const char *context, const char *calledn
        }
 }
 
-static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
+static int check_provisioning(struct ast_sockaddr *addr, int sockfd, char *si, unsigned int ver)
 {
        unsigned int ourver;
        char rsi[80];
@@ -9302,7 +9400,7 @@ static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, uns
                return 0;
        ast_debug(1, "Service identifier '%s', we think '%08x', they think '%08x'\n", si, ourver, ver);
        if (ourver != ver)
-               iax2_provision(sin, sockfd, NULL, rsi, 1);
+               iax2_provision(addr, sockfd, NULL, rsi, 1);
        return 0;
 }
 
@@ -9470,7 +9568,6 @@ static void defer_full_frame(struct iax2_thread *from_here, struct iax2_thread *
 static int socket_read(int *id, int fd, short events, void *cbdata)
 {
        struct iax2_thread *thread;
-       socklen_t len;
        time_t t;
        static time_t last_errtime = 0;
        struct ast_iax2_full_hdr *fh;
@@ -9485,9 +9582,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                return 1;
        }
 
-       len = sizeof(thread->iosin);
        thread->iofd = fd;
-       thread->buf_len = recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, (struct sockaddr *) &thread->iosin, &len);
+       thread->buf_len = ast_recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, &thread->ioaddr);
        thread->buf_size = sizeof(thread->readbuf);
        thread->buf = thread->readbuf;
        if (thread->buf_len < 0) {
@@ -9515,7 +9611,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                AST_LIST_LOCK(&active_list);
                AST_LIST_TRAVERSE(&active_list, cur, list) {
                        if ((cur->ffinfo.callno == callno) &&
-                           !inaddrcmp(&cur->ffinfo.sin, &thread->iosin))
+                           !ast_sockaddr_cmp_addr(&cur->ffinfo.addr, &thread->ioaddr))
                                break;
                }
                if (cur) {
@@ -9529,7 +9625,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                } else {
                        /* this thread is going to process this frame, so mark it */
                        thread->ffinfo.callno = callno;
-                       memcpy(&thread->ffinfo.sin, &thread->iosin, sizeof(thread->ffinfo.sin));
+                       ast_sockaddr_copy(&thread->ffinfo.addr, &thread->ioaddr);
                        thread->ffinfo.type = fh->type;
                        thread->ffinfo.csub = fh->csub;
                        AST_LIST_INSERT_HEAD(&active_list, thread, list);
@@ -9547,7 +9643,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        return 1;
 }
 
-static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct sockaddr_in *sin, int sockfd,
+static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct ast_sockaddr *addr, int sockfd,
        struct iax_frame *fr)
 {
        unsigned char metatype;
@@ -9561,8 +9657,8 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
        struct ast_frame f = { 0, };
 
        if (packet_len < sizeof(*meta)) {
-               ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n",
-                       ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a meta frame but is too short\n",
+                               ast_sockaddr_stringify(addr));
                return 1;
        }
 
@@ -9579,10 +9675,10 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
        metatype = meta->cmddata;
        packet_len -= (sizeof(*meta) + sizeof(*mth));
        ptr = mth->data;
-       tpeer = find_tpeer(sin, sockfd);
+       tpeer = find_tpeer(addr, sockfd);
        if (!tpeer) {
-               ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n",
-                       ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s': No matching peer\n",
+                               ast_sockaddr_stringify(addr));
                return 1;
        }
        tpeer->trunkact = ast_tvnow();
@@ -9609,13 +9705,13 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
                        callno = ntohs(mte->callno);
                        trunked_ts = 0;
                } else {
-                       ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+                       ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s': dropping\n", ast_sockaddr_stringify(addr));
                        break;
                }
                /* Stop if we don't have enough data */
                if (len > packet_len)
                        break;
-               fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd, 0);
+               fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, addr, NEW_PREVENT, sockfd, 0);
                if (!fr->callno)
                        continue;
 
@@ -9769,7 +9865,7 @@ static void set_hangup_source_and_cause(int callno, unsigned char causecode)
 
 static int socket_process_helper(struct iax2_thread *thread)
 {
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        int res;
        int updatehistory=1;
        int new = NEW_PREVENT;
@@ -9806,7 +9902,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        /* Copy frequently used parameters to the stack */
        res = thread->buf_len;
        fd = thread->iofd;
-       memcpy(&sin, &thread->iosin, sizeof(sin));
+       ast_sockaddr_copy(&addr, &thread->ioaddr);
 
        if (res < sizeof(*mh)) {
                ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int) sizeof(*mh));
@@ -9814,23 +9910,25 @@ static int socket_process_helper(struct iax2_thread *thread)
        }
        if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) {
                if (res < sizeof(*vh)) {
-                       ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a video frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+                       ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a video frame but is too short\n",
+                                       ast_sockaddr_stringify(&addr));
                        return 1;
                }
 
                /* This is a video frame, get call number */
-               fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd, 0);
+               fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &addr, new, fd, 0);
                minivid = 1;
        } else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000))
-               return socket_process_meta(res, meta, &sin, fd, fr);
+               return socket_process_meta(res, meta, &addr, fd, fr);
 
 #ifdef DEBUG_SUPPORT
        if (res >= sizeof(*fh))
-               iax_outputframe(NULL, fh, 1, &sin, res - sizeof(*fh));
+               iax_outputframe(NULL, fh, 1, &addr, res - sizeof(*fh));
 #endif
        if (ntohs(mh->callno) & IAX_FLAG_FULL) {
                if (res < sizeof(*fh)) {
-                       ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a full frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+                       ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a full frame but is too short\n",
+                               ast_sockaddr_stringify(&addr));
                        return 1;
                }
 
@@ -9839,10 +9937,10 @@ static int socket_process_helper(struct iax2_thread *thread)
 
 
                /* check to make sure this full frame isn't encrypted before we attempt
-                * to look inside of it. If it is encrypted, decrypt it first. Its ok if the
+                * to look inside of it. If it is encrypted, decrypt it first. Its ok if the
                 * callno is not found here, that just means one hasn't been allocated for
                 * this connection yet. */
-               if ((dcallno != 1) && (fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, NEW_PREVENT, fd, 1))) {
+               if ((dcallno != 1) && (fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &addr, NEW_PREVENT, fd, 1))) {
                        ast_mutex_lock(&iaxsl[fr->callno]);
                        if (iaxs[fr->callno] && ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED)) {
                                if (decrypt_frame(fr->callno, fh, &f, &res)) {
@@ -9871,7 +9969,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                /* Deal with POKE/PONG without allocating a callno */
                if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_POKE) {
                        /* Reply back with a PONG, but don't care about the result. */
-                       send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+                       send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
                        return 1;
                } else if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_ACK && dcallno == 1) {
                        /* Ignore */
@@ -9882,7 +9980,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                if (f.datalen) {
                        if (f.frametype == AST_FRAME_IAX) {
                                if (iax_parse_ies(&ies, thread->buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
-                                       ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr));
+                                       ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_sockaddr_stringify(&addr));
                                        ast_variables_destroy(ies.vars);
                                        return 1;
                                }
@@ -9902,7 +10000,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
                if (!dcallno && iax2_allow_new(f.frametype, f.subclass.integer, 1)) {
                        /* only set NEW_ALLOW if calltoken checks out */
-                       if (handle_call_token(fh, &ies, &sin, fd)) {
+                       if (handle_call_token(fh, &ies, &addr, fd)) {
                                ast_variables_destroy(ies.vars);
                                return 1;
                        }
@@ -9939,11 +10037,11 @@ static int socket_process_helper(struct iax2_thread *thread)
                        check_dcallno = 1;
                }
 
-               if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, check_dcallno))) {
+               if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &addr, new, fd, check_dcallno))) {
                        if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_NEW) {
-                               send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+                               send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
                        } else if (f.frametype == AST_FRAME_IAX && (f.subclass.integer == IAX_COMMAND_REGREQ || f.subclass.integer == IAX_COMMAND_REGREL)) {
-                               send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+                               send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
                        }
                        ast_variables_destroy(ies.vars);
                        return 1;
@@ -9970,11 +10068,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                                 (f.subclass.integer != IAX_COMMAND_TXACC) &&
                                 (f.subclass.integer != IAX_COMMAND_FWDOWNL))||
                            (f.frametype != AST_FRAME_IAX))
-                               raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
+                               raw_hangup(&addr, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
                                fd);
                }
-               if (fr->callno > 0)
+               if (fr->callno > 0){
                        ast_mutex_unlock(&iaxsl[fr->callno]);
+               }
                ast_variables_destroy(ies.vars);
                return 1;
        }
@@ -9990,7 +10089,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
 #ifdef DEBUG_SUPPORT
        if (decrypted) {
-               iax_outputframe(NULL, fh, 3, &sin, res - sizeof(*fh));
+               iax_outputframe(NULL, fh, 3, &addr, res - sizeof(*fh));
        }
 #endif
 
@@ -10042,7 +10141,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        /* count this frame */
        iaxs[fr->callno]->frames_received++;
 
-       if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
+       if (!ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) && !minivid &&
                f.subclass.integer != IAX_COMMAND_TXCNT &&              /* for attended transfer */
                f.subclass.integer != IAX_COMMAND_TXACC) {              /* for attended transfer */
                unsigned short new_peercallno;
@@ -10139,7 +10238,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
                /* Handle implicit ACKing unless this is an INVAL, and only if this is
                   from the real peer, not the transfer peer */
-               if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
+               if (!ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) &&
                    ((f.subclass.integer != IAX_COMMAND_INVAL) ||
                     (f.frametype != AST_FRAME_IAX))) {
                        unsigned char x;
@@ -10187,7 +10286,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                ast_debug(1, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno);
                        }
                }
-               if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
+               if (ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) &&
                        ((f.frametype != AST_FRAME_IAX) ||
                         ((f.subclass.integer != IAX_COMMAND_TXACC) &&
                          (f.subclass.integer != IAX_COMMAND_TXCNT)))) {
@@ -10415,9 +10514,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                                /* Ignore if it's already up */
                                if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD))
                                        break;
-                               if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
+                               if (ies.provverpres && ies.serviceident && !(ast_sockaddr_isnull(&addr))) {
                                        ast_mutex_unlock(&iaxsl[fr->callno]);
-                                       check_provisioning(&sin, fd, ies.serviceident, ies.provver);
+                                       check_provisioning(&addr, fd, ies.serviceident, ies.provver);
                                        ast_mutex_lock(&iaxsl[fr->callno]);
                                        if (!iaxs[fr->callno]) {
                                                break;
@@ -10432,11 +10531,13 @@ static int socket_process_helper(struct iax2_thread *thread)
                                /* For security, always ack immediately */
                                if (delayreject)
                                        send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
-                               if (check_access(fr->callno, &sin, &ies)) {
+                               if (check_access(fr->callno, &addr, &ies)) {
                                        /* They're not allowed on */
                                        auth_fail(fr->callno, IAX_COMMAND_REJECT);
-                                       if (authdebug)
-                                               ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                       if (authdebug) {
+                                               ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n",
+                                                               ast_sockaddr_stringify(&addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                       }
                                        break;
                                }
                                if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_test_flag64(iaxs[fr->callno], IAX_FORCE_ENCRYPT)) {
@@ -10472,8 +10573,10 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                if (!iaxs[fr->callno]) {
                                                        break;
                                                }
-                                               if (authdebug)
-                                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                               if (authdebug) {
+                                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n",
+                                                                       ast_sockaddr_stringify(&addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                               }
                                        } else {
                                                /* Select an appropriate format */
 
@@ -10523,12 +10626,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                        char tmp[256], tmp2[256], tmp3[256];
                                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
+                                                                                       ast_sockaddr_stringify(&addr),
                                                                                        iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
                                                                                        iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
                                                                        } else {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
+                                                                                       ast_sockaddr_stringify(&addr),
                                                                                        iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
                                                                                        iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
                                                                                        iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
@@ -10575,7 +10678,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                        }
                                                                        if (authdebug) {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
+                                                                                       ast_sockaddr_stringify(&addr),
                                                                                        iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
                                                                                        iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
                                                                                        iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
@@ -10599,7 +10702,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                                "%sactual format = %s,\n"
                                                                                                "%shost prefs = %s,\n"
                                                                                                "%spriority = %s\n",
-                                                                                               ast_inet_ntoa(sin.sin_addr),
+                                                                                               ast_sockaddr_stringify(&addr),
                                                                                                VERBOSE_PREFIX_4,
                                                                                                iax2_getformatname(iaxs[fr->callno]->peerformat),
                                                                                                VERBOSE_PREFIX_4,
@@ -10619,7 +10722,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        } else {
                                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
                                                                /* If this is a TBD call, we're ready but now what...  */
-                                                               ast_verb(3, "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
+                                                               ast_verb(3, "Accepted unauthenticated TBD call from %s\n", ast_sockaddr_stringify(&addr));
                                                        }
                                                }
                                        }
@@ -10672,7 +10775,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                if (!ast_test_flag64(iaxs[fr->callno], IAX_PROVISION)) {
                                        if (iaxs[fr->callno]->owner && authdebug)
                                                ast_log(LOG_WARNING, "Call rejected by %s: %s\n",
-                                                       ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr),
+                                                       ast_sockaddr_stringify(&addr),
                                                        ies.cause ? ies.cause : "<Unknown>");
                                        ast_debug(1, "Immediately destroying %d, having received reject\n",
                                                fr->callno);
@@ -10730,7 +10833,8 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        else
                                                iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability;
                                }
-                               ast_verb(3, "Call accepted by %s (format %s)\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iax2_getformatname(iaxs[fr->callno]->peerformat));
+                               ast_verb(3, "Call accepted by %s (format %s)\n", ast_sockaddr_stringify(&addr),
+                                               iax2_getformatname(iaxs[fr->callno]->peerformat));
                                if (!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability)) {
                                        memset(&ied0, 0, sizeof(ied0));
                                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
@@ -10742,7 +10846,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        if (authdebug) {
                                                char tmp1[256], tmp2[256];
                                                ast_log(LOG_NOTICE, "Rejected call to %s, format %s incompatible with our capability %s.\n",
-                                                       ast_inet_ntoa(sin.sin_addr),
+                                                       ast_sockaddr_stringify(&addr),
                                                        iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
                                                        iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
                                        }
@@ -10864,7 +10968,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        iaxs[fr->callno]->lag = ts - fr->ts;
                                        if (iaxdebug)
                                                ast_debug(1, "Peer %s lag measured as %dms\n",
-                                                       ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->lag);
+                                                       ast_sockaddr_stringify(&addr), iaxs[fr->callno]->lag);
                                }
                                break;
                        case IAX_COMMAND_AUTHREQ:
@@ -10878,7 +10982,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        };
                                        ast_log(LOG_WARNING,
                                                "I don't know how to authenticate %s to %s\n",
-                                               ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
+                                               ies.username ? ies.username : "<unknown>", ast_sockaddr_stringify(&addr));
                                        iax2_queue_frame(fr->callno, &hangup_fr);
                                }
                                break;
@@ -10893,7 +10997,8 @@ static int socket_process_helper(struct iax2_thread *thread)
                                }
                                if (authenticate_verify(iaxs[fr->callno], &ies)) {
                                        if (authdebug)
-                                               ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->username);
+                                               ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_sockaddr_stringify(&addr),
+                                                               iaxs[fr->callno]->username);
                                        memset(&ied0, 0, sizeof(ied0));
                                        auth_fail(fr->callno, IAX_COMMAND_REJECT);
                                        break;
@@ -10905,7 +11010,10 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        exists = 0;
                                if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
                                        if (authdebug)
-                                               ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                               ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n",
+                                                               ast_sockaddr_stringify(&addr),
+                                                               iaxs[fr->callno]->exten,
+                                                               iaxs[fr->callno]->context);
                                        memset(&ied0, 0, sizeof(ied0));
                                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
                                        iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
@@ -10954,12 +11062,13 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                if (!format) {
                                                        if (authdebug) {
                                                                if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
-                                                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n", ast_inet_ntoa(sin.sin_addr),
+                                                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
+                                                                                       ast_sockaddr_stringify(&addr),
                                                                                iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
                                                                                iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
                                                                } else {
                                                                        ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-                                                                               ast_inet_ntoa(sin.sin_addr),
+                                                                               ast_sockaddr_stringify(&addr),
                                                                                iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
                                                                                iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
                                                                                iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
@@ -11008,12 +11117,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                if (authdebug) {
                                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
+                                                                                       ast_sockaddr_stringify(&addr),
                                                                                        iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
                                                                                        iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
                                                                        } else {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
+                                                                                       ast_sockaddr_stringify(&addr),
                                                                                        iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
                                                                                        iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
                                                                                        iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
@@ -11043,7 +11152,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                        "%sactual format = %s,\n"
                                                                                        "%shost prefs = %s,\n"
                                                                                        "%spriority = %s\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
+                                                                                       ast_sockaddr_stringify(&addr),
                                                                                        VERBOSE_PREFIX_4,
                                                                                        iax2_getformatname(iaxs[fr->callno]->peerformat),
                                                                                        VERBOSE_PREFIX_4,
@@ -11096,7 +11205,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                } else {
                                                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
                                                        /* If this is a TBD call, we're ready but now what...  */
-                                                       ast_verb(3, "Accepted AUTHENTICATED TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
+                                                       ast_verb(3, "Accepted AUTHENTICATED TBD call from %s\n", ast_sockaddr_stringify(&addr));
                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_IMMEDIATE)) {
                                                                goto immediatedial;
                                                        }
@@ -11111,7 +11220,10 @@ immediatedial:
                                        ast_string_field_set(iaxs[fr->callno], exten, ies.called_number ? ies.called_number : "s");
                                        if (!ast_exists_extension(NULL, iaxs[fr->callno]->context, iaxs[fr->callno]->exten, 1, iaxs[fr->callno]->cid_num)) {
                                                if (authdebug)
-                                                       ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                                       ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n",
+                                                                       ast_sockaddr_stringify(&addr),
+                                                                       iaxs[fr->callno]->exten,
+                                                                       iaxs[fr->callno]->context);
                                                memset(&ied0, 0, sizeof(ied0));
                                                iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
                                                iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
@@ -11123,8 +11235,8 @@ immediatedial:
                                                char tmp[256];
                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                                ast_verb(3, "Accepting DIAL from %s, formats = %s\n",
-                                                       ast_inet_ntoa(sin.sin_addr),
-                                                       iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat));
+                                                               ast_sockaddr_stringify(&addr),
+                                                               iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat));
                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                                send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1);
                                                if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, 1)))
@@ -11183,7 +11295,7 @@ immediatedial:
                                /* For security, always ack immediately */
                                if (delayreject)
                                        send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
-                               if (register_verify(fr->callno, &sin, &ies)) {
+                               if (register_verify(fr->callno, &addr, &ies)) {
                                        if (!iaxs[fr->callno]) {
                                                break;
                                        }
@@ -11198,18 +11310,17 @@ immediatedial:
                                                ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED)) {
 
                                        if (f.subclass.integer == IAX_COMMAND_REGREL) {
-                                               memset(&sin, 0, sizeof(sin));
-                                               sin.sin_family = AF_INET;
+                                               ast_sockaddr_setnull(&addr);
                                        }
-                                       if (update_registry(&sin, fr->callno, ies.devicetype, fd, ies.refresh)) {
+                                       if (update_registry(&addr, fr->callno, ies.devicetype, fd, ies.refresh)) {
                                                ast_log(LOG_WARNING, "Registry error\n");
                                        }
                                        if (!iaxs[fr->callno]) {
                                                break;
                                        }
-                                       if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
+                                       if (ies.provverpres && ies.serviceident && !(ast_sockaddr_isnull(&addr))) {
                                                ast_mutex_unlock(&iaxsl[fr->callno]);
-                                               check_provisioning(&sin, fd, ies.serviceident, ies.provver);
+                                               check_provisioning(&addr, fd, ies.serviceident, ies.provver);
                                                ast_mutex_lock(&iaxsl[fr->callno]);
                                        }
                                        break;
@@ -11217,8 +11328,9 @@ immediatedial:
                                registry_authrequest(fr->callno);
                                break;
                        case IAX_COMMAND_REGACK:
-                               if (iax2_ack_registry(&ies, &sin, fr->callno))
+                               if (iax2_ack_registry(&ies, &addr, fr->callno)) {
                                        ast_log(LOG_WARNING, "Registration failure\n");
+                               }
                                /* Send ack immediately, before we destroy */
                                send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
                                iax2_destroy(fr->callno);
@@ -11226,9 +11338,11 @@ immediatedial:
                        case IAX_COMMAND_REGREJ:
                                if (iaxs[fr->callno]->reg) {
                                        if (authdebug) {
-                                               ast_log(LOG_NOTICE, "Registration of '%s' rejected: '%s' from: '%s'\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>", ast_inet_ntoa(sin.sin_addr));
+                                               ast_log(LOG_NOTICE, "Registration of '%s' rejected: '%s' from: '%s'\n",
+                                                               iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>",
+                                                               ast_sockaddr_stringify(&addr));
                                        }
-                                       iax2_publish_registry(iaxs[fr->callno]->reg->username, ast_inet_ntoa(sin.sin_addr), "Rejected", S_OR(ies.cause, "<unknown>"));
+                                       iax2_publish_registry(iaxs[fr->callno]->reg->username, ast_sockaddr_stringify(&addr), "Rejected", S_OR(ies.cause, "<unknown>"));
                                        iaxs[fr->callno]->reg->regstate = REG_STATE_REJECTED;
                                }
                                /* Send ack immediately, before we destroy */
@@ -11237,7 +11351,7 @@ immediatedial:
                                break;
                        case IAX_COMMAND_REGAUTH:
                                /* Authentication request */
-                               if (registry_rerequest(&ies, fr->callno, &sin)) {
+                               if (registry_rerequest(&ies, fr->callno, &addr)) {
                                        memset(&ied0, 0, sizeof(ied0));
                                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No authority found");
                                        iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_FACILITY_NOT_SUBSCRIBED);
@@ -11753,7 +11867,7 @@ static int iax2_do_register(struct iax2_registry *reg)
                ast_debug(1, "Sending registration request for '%s'\n", reg->username);
 
        if (reg->dnsmgr &&
-           ((reg->regstate == REG_STATE_TIMEOUT) || !ast_sockaddr_ipv4(&reg->addr))) {
+           ((reg->regstate == REG_STATE_TIMEOUT) || ast_sockaddr_isnull(&reg->addr))) {
                /* Maybe the IP has changed, force DNS refresh */
                ast_dnsmgr_refresh(reg->dnsmgr);
        }
@@ -11769,7 +11883,7 @@ static int iax2_do_register(struct iax2_registry *reg)
                ast_mutex_unlock(&iaxsl[callno]);
                reg->callno = 0;
        }
-       if (!ast_sockaddr_ipv4(&reg->addr)) {
+       if (ast_sockaddr_isnull(&reg->addr)) {
                if (iaxdebug)
                        ast_debug(1, "Unable to send registration request for '%s' without IP address\n", reg->username);
                /* Setup the next registration attempt */
@@ -11779,13 +11893,10 @@ static int iax2_do_register(struct iax2_registry *reg)
        }
 
        if (!reg->callno) {
-               struct sockaddr_in reg_addr;
 
                ast_debug(3, "Allocate call number\n");
 
-               ast_sockaddr_to_sin(&reg->addr, &reg_addr);
-
-               reg->callno = find_callno_locked(0, 0, &reg_addr, NEW_FORCE, defaultsockfd, 0);
+               reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd, 0);
                if (reg->callno < 1) {
                        ast_log(LOG_WARNING, "Unable to create call for registration\n");
                        return -1;
@@ -11807,14 +11918,14 @@ static int iax2_do_register(struct iax2_registry *reg)
        return 0;
 }
 
-static int iax2_provision(struct sockaddr_in *end, int sockfd, const char *dest, const char *template, int force)
+static int iax2_provision(struct ast_sockaddr *end, int sockfd, const char *dest, const char *template, int force)
 {
        /* Returns 1 if provisioned, -1 if not able to find destination, or 0 if no provisioning
           is found for template */
        struct iax_ie_data provdata;
        struct iax_ie_data ied;
        unsigned int sig;
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        int callno;
        struct create_addr_info cai;
 
@@ -11828,16 +11939,16 @@ static int iax2_provision(struct sockaddr_in *end, int sockfd, const char *dest,
        }
 
        if (end) {
-               memcpy(&sin, end, sizeof(sin));
+               ast_sockaddr_copy(&addr, end);
                cai.sockfd = sockfd;
-       } else if (create_addr(dest, NULL, &sin, &cai))
+       } else if (create_addr(dest, NULL, &addr, &cai))
                return -1;
 
        /* Build the rest of the message */
        memset(&ied, 0, sizeof(ied));
        iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos);
 
-       callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
+       callno = find_callno_locked(0, 0, &addr, NEW_FORCE, cai.sockfd, 0);
        if (!callno)
                return -1;
 
@@ -11877,13 +11988,13 @@ static int iax2_prov_app(struct ast_channel *chan, const char *data)
                ast_log(LOG_NOTICE, "Can't provision a non-IAX device!\n");
                return -1;
        }
-       if (!callno || !iaxs[callno] || !iaxs[callno]->addr.sin_addr.s_addr) {
+       if (!callno || !iaxs[callno] || ast_sockaddr_isnull(&iaxs[callno]->addr)) {
                ast_log(LOG_NOTICE, "Can't provision something with no IP?\n");
                return -1;
        }
        res = iax2_provision(&iaxs[callno]->addr, iaxs[callno]->sockfd, NULL, sdata, force);
        ast_verb(3, "Provisioned IAXY at '%s' with '%s'= %d\n",
-               ast_inet_ntoa(iaxs[callno]->addr.sin_addr),
+               ast_sockaddr_stringify(&iaxs[callno]->addr),
                sdata, res);
        return res;
 }
@@ -11980,9 +12091,8 @@ static int iax2_poke_peer_cb(void *obj, void *arg, int flags)
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
 {
        int callno;
-       struct sockaddr_in peer_addr;
 
-       if (!peer->maxms || (!ast_sockaddr_ipv4(&peer->addr) && !peer->dnsmgr)) {
+       if (!peer->maxms || (ast_sockaddr_isnull(&peer->addr) && !peer->dnsmgr)) {
                /* IF we have no IP without dnsmgr, or this isn't to be monitored, return
                  immediately after clearing things out */
                peer->lastms = 0;
@@ -11992,8 +12102,6 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
                return 0;
        }
 
-       ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
        /* The peer could change the callno inside iax2_destroy, since we do deadlock avoidance */
        if ((callno = peer->callno) > 0) {
                ast_log(LOG_NOTICE, "Still have a callno...\n");
@@ -12003,7 +12111,7 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
        }
        if (heldcall)
                ast_mutex_unlock(&iaxsl[heldcall]);
-       callno = peer->callno = find_callno(0, 0, &peer_addr, NEW_FORCE, peer->sockfd, 0);
+       callno = peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd, 0);
        if (heldcall)
                ast_mutex_lock(&iaxsl[heldcall]);
        if (peer->callno < 1) {
@@ -12061,7 +12169,7 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
 {
        int callno;
        int res;
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        struct ast_channel *c;
        struct parsed_dial_string pds;
        struct create_addr_info cai;
@@ -12084,15 +12192,18 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap
        ast_copy_flags64(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
 
        /* Populate our address from the given */
-       if (create_addr(pds.peer, NULL, &sin, &cai)) {
+       if (create_addr(pds.peer, NULL, &addr, &cai)) {
                *cause = AST_CAUSE_UNREGISTERED;
                return NULL;
        }
 
-       if (pds.port)
-               sin.sin_port = htons(atoi(pds.port));
+       if (pds.port) {
+               int bindport;
+               ast_parse_arg(pds.port, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535);
+               ast_sockaddr_set_port(&addr, bindport);
+       }
 
-       callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
+       callno = find_callno_locked(0, 0, &addr, NEW_FORCE, cai.sockfd, 0);
        if (callno < 1) {
                ast_log(LOG_WARNING, "Unable to create call\n");
                *cause = AST_CAUSE_CONGESTION;
@@ -12287,8 +12398,6 @@ static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr)
                        port = IAX_DEFAULT_PORTNO;
        }
 
-       addr.ss.ss_family = AF_INET;
-
        if (!ast_get_ip(&addr, host)) {
                struct ast_netsock *sock;
 
@@ -12391,8 +12500,6 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                peer->expire = -1;
                peer->pokeexpire = -1;
                peer->sockfd = defaultsockfd;
-               peer->addr.ss.ss_family = AF_INET;
-               peer->addr.len = sizeof(struct sockaddr_in);
                if (ast_string_field_init(peer, 32))
                        peer = peer_unref(peer);
                if (!(peer->endpoint = ast_endpoint_create("IAX2", name))) {
@@ -12405,9 +12512,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                        ast_copy_flags64(peer, &globalflags, IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
                        peer->encmethods = iax2_encryption;
                        peer->adsi = adsi;
-                       ast_string_field_set(peer,secret,"");
+                       ast_string_field_set(peer, secret, "");
                        if (!found) {
                                ast_string_field_set(peer, name, name);
+                               ast_sockaddr_parse(&peer->addr, "0.0.0.0", 0);
                                ast_sockaddr_set_port(&peer->addr, IAX_DEFAULT_PORTNO);
                                peer->expiry = min_reg_expire;
                        }
@@ -12487,10 +12595,9 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                                        /* They'll register with us */
                                        ast_set_flag64(peer, IAX_DYNAMIC);
                                        if (!found) {
-                                               /* Initialize stuff iff we're not found, otherwise
-                                                  we keep going with what we had */
-                                               if (ast_sockaddr_port(&peer->addr)) {
-                                                       peer->defaddr.sin_port = htons(ast_sockaddr_port(&peer->addr));
+                                               int peer_port = ast_sockaddr_port(&peer->addr);
+                                               if (peer_port) {
+                                                       ast_sockaddr_set_port(&peer->defaddr, peer_port);
                                                }
                                                ast_sockaddr_setnull(&peer->addr);
                                        }
@@ -12498,23 +12605,22 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                                        /* Non-dynamic.  Make sure we become that way if we're not */
                                        AST_SCHED_DEL(sched, peer->expire);
                                        ast_clear_flag64(peer, IAX_DYNAMIC);
-                                       if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL))
+                                       peer->addr.ss.ss_family = AST_AF_UNSPEC;
+                                       if (ast_dnsmgr_lookup(v->value, &peer->addr, &peer->dnsmgr, srvlookup ? "_iax._udp" : NULL)) {
                                                return peer_unref(peer);
+                                       }
                                        if (!ast_sockaddr_port(&peer->addr)) {
                                                ast_sockaddr_set_port(&peer->addr, IAX_DEFAULT_PORTNO);
                                        }
                                }
-                               if (!maskfound)
-                                       inet_aton("255.255.255.255", &peer->mask);
                        } else if (!strcasecmp(v->name, "defaultip")) {
                                struct ast_sockaddr peer_defaddr_tmp;
-
-                               peer_defaddr_tmp.ss.ss_family = AF_INET;
+                               peer_defaddr_tmp.ss.ss_family = AF_UNSPEC;
                                if (ast_get_ip(&peer_defaddr_tmp, v->value)) {
                                        return peer_unref(peer);
                                }
-                               ast_sockaddr_to_sin(&peer_defaddr_tmp,
-                                                   &peer->defaddr);
+                               ast_sockaddr_set_port(&peer_defaddr_tmp, ast_sockaddr_port(&peer->defaddr));
+                               ast_sockaddr_copy(&peer->defaddr, &peer_defaddr_tmp);
                        } else if (!strcasecmp(v->name, "sourceaddress")) {
                                peer_set_srcaddr(peer, v->value);
                        } else if (!strcasecmp(v->name, "permit") ||
@@ -12523,7 +12629,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                                ast_append_acl(v->name, v->value, &peer->acl, NULL, &subscribe_acl_change);
                        } else if (!strcasecmp(v->name, "mask")) {
                                maskfound++;
-                               inet_aton(v->value, &peer->mask);
+                               ast_sockaddr_parse(&peer->mask, v->value, 0);
                        } else if (!strcasecmp(v->name, "context")) {
                                ast_string_field_set(peer, context, v->value);
                        } else if (!strcasecmp(v->name, "regexten")) {
@@ -12531,10 +12637,14 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                        } else if (!strcasecmp(v->name, "peercontext")) {
                                ast_string_field_set(peer, peercontext, v->value);
                        } else if (!strcasecmp(v->name, "port")) {
+                               int bindport;
+                               if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
+                                       bindport = IAX_DEFAULT_PORTNO;
+                               }
                                if (ast_test_flag64(peer, IAX_DYNAMIC)) {
-                                       peer->defaddr.sin_port = htons(atoi(v->value));
+                                       ast_sockaddr_set_port(&peer->defaddr, bindport);
                                } else {
-                                       ast_sockaddr_set_port(&peer->addr, atoi(v->value));
+                                       ast_sockaddr_set_port(&peer->addr, bindport);
                                }
                        } else if (!strcasecmp(v->name, "username")) {
                                ast_string_field_set(peer, username, v->value);
@@ -12631,8 +12741,19 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                ast_clear_flag64(peer, IAX_DELME);
        }
 
-       if (oldacl)
+       if (!maskfound && !ast_sockaddr_isnull(&peer->addr)) {
+               if (ast_sockaddr_is_ipv4_mapped(&peer->addr)) {
+                       ast_sockaddr_parse(&peer->mask, "::ffff:ffff:ffff", 0);
+               } else if (ast_sockaddr_is_ipv6(&peer->addr)) {
+                       ast_sockaddr_parse(&peer->mask, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0);
+               } else {
+                       ast_sockaddr_parse(&peer->mask, "255.255.255.255", 0);
+               }
+       }
+
+       if (oldacl) {
                ast_free_acl_list(oldacl);
+       }
 
        if (!ast_strlen_zero(peer->mailbox)) {
                char *mailbox, *context;
@@ -13044,6 +13165,7 @@ static int set_config(const char *config_file, int reload, int forced)
        struct iax2_peer *peer;
        struct ast_netsock *ns;
        struct ast_flags config_flags = { (reload && !forced) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+       struct ast_sockaddr bindaddr;
 #if 0
        static unsigned short int last_port=0;
 #endif
@@ -13085,6 +13207,8 @@ static int set_config(const char *config_file, int reload, int forced)
                set_config_destroy();
        }
 
+       ast_sockaddr_parse(&bindaddr, "0.0.0.0:0", 0);
+
        /* Reset global codec prefs */
        memset(&prefs, 0 , sizeof(struct ast_codec_pref));
 
@@ -13124,13 +13248,17 @@ static int set_config(const char *config_file, int reload, int forced)
                        ast_log(LOG_WARNING, "Invalid cos value, refer to QoS documentation\n");
        }
        while(v) {
-               if (!strcasecmp(v->name, "bindport")){
-                       if (reload)
+               if (!strcasecmp(v->name, "bindport")) {
+                       if (reload) {
                                ast_log(LOG_NOTICE, "Ignoring bindport on reload\n");
-                       else
-                               portno = atoi(v->value);
-               } else if (!strcasecmp(v->name, "pingtime"))
+                       }
+                       else if (ast_parse_arg(v->value, PARSE_UINT32 | PARSE_IN_RANGE, &portno, 1024, 65535)) {
+                               portno = IAX_DEFAULT_PORTNO;
+                       }
+                       ast_sockaddr_set_port(&bindaddr, portno);
+               } else if (!strcasecmp(v->name, "pingtime")){
                        ping_time = atoi(v->value);
+               }
                else if (!strcasecmp(v->name, "iaxthreadcount")) {
                        if (reload) {
                                if (atoi(v->value) != iaxthreadcount)
@@ -13189,16 +13317,18 @@ static int set_config(const char *config_file, int reload, int forced)
                        if (reload) {
                                ast_log(LOG_NOTICE, "Ignoring bindaddr on reload\n");
                        } else {
-                               if (!(ns = ast_netsock_bind(netsock, io, v->value, portno, qos.tos, qos.cos, socket_read, NULL))) {
-                                       ast_log(LOG_WARNING, "Unable apply binding to '%s' at line %d\n", v->value, v->lineno);
+                               /* remember port if it has already been set */
+                               int setport = ast_sockaddr_port(&bindaddr);
+
+                               if (ast_parse_arg(v->value, PARSE_ADDR | PARSE_PORT_IGNORE, NULL)) {
+                                       ast_log(LOG_WARNING, "Invalid address '%s' specified, default '%s' will be used\n", v->value,
+                                               ast_sockaddr_stringify(&bindaddr));
                                } else {
-                                               if (strchr(v->value, ':'))
-                                               ast_verb(2, "Binding IAX2 to '%s'\n", v->value);
-                                               else
-                                               ast_verb(2, "Binding IAX2 to '%s:%d'\n", v->value, portno);
-                                       if (defaultsockfd < 0)
-                                               defaultsockfd = ast_netsock_sockfd(ns);
-                                       ast_netsock_unref(ns);
+                                       ast_sockaddr_parse(&bindaddr, v->value, PARSE_PORT_IGNORE);
+                               }
+
+                               if (setport) {
+                                       ast_sockaddr_set_port(&bindaddr, setport);
                                }
                        }
                } else if (!strcasecmp(v->name, "authdebug")) {
@@ -13397,11 +13527,15 @@ static int set_config(const char *config_file, int reload, int forced)
                network_change_stasis_unsubscribe();
        }
 
+       if (!ast_sockaddr_port(&bindaddr)) {
+               ast_sockaddr_set_port(&bindaddr, IAX_DEFAULT_PORTNO);
+       }
+
        if (defaultsockfd < 0) {
-               if (!(ns = ast_netsock_bind(netsock, io, "0.0.0.0", portno, qos.tos, qos.cos, socket_read, NULL))) {
+               if (!(ns = ast_netsock_bindaddr(netsock, io, &bindaddr, qos.tos, qos.cos, socket_read, NULL))) {
                        ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
                } else {
-                       ast_verb(2, "Binding IAX2 to default address 0.0.0.0:%d\n", portno);
+                       ast_verb(2, "Binding IAX2 to address %s\n", ast_sockaddr_stringify(&bindaddr));
                        defaultsockfd = ast_netsock_sockfd(ns);
                        ast_netsock_unref(ns);
                }
@@ -13446,8 +13580,9 @@ static int set_config(const char *config_file, int reload, int forced)
                                        }
                                        peer = build_peer(cat, gen, ast_variable_browse(ucfg, cat), 0);
                                        if (peer) {
-                                               if (ast_test_flag64(peer, IAX_DYNAMIC))
+                                               if (ast_test_flag64(peer, IAX_DYNAMIC)) {
                                                        reg_source_db(peer);
+                                               }
                                                ao2_link(peers, peer);
                                                peer = peer_unref(peer);
                                        }
@@ -13579,7 +13714,7 @@ static int reload(void)
 
 static int cache_get_callno_locked(const char *data)
 {
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        int x;
        int callno;
        struct iax_ie_data ied;
@@ -13612,13 +13747,13 @@ static int cache_get_callno_locked(const char *data)
        }
 
        /* Populate our address from the given */
-       if (create_addr(pds.peer, NULL, &sin, &cai))
+       if (create_addr(pds.peer, NULL, &addr, &cai))
                return -1;
 
        ast_debug(1, "peer: %s, username: %s, password: %s, context: %s\n",
                pds.peer, pds.username, pds.password, pds.context);
 
-       callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
+       callno = find_callno_locked(0, 0, &addr, NEW_FORCE, cai.sockfd, 0);
        if (callno < 1) {
                ast_log(LOG_WARNING, "Unable to create call\n");
                return -1;
@@ -13916,7 +14051,7 @@ static int function_iaxpeer(struct ast_channel *chan, const char *cmd, char *dat
                if (ast_channel_tech(chan) != &iax2_tech)
                        return -1;
                callno = PTR_TO_CALLNO(ast_channel_tech_pvt(chan));
-               ast_copy_string(buf, iaxs[callno]->addr.sin_addr.s_addr ? ast_inet_ntoa(iaxs[callno]->addr.sin_addr) : "", len);
+               ast_copy_string(buf, !ast_sockaddr_isnull(&iaxs[callno]->addr) ? ast_sockaddr_stringify_addr(&iaxs[callno]->addr) : "", len);
                return 0;
        }
 
@@ -13997,7 +14132,7 @@ static int acf_channel_read(struct ast_channel *chan, const char *funcname, char
        if (!strcasecmp(args, "osptoken")) {
                ast_copy_string(buf, pvt->osptoken, buflen);
        } else if (!strcasecmp(args, "peerip")) {
-               ast_copy_string(buf, pvt->addr.sin_addr.s_addr ? ast_inet_ntoa(pvt->addr.sin_addr) : "", buflen);
+               ast_copy_string(buf, !ast_sockaddr_isnull(&pvt->addr) ? ast_sockaddr_stringify_addr(&pvt->addr) : "", buflen);
        } else if (!strcasecmp(args, "peername")) {
                ast_copy_string(buf, pvt->username, buflen);
        } else if (!strcasecmp(args, "secure_signaling") || !strcasecmp(args, "secure_media")) {
@@ -14034,10 +14169,11 @@ static int iax2_devicestate(const char *data)
                return res;
 
        res = AST_DEVICE_UNAVAILABLE;
-       ast_debug(3, "Found peer. What's device state of %s? addr=%d, defaddr=%d maxms=%d, lastms=%d\n",
-               pds.peer, ast_sockaddr_ipv4(&p->addr), p->defaddr.sin_addr.s_addr, p->maxms, p->lastms);
 
-       if ((ast_sockaddr_ipv4(&p->addr) || p->defaddr.sin_addr.s_addr) &&
+       ast_debug(3, "Found peer. What's device state of %s? addr=%s, defaddr=%s maxms=%d, lastms=%d\n",
+               pds.peer, ast_sockaddr_stringify(&p->addr), ast_sockaddr_stringify(&p->defaddr), p->maxms, p->lastms);
+
+       if (((!ast_sockaddr_isnull(&p->addr)) || (!ast_sockaddr_isnull(&p->defaddr))) &&
            (!p->maxms || ((p->lastms > -1) && (p->historicms <= p->maxms)))) {
                /* Peer is registered, or have default IP address
                   and a valid registration */
@@ -14479,7 +14615,7 @@ static int peers_data_provider_get(const struct ast_data_search *search,
 
                ast_data_add_str(data_peer, "host", ast_sockaddr_stringify_host(&peer->addr));
 
-               ast_data_add_str(data_peer, "mask", ast_inet_ntoa(peer->mask));
+               ast_data_add_str(data_peer, "mask", ast_sockaddr_stringify_addr(&peer->mask));
 
                ast_data_add_int(data_peer, "port", ast_sockaddr_port(&peer->addr));
 
index caaa098..d17def8 100644 (file)
@@ -47,7 +47,7 @@ struct iax_ies {
        char *challenge;
        char *md5_result;
        char *rsa_result;
-       struct sockaddr_in *apparent_addr;
+       struct ast_sockaddr apparent_addr;
        unsigned short refresh;
        unsigned short dpstatus;
        unsigned short callno;
@@ -153,13 +153,13 @@ struct iax_ie_data {
 void iax_set_output(void (*output)(const char *data));
 /* Choose a different function for errors */
 void iax_set_error(void (*output)(const char *data));
-void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen);
+void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen);
 void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len);
 
 const char *iax_ie2str(int ie);
 
 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen);
-int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin);
+int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct ast_sockaddr *addr);
 int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value);
 int iax_ie_append_int(struct iax_ie_data *ied, unsigned char ie, unsigned int value);
 int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value);
index e77a9b3..ee4a6c3 100644 (file)
@@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/config.h"
 #include "asterisk/lock.h"
 #include "asterisk/threadstorage.h"
+#include "asterisk/netsock2.h"
 
 #include "include/iax2.h"
 #include "include/parser.h"
@@ -83,13 +84,23 @@ static void (*errorf)(const char *str) = internalerror;
 
 static void dump_addr(char *output, int maxlen, void *value, int len)
 {
-       struct sockaddr_in sin;
-       if (len == (int)sizeof(sin)) {
-               memcpy(&sin, value, len);
-               snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+       struct ast_sockaddr addr;
+
+       if (len == (int)sizeof(struct sockaddr_in)) {
+               addr.ss.ss_family = AF_INET;
+       } else if (len == (int) sizeof(struct sockaddr_in6)) {
+               addr.ss.ss_family = AF_INET6;
        } else {
                ast_copy_string(output, "Invalid Address", maxlen);
+               return;
        }
+
+       memcpy(&addr, value, len);
+       addr.len = len;
+
+       snprintf(output, maxlen, "%s %s",
+                               ast_sockaddr_is_ipv4(&addr) || ast_sockaddr_is_ipv4_mapped(&addr) ? "IPV4" : "IPV6",
+                               ast_sockaddr_stringify(&addr));
 }
 
 static void dump_string_hex(char *output, int maxlen, void *value, int len)
@@ -172,12 +183,23 @@ static void dump_datetime(char *output, int maxlen, void *value, int len)
 
 static void dump_ipaddr(char *output, int maxlen, void *value, int len)
 {
-       struct sockaddr_in sin;
-       if (len == (int)sizeof(unsigned int)) {
-               memcpy(&sin.sin_addr, value, len);
-               snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr));
-       } else
+       struct ast_sockaddr addr;
+       char *str_addr;
+
+       if (len == (int)sizeof(struct sockaddr_in)) {
+               addr.ss.ss_family = AF_INET;
+       } else if (len == (int)sizeof(struct sockaddr_in6)) {
+               addr.ss.ss_family = AF_INET6;
+       } else {
                ast_copy_string(output, "Invalid IPADDR", maxlen);
+               return;
+       }
+
+       memcpy(&addr, value, len);
+       addr.len = len;
+
+       str_addr = ast_sockaddr_stringify(&addr);
+       ast_copy_string(output, str_addr, maxlen);
 }
 
 
@@ -564,7 +586,7 @@ void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t
        ast_copy_string(str, cmd, len);
 }
 
-void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
+void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen)
 {
        const char *framelist[] = {
                "(0?)",
@@ -677,19 +699,22 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
                snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
                subclass = subclass2;
        }
-       snprintf(tmp, sizeof(tmp), 
-                "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
+
+       snprintf(tmp, sizeof(tmp),
+               "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
                 dir,
                 retries, fh->oseqno, fh->iseqno, class, subclass);
        outputf(tmp);
-       snprintf(tmp, sizeof(tmp), 
-                "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%d]\n",
-                (unsigned long)ntohl(fh->ts),
-                ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
-                ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+       snprintf(tmp, sizeof(tmp), "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d %s\n",
+                       (unsigned long)ntohl(fh->ts),
+                       ntohs(fh->scallno) & ~IAX_FLAG_FULL,
+                       ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
+                       ast_sockaddr_stringify(addr));
+
        outputf(tmp);
        if (fh->type == AST_FRAME_IAX)
                dump_ies(fh->iedata, datalen);
+
 }
 
 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
@@ -707,9 +732,9 @@ int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *dat
        return 0;
 }
 
-int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct sockaddr_in *sin)
+int iax_ie_append_addr(struct iax_ie_data *ied, unsigned char ie, const struct ast_sockaddr *addr)
 {
-       return iax_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in));
+       return iax_ie_append_raw(ied, ie, addr, addr->len);
 }
 
 int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value)
@@ -904,7 +929,8 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
                        ies->rsa_result = (char *)data + 2;
                        break;
                case IAX_IE_APPARENT_ADDR:
-                       ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
+                       memcpy(&ies->apparent_addr , (struct ast_sockaddr *) (data + 2), len);
+                       ies->apparent_addr.len = len;
                        break;
                case IAX_IE_REFRESH:
                        if (len != (int)sizeof(unsigned short)) {
index a039d1b..90122f6 100644 (file)
@@ -51,6 +51,18 @@ enum ast_transport {
 };
 
 /*!
+ * \brief
+ * Isolate a 32-bit section of an IPv6 address
+ *
+ * An IPv6 address can be divided into 4 32-bit chunks. This gives
+ * easy access to one of these chunks.
+ *
+ * \param sin6 A pointer to a struct sockaddr_in6
+ * \param index Which 32-bit chunk to operate on. Must be in the range 0-3.
+ */
+#define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
+
+/*!
  * \brief Socket address structure.
  *
  * \details
@@ -400,6 +412,23 @@ int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
                         int flags, int family);
 
 /*!
+ * \brief
+ * Apply a netmask to an address and store the result in a separate structure.
+ *
+ * When dealing with IPv6 addresses, one cannot apply a netmask with a simple
+ * logical AND operation.  Futhermore, the incoming address may be an IPv4
+ * address and needs to be mapped properly before attempting to apply a rule.
+ *
+ * \param addr The IP address to apply the mask to.
+ * \param netmask The netmask configured in the host access rule.
+ * \param result The resultant address after applying the netmask to the given address
+ * \retval 0 Successfully applied netmask
+ * \retval -1 Failed to apply netmask
+ */
+int ast_sockaddr_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
+               struct ast_sockaddr *result);
+
+/*!
  * \since 1.8
  *
  * \brief
index 148cb08..a4567be 100644 (file)
@@ -349,63 +349,6 @@ struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original)
 
 /*!
  * \brief
- * Isolate a 32-bit section of an IPv6 address
- *
- * An IPv6 address can be divided into 4 32-bit chunks. This gives
- * easy access to one of these chunks.
- *
- * \param sin6 A pointer to a struct sockaddr_in6
- * \param index Which 32-bit chunk to operate on. Must be in the range 0-3.
- */
-#define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
-
-/*!
- * \brief
- * Apply a netmask to an address and store the result in a separate structure.
- *
- * When dealing with IPv6 addresses, one cannot apply a netmask with a simple
- * logical and operation. Furthermore, the incoming address may be an IPv4 address
- * and need to be mapped properly before attempting to apply a rule.
- *
- * \param addr The IP address to apply the mask to.
- * \param netmask The netmask configured in the host access rule.
- * \param result The resultant address after applying the netmask to the given address
- * \retval 0 Successfully applied netmask
- * \retval -1 Failed to apply netmask
- */
-static int apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
-               struct ast_sockaddr *result)
-{
-       int res = 0;
-
-       if (ast_sockaddr_is_ipv4(addr)) {
-               struct sockaddr_in result4 = { 0, };
-               struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr->ss;
-               struct sockaddr_in *mask4 = (struct sockaddr_in *) &netmask->ss;
-               result4.sin_family = AF_INET;
-               result4.sin_addr.s_addr = addr4->sin_addr.s_addr & mask4->sin_addr.s_addr;
-               ast_sockaddr_from_sin(result, &result4);
-       } else if (ast_sockaddr_is_ipv6(addr)) {
-               struct sockaddr_in6 result6 = { 0, };
-               struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr->ss;
-               struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *) &netmask->ss;
-               int i;
-               result6.sin6_family = AF_INET6;
-               for (i = 0; i < 4; ++i) {
-                       V6_WORD(&result6, i) = V6_WORD(addr6, i) & V6_WORD(mask6, i);
-               }
-               memcpy(&result->ss, &result6, sizeof(result6));
-               result->len = sizeof(result6);
-       } else {
-               /* Unsupported address scheme */
-               res = -1;
-       }
-
-       return res;
-}
-
-/*!
- * \brief
  * Parse a netmask in CIDR notation
  *
  * \details
@@ -468,8 +411,6 @@ static int parse_cidr_mask(struct ast_sockaddr *addr, int is_v4, const char *mas
        return 0;
 }
 
-
-
 void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
 {
        struct ast_acl *acl = NULL;
@@ -693,7 +634,7 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
                        return ret;
                }
 
-               if (apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
+               if (ast_sockaddr_apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
                        /* This shouldn't happen because ast_sockaddr_parse would
                         * have failed much earlier on an unsupported address scheme
                         */
@@ -805,7 +746,7 @@ enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockad
 
                /* For each rule, if this address and the netmask = the net address
                   apply the current rule */
-               if (apply_netmask(addr_to_use, &current_ha->netmask, &result)) {
+               if (ast_sockaddr_apply_netmask(addr_to_use, &current_ha->netmask, &result)) {
                        /* Unlikely to happen since we know the address to be IPv4 or IPv6 */
                        continue;
                }
index 598bc4b..18bf561 100644 (file)
@@ -117,7 +117,7 @@ struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct i
        const int reuseFlag = 1;
 
        /* Make a UDP socket */
-       netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+       netsocket = socket(ast_sockaddr_is_ipv6(bindaddr) ? AST_AF_INET6 : AST_AF_INET, SOCK_DGRAM, IPPROTO_IP);
 
        if (netsocket < 0) {
                ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
@@ -155,7 +155,7 @@ struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct i
        ns->ioc = ioc;
        ns->sockfd = netsocket;
        ns->data = data;
-       memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr));
+       ast_sockaddr_copy(&ns->bindaddr, bindaddr);
        ASTOBJ_CONTAINER_LINK(list, ns);
 
        return ns;
@@ -171,10 +171,6 @@ struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_co
        struct ast_sockaddr addr;
 
        if (ast_sockaddr_parse(&addr, bindinfo, 0)) {
-               if (!ast_sockaddr_is_ipv4(&addr)) {
-                       ast_log(LOG_WARNING, "Only IPv4 addresses are supported at this time.\n");
-                       return NULL;
-               }
 
                if (!ast_sockaddr_port(&addr)) {
                        ast_sockaddr_set_port(&addr, defaultport);
index aa5e17d..bee88c2 100644 (file)
@@ -297,6 +297,37 @@ cleanup:
        return res_cnt;
 }
 
+int ast_sockaddr_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
+               struct ast_sockaddr *result)
+{
+       int res = 0;
+
+       if (ast_sockaddr_is_ipv4(addr)) {
+               struct sockaddr_in result4 = { 0, };
+               struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr->ss;
+               struct sockaddr_in *mask4 = (struct sockaddr_in *) &netmask->ss;
+               result4.sin_family = AF_INET;
+               result4.sin_addr.s_addr = addr4->sin_addr.s_addr & mask4->sin_addr.s_addr;
+               ast_sockaddr_from_sin(result, &result4);
+       } else if (ast_sockaddr_is_ipv6(addr)) {
+               struct sockaddr_in6 result6 = { 0, };
+               struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr->ss;
+               struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *) &netmask->ss;
+               int i;
+               result6.sin6_family = AF_INET6;
+               for (i = 0; i < 4; ++i) {
+                       V6_WORD(&result6, i) = V6_WORD(addr6, i) & V6_WORD(mask6, i);
+               }
+               memcpy(&result->ss, &result6, sizeof(result6));
+               result->len = sizeof(result6);
+       } else {
+               /* Unsupported address scheme */
+               res = -1;
+       }
+
+       return res;
+}
+
 int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
 {
        const struct ast_sockaddr *a_tmp, *b_tmp;