Index: CHANGES
===================================================================
--- CHANGES	(revision 400553)
+++ CHANGES	(working copy)
@@ -770,7 +770,6 @@
    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 @@
    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: channels/chan_iax2.c
===================================================================
--- channels/chan_iax2.c	(revision 400553)
+++ channels/chan_iax2.c	(working copy)
@@ -110,7 +110,6 @@
 #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 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_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 @@
 	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 @@
 	/*! 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 @@
 	/*! 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 @@
  *  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 @@
 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 @@
 	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 @@
 	  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 @@
 #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_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_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 @@
 	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 @@
 	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 @@
 
 	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 @@
 	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 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 @@
 	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 @@
 			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_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 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 @@
 /*!
  * \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 @@
 	 */
 
 	/* ----- 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 @@
 	/* ----- 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 @@
 		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 @@
 {
 	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,15 +2427,10 @@
 {
 	/* 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;
+	struct peercnt tmp;
 
-	ast_sockaddr_to_sin(sockaddr, &sin);
+	ast_sockaddr_copy(&tmp.addr, sockaddr);
 
-	tmp.addr = sin.sin_addr.s_addr;
-
 	if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
 		peercnt->reg = reg;
 		if (limit) {
@@ -2450,7 +2438,7 @@
 		} 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,15 +2451,14 @@
  * 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
 	 * lock, both threads could alloc space for the same object and attempt
@@ -2484,7 +2471,7 @@
 	} 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 @@
 	/* 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,10 +2504,10 @@
  */
 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
 	 * list.  If left unlocked, peercnt_add could try and grab this
@@ -2529,7 +2516,7 @@
 	 */
 	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,13 +2542,13 @@
  * \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);
 		ao2_ref(peercnt, -1); /* decrement ref from find */
@@ -2673,7 +2660,7 @@
 {
 	struct ao2_iterator i;
 	struct peercnt *peercnt;
-	struct sockaddr_in sin;
+	struct ast_sockaddr addr;
 	int found = 0;
 
 	switch (cmd) {
@@ -2690,22 +2677,23 @@
 			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 @@
  * 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 @@
 /*
  * \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 @@
 				.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 @@
 			}
 			/* 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 @@
 		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 @@
 	}
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 	    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 @@
 			} 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 @@
 
 	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 @@
 		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 @@
  * \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 @@
 		 * 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 @@
 		} 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 @@
 
 	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 @@
 	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 @@
 		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 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 @@
 		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 @@
 	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 @@
 
 	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 @@
 		}
 	}
 
-	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 @@
 };
 
 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 @@
 	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 @@
  *         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 @@
 		};
 
 		/* 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 @@
 		}
 
 		/* 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 @@
 
 	/* ----- 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 @@
 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 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 @@
 	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 @@
 	/* 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 @@
 	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 @@
 
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 
 				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 @@
 #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 show_peers_context cont = {
+		.havepattern = 0,
+		.idtext = "",
+		.registeredonly = 0,
+
+		.peerlist = 0,
+
+		.total_peers = 0,
+		.online_peers = 0,
+		.offline_peers = 0,
+		.unmonitored_peers = 0,
+	};
+
 	struct ao2_iterator i;
 
-#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"
+	struct iax2_peer *peer = NULL;
 
-	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 @@
 	}
 
 
-	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 @@
 /*! \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");
 
-	astman_append(s, "Response: Success\r\n%sMessage: IAX Peer status list will follow\r\n\r\n", idtext);
+	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",
+		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 *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 @@
 	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 @@
 	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 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 @@
 			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,9 +7425,7 @@
 
 	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,14 +7436,10 @@
 			return CLI_FAILURE;
 		}
 
-		ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+		ast_sockaddr_copy(&debugaddr, &peer->addr);
 
-		debugaddr.sin_addr = peer_addr.sin_addr;
-		debugaddr.sin_port = peer_addr.sin_port;
+		ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s\n", ast_sockaddr_stringify_port(&debugaddr));
 
-		ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s:%d\n",
-			ast_inet_ntoa(debugaddr.sin_addr), ntohs(debugaddr.sin_port));
-
 		ao2_ref(peer, -1);
 	} else if (!strncasecmp(a->argv[3], "on", 2)) {
 		iaxdebug = 1;
@@ -7517,7 +7602,7 @@
 }
 
 
-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 @@
 	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 @@
 		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 @@
 	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 @@
 			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 @@
 	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 @@
 	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 @@
 		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 @@
 }
 
 /*! \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 @@
 	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 @@
 		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 @@
 			}
 		}
 		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 @@
 			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 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 @@
 			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 @@
  * \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 @@
 	/* 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 @@
 					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 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 @@
 	}
 	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 @@
 }
 
 /*! \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 @@
 	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 @@
 		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 @@
 	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 @@
 		} 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 @@
 	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 @@
 	/* 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 @@
  * \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,10 +8797,8 @@
 	uint16_t version;
 	const char *peer_name;
 	int res = -1;
-	struct ast_sockaddr sockaddr;
+	char *str_addr;
 
-	ast_sockaddr_from_sin(&sockaddr, sin);
-
 	peer_name = ast_strdupa(iaxs[callno]->peer);
 
 	/* SLD: Another find_peer call during registration - this time when we are really updating our registration */
@@ -8726,12 +8813,12 @@
 		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 @@
 		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 @@
 		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);
 
-		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) {
+		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(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 @@
 		}
 	}
 
-	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 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 @@
 	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 @@
 			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 @@
 	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 @@
 		} 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 @@
 
 	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 @@
 		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 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 @@
 		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 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 @@
 		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 @@
 		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 @@
 		} 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 @@
 	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 @@
 	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 @@
 	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 @@
 			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 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 @@
 	/* 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 @@
 	}
 	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 @@
 
 
 		/* 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 @@
 		/* 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 @@
 		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 @@
 
 		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 @@
 			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 @@
 				 (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 @@
 
 #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 @@
 	/* 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 @@
 
 		/* 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 @@
 				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 @@
 				/* 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 @@
 				/* 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 @@
 						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 @@
 									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 @@
 									}
 									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 @@
 												"%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 @@
 							} 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 @@
 				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 @@
 					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 @@
 					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 @@
 					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 @@
 					};
 					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 @@
 				}
 				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 @@
 					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 @@
 						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 @@
 								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 @@
 											"%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 @@
 						} 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 @@
 					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 @@
 						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 @@
 				/* 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 @@
 						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 @@
 				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 @@
 			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 @@
 				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 @@
 		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 @@
 		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 @@
 	}
 
 	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 @@
 	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 @@
 	}
 
 	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 @@
 		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(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 @@
 		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 @@
 	}
 	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 @@
 {
 	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 @@
 	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 @@
 			port = IAX_DEFAULT_PORTNO;
 	}
 
-	addr.ss.ss_family = AF_INET;
-
 	if (!ast_get_ip(&addr, host)) {
 		struct ast_netsock *sock;
 
@@ -12391,8 +12500,6 @@
 		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 @@
 			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 @@
 					/* 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 @@
 					/* 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 @@
 				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 @@
 			} 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 @@
 		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 @@
 	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 @@
 		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 @@
 			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,17 +13317,19 @@
 			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")) {
 			authdebug = ast_true(v->value);
@@ -13397,11 +13527,15 @@
 		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 @@
 					}
 					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 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 @@
 	}
 
 	/* 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 @@
 		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 @@
 	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 @@
 		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 @@
 
 		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: channels/iax2/include/parser.h
===================================================================
--- channels/iax2/include/parser.h	(revision 400553)
+++ channels/iax2/include/parser.h	(working copy)
@@ -47,7 +47,7 @@
 	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 @@
 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: channels/iax2/parser.c
===================================================================
--- channels/iax2/parser.c	(revision 400553)
+++ channels/iax2/parser.c	(working copy)
@@ -41,6 +41,7 @@
 #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 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_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 @@
 	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 @@
 		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 @@
 	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 @@
 			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: include/asterisk/netsock2.h
===================================================================
--- include/asterisk/netsock2.h	(revision 400553)
+++ include/asterisk/netsock2.h	(working copy)
@@ -51,6 +51,18 @@
 };
 
 /*!
+ * \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 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: main/acl.c
===================================================================
--- main/acl.c	(revision 400553)
+++ main/acl.c	(working copy)
@@ -349,63 +349,6 @@
 
 /*!
  * \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 @@
 	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 @@
 			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 @@
 
 		/* 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: main/netsock.c
===================================================================
--- main/netsock.c	(revision 400553)
+++ main/netsock.c	(working copy)
@@ -117,7 +117,7 @@
 	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 @@
 	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_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: main/netsock2.c
===================================================================
--- main/netsock2.c	(revision 400553)
+++ main/netsock2.c	(working copy)
@@ -297,6 +297,37 @@
 	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;
