Index: CHANGES
===================================================================
--- CHANGES	(revision 393737)
+++ CHANGES	(working copy)
@@ -460,6 +460,10 @@
    set of proxies by using a pre-loaded route-set defined by the Path headers in
    the REGISTER request. See Realtime updates for more configuration information.
 
+chan_iax2
+------------------
+ * IPv6 support has been added.  We are now able to bind to and
+   communicate using IPv6 addresses.
 
 Functions
 ------------------
Index: channels/chan_iax2.c
===================================================================
--- channels/chan_iax2.c	(revision 393737)
+++ channels/chan_iax2.c	(working copy)
@@ -99,7 +99,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/bridging.h"
@@ -524,12 +523,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_*) */
 
@@ -562,7 +561,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 */
@@ -613,7 +612,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;
 };
@@ -693,7 +692,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 */
@@ -809,7 +808,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 */
@@ -941,7 +940,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 */
@@ -995,8 +994,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);
@@ -1034,7 +1033,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;
@@ -1051,7 +1050,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;
@@ -1145,20 +1144,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;
 		}
 	}
@@ -1223,7 +1223,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);
@@ -1257,7 +1257,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_topic *topic, struct stasis_message *message);
 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message);
 
@@ -1842,9 +1842,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;
 }
 
@@ -1876,7 +1876,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;
@@ -1884,12 +1884,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_addr(&peer->addr, &addr)) {
 			ast_copy_string(host, peer->name, len);
 			peer_unref(peer);
 			res = 1;
@@ -1900,7 +1896,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);
@@ -2057,7 +2053,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;
@@ -2128,10 +2124,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_addr(&cur->addr, addr)) {
 		/* This is the main host */
 		if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
 			 (check_dcallno ? dcallno == cur->callno : 1) ) {
@@ -2139,8 +2134,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_addr(&cur->transfer, addr) && cur->transferring) {
 		/* We're transferring */
 		if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
 			return 1;
@@ -2263,9 +2257,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)
@@ -2279,26 +2271,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_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;
@@ -2309,7 +2303,7 @@
  *
  * \brief compares sin 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;
@@ -2326,7 +2320,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;
 	}
@@ -2334,11 +2328,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;
 	}
 
@@ -2349,7 +2343,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;
@@ -2372,18 +2366,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);
 	}
 
@@ -2423,15 +2416,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) {
@@ -2439,7 +2427,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 */
 	}
 }
@@ -2452,15 +2440,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
@@ -2473,7 +2460,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 */
@@ -2486,9 +2473,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;
 	}
 
@@ -2506,10 +2493,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
@@ -2518,7 +2505,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 */
@@ -2544,13 +2531,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 */
@@ -2662,8 +2649,9 @@
 {
 	struct ao2_iterator i;
 	struct peercnt *peercnt;
-	struct sockaddr_in sin;
+	struct ast_sockaddr addr;
 	int found = 0;
+	char *str_addr;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -2679,22 +2667,24 @@
 			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);
+			str_addr = ast_strdupa(ast_sockaddr_stringify(&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], str_addr)) {
+					ast_cli(a->fd, "%-45s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
+					ast_cli(a->fd, "%-45s %-12d %-12d\n", str_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", str_addr, peercnt->cur, peercnt->limit);
 			}
 			ao2_ref(peercnt, -1);
 		}
@@ -2875,17 +2865,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);
@@ -2929,7 +2919,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;
@@ -2949,7 +2939,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) {
@@ -2962,7 +2952,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]);
@@ -2978,7 +2968,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]);
@@ -2993,6 +2983,11 @@
 	}
 	if (!res && (new >= NEW_ALLOW)) {
 		callno_entry entry;
+		char *str_addr, *str_port;
+
+		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+		str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
+
 		/* 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,
@@ -2999,10 +2994,10 @@
 		 * 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:%s", str_addr, str_port);
 
-		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;
@@ -3011,7 +3006,7 @@
 		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;
 		}
@@ -3018,15 +3013,13 @@
 		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;
@@ -3056,13 +3049,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);
 }
 
 /*!
@@ -3211,11 +3204,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();
@@ -3234,15 +3227,20 @@
 	    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) {
+		char *str_addr, *str_port;
 
+		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&iaxs[callno]->addr));
+		str_port = ast_strdupa(ast_sockaddr_stringify_port(&iaxs[callno]->addr));
+
+		ast_debug(3, "Sending %d on %d/%d to %s:%s\n", f->ts, callno, iaxs[callno]->peercallno, str_addr, str_port);
+	}
 	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)
@@ -3392,7 +3390,7 @@
 						iax2_destroy(callno);
 					} 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_channel_name(iaxs[f->callno]->owner), f->af.frametype, f->af.subclass.integer, f->ts, f->oseqno);
+							ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %u, ts=%d, seqno=%d)\n", ast_sockaddr_stringify_addr(&iaxs[f->callno]->addr), ast_channel_name(iaxs[f->callno]->owner), f->af.frametype, f->af.subclass.integer, f->ts, f->oseqno);
 						iaxs[callno]->error = ETIMEDOUT;
 						if (iaxs[callno]->owner) {
 							struct ast_frame fr = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = AST_CAUSE_DESTINATION_OUT_OF_ORDER };
@@ -3659,9 +3657,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");
@@ -3679,8 +3681,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);
@@ -4222,7 +4224,7 @@
  * \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;
@@ -4229,15 +4231,18 @@
 	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) {
@@ -4254,12 +4259,12 @@
 		 * 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)) {
+					if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &addr, hp->h_length)) {
 						/* No match */
 						ast_variables_destroy(var);
 						var = NULL;
@@ -4291,11 +4296,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;
@@ -4304,9 +4317,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)) {
@@ -4344,21 +4354,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);
@@ -4373,7 +4385,7 @@
 				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)) {
+					if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &addr, hp->h_length)) {
 						/* No match */
 						ast_variables_destroy(var);
 						var = NULL;
@@ -4417,10 +4429,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;
@@ -4428,9 +4440,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 */
 }
 
@@ -4455,31 +4468,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));
@@ -4497,10 +4509,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;
 	}
 
@@ -4551,12 +4561,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;
@@ -4616,7 +4624,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 {
@@ -4638,9 +4646,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)
@@ -4776,15 +4784,19 @@
  *         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%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);
 	char hash[41]; /* 40 char sha1 hash */
 	int subclass = uncompress_subclass(fh->csub);
+	char *str_addr, *str_port;
 
+	str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+	str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
+
 	/* ----- Case 1 ----- */
 	if (ies->calltoken && !ies->calltokendata) {  /* empty calltoken is provided, client supports calltokens */
 		struct iax_ie_data ied = {
@@ -4793,12 +4805,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, str_addr, str_port, (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;
 
@@ -4823,15 +4835,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, str_addr, str_port, (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", str_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", str_addr);
 			goto reject; /* too much delay, reject */
 		}
 
@@ -4842,8 +4854,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", str_addr, S_OR(ies->username, "guest"));
 			goto reject;
 		}
 		return 0; /* calltoken is not required for this addr, so permit it. */
@@ -4852,9 +4864,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;
@@ -4920,7 +4932,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";
@@ -4955,7 +4967,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;
 	}
@@ -4980,8 +4992,11 @@
 	/* 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;
+		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;
@@ -5611,7 +5626,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;
@@ -5619,12 +5634,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_addr(&peer->addr, &addr)) {
 			res = ast_test_flag64(peer, IAX_TRUNK);
 			peer_unref(peer);
 			break;
@@ -5993,7 +6004,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;
 	
@@ -6001,7 +6012,7 @@
 	AST_LIST_LOCK(&tpeers);
 
 	AST_LIST_TRAVERSE(&tpeers, tpeer, list) {
-		if (!inaddrcmp(&tpeer->addr, sin)) {
+		if (!ast_sockaddr_cmp_addr(&tpeer->addr, addr)) {
 			ast_mutex_lock(&tpeer->lock);
 			break;
 		}
@@ -6009,16 +6020,20 @@
 
 	if (!tpeer) {
 		if ((tpeer = ast_calloc(1, sizeof(*tpeer)))) {
+			char *str_taddr, *str_tport;
 			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;
+
+			str_taddr = ast_strdupa(ast_sockaddr_stringify_addr(&tpeer->addr));
+			str_tport = ast_strdupa(ast_sockaddr_stringify_port(&tpeer->addr));
 #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:%s'\n", str_taddr, str_tport);
 			AST_LIST_INSERT_TAIL(&tpeers, tpeer, list);
 		}
 	}
@@ -6036,10 +6051,15 @@
 	struct timeval now;
 	struct ast_iax2_meta_trunk_entry *met;
 	struct ast_iax2_meta_trunk_mini *mtm;
+	char *str_taddr, *str_tport;
 
 	f = &fr->af;
 	tpeer = find_tpeer(&pvt->addr, pvt->sockfd);
 	if (tpeer) {
+
+		str_taddr = ast_strdupa(ast_sockaddr_stringify_addr(&tpeer->addr));
+		str_tport = ast_strdupa(ast_sockaddr_stringify_port(&tpeer->addr));
+
 		if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) {
 			/* Need to reallocate space */
 			if (tpeer->trunkdataalloc < trunkmaxsize) {
@@ -6050,9 +6070,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:%s' to %d bytes\n", str_taddr, str_tport, 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:%s\n", str_taddr, str_tport);
 				ast_mutex_unlock(&tpeer->lock);
 				return -1;
 			}
@@ -6583,8 +6603,8 @@
 	int 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"
+#define FORMAT2 "%-15.15s  %-40.40s %s  %-15.15s  %-8s  %s %-11s %-32.32s\n"
+#define FORMAT "%-15.15s  %-40.40s %s  %-15.15s  %-5d%s  %s %-11s %-32.32s\n"
 
 	struct iax2_peer *peer = NULL;
 	char name[256];
@@ -6630,14 +6650,11 @@
 
 	i = ao2_iterator_init(peers, 0);
 	for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
-		char nm[20];
+		char *nm;
 		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 (registeredonly && ast_sockaddr_isnull(&peer->addr)) {
 			continue;
 		}
 		if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0)) {
@@ -6644,21 +6661,23 @@
 			continue;
 		}
 
-		if (!ast_strlen_zero(peer->username))
+		if (!ast_strlen_zero(peer->username)) {
 			snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
-		else
+		} 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)
+		if (retstatus > 0) {
 			online_peers++;
-		else if (!retstatus)
+		} else if (!retstatus) {
 			offline_peers++;
-		else
+		} else {
 			unmonitored_peers++;
+		}
 
-		ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
+		nm = ast_strdupa(ast_sockaddr_stringify_addr(&peer->mask));
 
 		if (s) {
 			astman_append(s,
@@ -6697,15 +6716,18 @@
 	}
 	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);
+	}
 
-	if (havepattern)
+	if (havepattern) {
 		regfree(&regexbuf);
+	}
 
-	if (total)
+	if (total) {
 		*total = total_peers;
+	}
 
 	return RESULT_SUCCESS;
 #undef FORMAT
@@ -6947,7 +6969,6 @@
 {
 	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] = "";
@@ -6971,8 +6992,7 @@
 		}
 		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, "Mask: %s\r\n", ast_sockaddr_stringify_addr(&peer->mask));
 		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");
@@ -7012,12 +7032,16 @@
 
 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"
+#define IPV4FORMAT "%s:%s"
+#define IPV6FORMAT "[%s]:%s"
+
 	struct iax2_registry *reg = NULL;
 	char host[80];
 	char perceived[80];
 	int counter = 0;
+	char *str_addr, *str_port;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -7035,10 +7059,15 @@
 	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
+		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&reg->addr));
+		str_port = ast_strdupa(ast_sockaddr_stringify_port(&reg->addr));
+		if (str_addr) {
+			snprintf(perceived, sizeof(perceived),
+					(ast_sockaddr_is_ipv4(&reg->addr) || ast_sockaddr_is_ipv4_mapped(&reg->addr)) ? 
+					 	IPV4FORMAT : IPV6FORMAT, str_addr, str_port);
+		} else {
 			ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
+		}
 		ast_cli(a->fd, FORMAT, host, 
 					(reg->dnsmgr) ? "Y" : "N", 
 					reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
@@ -7049,6 +7078,8 @@
 	return CLI_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
+#undef IPV4FORMAT
+#undef IPV6FORMAT
 }
 
 static int manager_iax2_show_registry(struct mansession *s, const struct message *m)
@@ -7059,6 +7090,7 @@
 	char host[80] = "";
 	char perceived[80] = "";
 	int total = 0;
+	char *str_addr, *str_port;
 
 	if (!ast_strlen_zero(id))
 		snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
@@ -7068,9 +7100,10 @@
 	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));
+		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&reg->addr));
+		str_port = ast_strdupa(ast_sockaddr_stringify_port(&reg->addr));
+		if (str_addr) {
+			snprintf(perceived, sizeof(perceived), "%s:%s", str_addr, str_port);
 		} else {
 			ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
 		}
@@ -7103,13 +7136,14 @@
 
 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, };
 	char last_message[10] = { 0, };
+	char *str_addr;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -7142,9 +7176,10 @@
 			iax_frame_subclass2str(iaxs[x]->first_iax_message & ~MARK_IAX_SUBCLASS_TX, first_message, sizeof(first_message));
 			iax_frame_subclass2str(iaxs[x]->last_iax_message & ~MARK_IAX_SUBCLASS_TX, last_message, sizeof(last_message));
 			lag = iaxs[x]->remote_rr.delay;
+			str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&iaxs[x]->addr));
 			ast_cli(a->fd, FORMAT,
 				iaxs[x]->owner ? ast_channel_name(iaxs[x]->owner) : "(None)",
-				ast_inet_ntoa(iaxs[x]->addr.sin_addr),
+				str_addr,
 				S_OR(iaxs[x]->username, "(None)"),
 				iaxs[x]->callno, iaxs[x]->peercallno,
 				iaxs[x]->oseqno, iaxs[x]->iseqno,
@@ -7294,9 +7329,8 @@
 
 	if (!strcasecmp(a->argv[3], "peer")) {
 		struct iax2_peer *peer;
-		struct sockaddr_in peer_addr;
+		char *str_addr, *str_port;
 
-
 		if (a->argc != e->args + 1)
 			return CLI_SHOWUSAGE;
 
@@ -7307,13 +7341,12 @@
 			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;
+		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&debugaddr));
+		str_port = ast_strdupa(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));
+		ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s:%s\n", str_addr, str_port);
 
 		ao2_ref(peer, -1);
 	} else if (!strncasecmp(a->argv[3], "on", 2)) {
@@ -7477,7 +7510,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;
@@ -7487,7 +7520,6 @@
 	int gotcapability = 0;
 	struct ast_variable *v = NULL, *tmpvar = NULL;
 	struct ao2_iterator i;
-	struct ast_sockaddr addr;
 
 	if (!iaxs[callno])
 		return res;
@@ -7540,16 +7572,15 @@
 		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)) {
@@ -7606,8 +7637,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);
@@ -7701,13 +7732,14 @@
 			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;
+	char *str_addr, *str_port;
 	fh.scallno = htons(src | IAX_FLAG_FULL);
 	fh.dcallno = htons(dst);
 	fh.ts = 0;
@@ -7715,10 +7747,13 @@
 	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);
+
+	str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+	str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
+
+	ast_debug(1, "Raw Hangup %s:%s, src=%d, dst=%d\n", str_addr, str_port, src, dst);
+	return ast_sendto(sockfd, &fh, sizeof(fh), 0, addr);
 }
 
 static void merge_encryption(struct chan_iax2_pvt *p, unsigned int enc)
@@ -7806,6 +7841,7 @@
 	if (p->authrej) {
 		return res;
 	}
+
 	user = ao2_find(users, p->username, OBJ_KEY);
 	if (user) {
 		if (ast_test_flag64(p, IAX_MAXAUTHREQ)) {
@@ -7852,7 +7888,6 @@
 		struct MD5Context md5;
 		unsigned char digest[16];
 		char *tmppw, *stringp;
-
 		tmppw = ast_strdupa(p->secret);
 		stringp = tmppw;
 		while((tmppw = strsep(&stringp, ";"))) {
@@ -7876,7 +7911,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] = "";
@@ -7889,7 +7924,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 */
@@ -7905,7 +7939,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;
 	}
 
@@ -7934,20 +7968,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);
@@ -8004,7 +8037,7 @@
 			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)) {
@@ -8011,7 +8044,7 @@
 		/* 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);
@@ -8040,7 +8073,7 @@
 	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;
@@ -8047,9 +8080,9 @@
 	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));
+				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;
@@ -8089,7 +8122,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;
 }
@@ -8098,7 +8131,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 */
@@ -8123,22 +8156,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_apply_netmask(addr, &peer->mask, &tmp_sockaddr1);
+			ast_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 */
 			    && (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;
@@ -8158,7 +8196,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) {
@@ -8237,23 +8275,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 */
@@ -8262,8 +8299,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;
 }
@@ -8377,7 +8415,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 */
@@ -8385,14 +8423,15 @@
 	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;
+	char *str_addr;
 
-	memset(&us, 0, sizeof(us));
-	if (ies->apparent_addr) {
-		memmove(&us, ies->apparent_addr, sizeof(us));
+	str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+
+	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));
@@ -8408,14 +8447,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_addr(&reg->addr, addr)) {
+		ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", str_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 */
 	}
@@ -8425,7 +8463,9 @@
 	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_addr(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
+		char *str_usaddr, *str_usport;
+
 		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) {
@@ -8435,9 +8475,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);
-		manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nDomain: %s\r\nStatus: Registered\r\n", ast_inet_ntoa(sin->sin_addr));
+		str_usaddr = ast_strdupa(ast_sockaddr_stringify_addr(&reg->us));
+		str_usport = ast_strdupa(ast_sockaddr_stringify_port(&reg->us));
+		snprintf(ourip, sizeof(ourip), "%s:%s", str_usaddr, str_usport);
+		ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", str_addr, ourip, msgstatus);
+		manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nDomain: %s\r\nStatus: Registered\r\n", str_addr);
 	}
 	reg->regstate = REG_STATE_REGISTERED;
 	return 0;
@@ -8451,7 +8493,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;
@@ -8479,7 +8521,7 @@
 	char *username, *hostname, *secret;
 	char *porta;
 	char *stringp=NULL;
-	
+	/* register => user[:secret][:[rsakey]]@host[:port] */
 	if (!value)
 		return -1;
 
@@ -8653,8 +8695,11 @@
  * \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)
 {
+#define IPV4FORMAT "%s:%s:%d"
+#define IPV6FORMAT "[%s]:%s:%d"
+
 	/* Called from IAX thread only, with proper iaxsl lock */
 	struct iax_ie_data ied = {
 		.pos = 0,
@@ -8665,10 +8710,8 @@
 	uint16_t version;
 	const char *peer_name;
 	int res = -1;
-	struct ast_sockaddr sockaddr;
+	char *str_addr, *str_port;
 
-	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 */
@@ -8683,16 +8726,16 @@
 		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);
 		}
 	}
 
-	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) {
@@ -8703,18 +8746,23 @@
 		peercnt_modify(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));
+		str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
+
+		snprintf(data, sizeof(data), (ast_sockaddr_is_ipv4(addr) || ast_sockaddr_is_ipv4_mapped(addr)) ? IPV4FORMAT : IPV6FORMAT,
+				str_addr, str_port, p->expiry);
+
+		if (!ast_test_flag64(p, IAX_TEMPONLY) && 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:%s\n", p->name,
+					    ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", str_addr, str_port);
 			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", str_port);
 			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)) {
@@ -8769,7 +8817,7 @@
 	} else {
 		p->expiry = refresh;
 	}
-	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);
@@ -8776,10 +8824,10 @@
 	}
 	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);
@@ -8827,6 +8875,9 @@
 
 	res = 0;
 
+#undef IPV4FORMAT
+#undef IPV6FORMAT
+
 return_unref:
 	peer_unref(p);
 
@@ -8881,7 +8932,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 */
@@ -8899,12 +8950,12 @@
 	memset(&ied, 0, sizeof(ied));
 	reg = iaxs[callno]->reg;
 	if (reg) {
-		struct sockaddr_in reg_addr;
+		char *str_addr;
 
-		ast_sockaddr_to_sin(&reg->addr, &reg_addr);
+		str_addr = ast_strdupa(ast_sockaddr_stringify_addr(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_addr(&reg->addr, addr)) {
+			ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", str_addr);
 			return -1;
 		}
 		if (ast_strlen_zero(reg->secret)) {
@@ -8918,9 +8969,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 */
@@ -9121,9 +9172,12 @@
 	int res, processed = 0, totalcalls = 0;
 	struct iax2_trunk_peer *tpeer = NULL, *drop = NULL;
 	struct timeval now = ast_tvnow();
+	char *str_addr, *str_daddr;
+	char *str_port, *str_dport;
 
-	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) {
@@ -9148,8 +9202,11 @@
 		} 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) {
+				str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&tpeer->addr));
+				str_port = ast_strdupa(ast_sockaddr_stringify_port(&tpeer->addr));
+				ast_verbose(" - Trunk peer (%s:%s) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n", str_addr, str_port, res, (res != 1) ? "s" : "", tpeer->trunkdatalen, tpeer->trunkdataalloc);
+			}
 		}
 		totalcalls += res;
 		res = 0;
@@ -9160,9 +9217,11 @@
 
 	if (drop) {
 		ast_mutex_lock(&drop->lock);
+		str_daddr = ast_strdupa(ast_sockaddr_stringify_addr(&drop->addr));
+		str_dport = ast_strdupa(ast_sockaddr_stringify_port(&drop->addr));
 		/* 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));
+		ast_debug(1, "Dropping unused iax2 trunk peer '%s:%s'\n", str_daddr, str_dport);
 		if (drop->trunkdata) {
 			ast_free(drop->trunkdata);
 			drop->trunkdata = NULL;
@@ -9172,8 +9231,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;
@@ -9247,7 +9307,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];
@@ -9256,7 +9316,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;
 }
 
@@ -9424,7 +9484,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;
@@ -9438,9 +9497,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) {
@@ -9468,7 +9526,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) {
@@ -9482,7 +9540,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);
@@ -9500,7 +9558,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;
@@ -9512,10 +9570,14 @@
 	void *ptr;
 	struct timeval rxtrunktime;
 	struct ast_frame f = { 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 (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:%s' that is flagged as a meta frame but is too short\n", 
+			str_addr, str_port);
 		return 1;
 	}
 
@@ -9532,10 +9594,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:%s': No matching peer\n", 
+			str_addr, str_port);
 		return 1;
 	}
 	tpeer->trunkact = ast_tvnow();
@@ -9562,13 +9624,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:%s': dropping\n", str_addr, str_port);
 			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;
 
@@ -9722,7 +9784,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;
@@ -9750,6 +9812,7 @@
 	char caller_pref_buf[128];
 	struct ast_codec_pref pref;
 	char *using_prefs = "mine";
+	char *str_addr, *str_port;
 
 	/* allocate an iax_frame with 4096 bytes of data buffer */
 	fr = ast_alloca(sizeof(*fr) + 4096);
@@ -9759,8 +9822,11 @@
 	/* 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);
 
+	str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&addr));
+	str_port = ast_strdupa(ast_sockaddr_stringify_port(&addr));
+
 	if (res < sizeof(*mh)) {
 		ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int) sizeof(*mh));
 		return 1;
@@ -9767,23 +9833,23 @@
 	}
 	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:%s' that is flagged as a video frame but is too short\n", str_addr, str_port);
 			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:%s' that is flagged as a full frame but is too short\n", str_addr, str_port);
 			return 1;
 		}
 
@@ -9795,7 +9861,7 @@
  		 * 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)) {
@@ -9824,7 +9890,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 */
@@ -9835,7 +9901,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", str_addr);
 					ast_variables_destroy(ies.vars);
 					return 1;
 				}
@@ -9855,7 +9921,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;
 			}
@@ -9892,11 +9958,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;
@@ -9923,7 +9989,7 @@
 				 (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) 
@@ -9943,7 +10009,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
 
@@ -9994,7 +10060,7 @@
 	/* count this frame */
 	iaxs[fr->callno]->frames_received++;
 
-	if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
+	if (!ast_sockaddr_cmp_addr(&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;
@@ -10091,7 +10157,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(&addr, &iaxs[fr->callno]->addr) &&
 		    ((f.subclass.integer != IAX_COMMAND_INVAL) ||
 		     (f.frametype != AST_FRAME_IAX))) {
 			unsigned char x;
@@ -10139,7 +10205,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(&addr, &iaxs[fr->callno]->addr) &&
 			((f.frametype != AST_FRAME_IAX) ||
 			 ((f.subclass.integer != IAX_COMMAND_TXACC) &&
 			  (f.subclass.integer != IAX_COMMAND_TXCNT)))) {
@@ -10367,9 +10433,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;
@@ -10384,11 +10450,11 @@
 				/* 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);
+						ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", str_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)) {
@@ -10425,7 +10491,7 @@
 							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);
+							ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", str_addr, iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
 					} else {
 						/* Select an appropriate format */
 
@@ -10475,12 +10541,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),
+											str_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),
+											str_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));
@@ -10527,7 +10593,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),
+											str_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));
@@ -10551,7 +10617,7 @@
 												"%sactual format = %s,\n"
 												"%shost prefs = %s,\n"
 												"%spriority = %s\n",
-												ast_inet_ntoa(sin.sin_addr), 
+												str_addr, 
 												VERBOSE_PREFIX_4,
 												iax2_getformatname(iaxs[fr->callno]->peerformat), 
 												VERBOSE_PREFIX_4,
@@ -10571,7 +10637,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", str_addr);
 							}
 						}
 					}
@@ -10624,7 +10690,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),
+							str_addr,
 							ies.cause ? ies.cause : "<Unknown>");
 					ast_debug(1, "Immediately destroying %d, having received reject\n",
 						fr->callno);
@@ -10682,7 +10748,7 @@
 					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", str_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");
@@ -10694,7 +10760,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),
+							str_addr,
 							iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
 							iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
 					}
@@ -10816,7 +10882,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);
+							str_addr, iaxs[fr->callno]->lag);
 				}
 				break;
 			case IAX_COMMAND_AUTHREQ:
@@ -10830,7 +10896,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>", str_addr);
 					iax2_queue_frame(fr->callno, &hangup_fr);
 				}
 				break;
@@ -10845,7 +10911,7 @@
 				}
 				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", str_addr, iaxs[fr->callno]->username);
 					memset(&ied0, 0, sizeof(ied0));
 					auth_fail(fr->callno, IAX_COMMAND_REJECT);
 					break;
@@ -10857,7 +10923,7 @@
 					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", str_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);
@@ -10906,12 +10972,12 @@
 						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", str_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),
+										str_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));
@@ -10960,12 +11026,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),
+											str_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),
+											str_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));
@@ -10995,7 +11061,7 @@
 											"%sactual format = %s,\n"
 											"%shost prefs = %s,\n"
 											"%spriority = %s\n", 
-											ast_inet_ntoa(sin.sin_addr), 
+											str_addr, 
 											VERBOSE_PREFIX_4,
 											iax2_getformatname(iaxs[fr->callno]->peerformat),
 											VERBOSE_PREFIX_4,
@@ -11048,7 +11114,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", str_addr);
 							if (ast_test_flag64(iaxs[fr->callno], IAX_IMMEDIATE)) {
 								goto immediatedial;
 							}
@@ -11063,7 +11129,7 @@
 					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", str_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);
@@ -11075,7 +11141,7 @@
 						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),
+							str_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);
@@ -11135,7 +11201,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;
 					}
@@ -11150,18 +11216,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;
+						memset(&addr, 0, sizeof(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;
@@ -11169,7 +11234,7 @@
 				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);
@@ -11178,7 +11243,7 @@
 			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>", str_addr);
 						manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nUsername: %s\r\nStatus: Rejected\r\nCause: %s\r\n", iaxs[fr->callno]->reg->username, ies.cause ? ies.cause : "<unknown>");
 					}
 					iaxs[fr->callno]->reg->regstate = REG_STATE_REJECTED;
@@ -11189,7 +11254,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);
@@ -11700,7 +11765,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);
 	}
@@ -11716,7 +11781,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 */
@@ -11726,13 +11791,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;
@@ -11754,7 +11816,7 @@
 	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 */
@@ -11761,7 +11823,7 @@
 	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;
 
@@ -11775,9 +11837,9 @@
 	}
 
 	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 */
@@ -11784,7 +11846,7 @@
 	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;
 
@@ -11824,13 +11886,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_addr(&iaxs[callno]->addr),
 		sdata, res);
 	return res;
 }
@@ -11927,9 +11989,10 @@
 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_is_ipv4(&peer->addr) && 
+				!ast_sockaddr_is_ipv4_mapped(&peer->addr) &&
+				!ast_sockaddr_is_ipv6(&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;
@@ -11939,8 +12002,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");
@@ -11950,7 +12011,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) {
@@ -12008,7 +12069,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;
@@ -12031,15 +12092,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;
@@ -12234,8 +12298,6 @@
 			port = IAX_DEFAULT_PORTNO;
 	}
 
-	addr.ss.ss_family = AF_INET;
-
 	if (!ast_get_ip(&addr, host)) {
 		struct ast_netsock *sock;
 
@@ -12338,8 +12400,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))) {
@@ -12352,9 +12412,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;
 			}
@@ -12433,11 +12494,10 @@
 				if (!strcasecmp(v->value, "dynamic")) {
 					/* 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));
+					if (!found && !firstpass) {
+						int peer_port = ast_sockaddr_port(&peer->addr);
+						if (peer_port) {
+							ast_sockaddr_set_port(&peer->defaddr, peer_port);
 						}
 						ast_sockaddr_setnull(&peer->addr);
 					}
@@ -12445,23 +12505,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") ||
@@ -12470,7 +12529,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")) {
@@ -12478,10 +12537,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);
@@ -12578,8 +12641,17 @@
 		ast_clear_flag64(peer, IAX_DELME);
 	}
 
-	if (oldacl)
+	if (!maskfound) {
+		if (ast_sockaddr_is_ipv6(&peer->addr)) {
+			ast_sockaddr_parse(&peer->mask, "::/128", 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;
@@ -12991,6 +13063,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
@@ -13032,6 +13105,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));
 
@@ -13072,10 +13147,13 @@
 	}
 	while(v) {
 		if (!strcasecmp(v->name, "bindport")){ 
-			if (reload)
+			if (reload) {
 				ast_log(LOG_NOTICE, "Ignoring bindport on reload\n");
-			else
-				portno = atoi(v->value);
+			}
+			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")) {
@@ -13136,17 +13214,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_addr(&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);
@@ -13344,11 +13424,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);
 		}
@@ -13393,8 +13477,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);
 					}
@@ -13526,7 +13611,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;
@@ -13559,13 +13644,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;
@@ -13863,7 +13948,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;
 	}
 
@@ -13944,7 +14029,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")) {
@@ -13965,6 +14050,7 @@
 	char *tmp = ast_strdupa(data);
 	struct iax2_peer *p;
 	int res = AST_DEVICE_INVALID;
+	char *str_paddr, *str_daddr;
 
 	memset(&pds, 0, sizeof(pds));
 	parse_dial_string(tmp, &pds);
@@ -13981,10 +14067,12 @@
 		return res;
 
 	res = AST_DEVICE_UNAVAILABLE;
-	ast_debug(3, "iax2_devicestate: 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);
+	str_paddr = ast_strdupa(ast_sockaddr_stringify_addr(&p->addr));
+	str_daddr = ast_strdupa(ast_sockaddr_stringify_addr(&p->defaddr));
+	ast_debug(3, "iax2_devicestate: Found peer. What's device state of %s? addr=%s, defaddr=%s maxms=%d, lastms=%d\n",
+		pds.peer, str_paddr, str_daddr, p->maxms, p->lastms);
 
-	if ((ast_sockaddr_ipv4(&p->addr) || p->defaddr.sin_addr.s_addr) &&
+	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 */
@@ -14426,7 +14514,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/iax2.h
===================================================================
--- channels/iax2/include/iax2.h	(revision 393737)
+++ channels/iax2/include/iax2.h	(working copy)
@@ -23,6 +23,8 @@
 #ifndef _IAX2_H
 #define _IAX2_H
 
+#include "asterisk/netsock2.h"
+
 /* Max version of IAX protocol we support */
 #define IAX_PROTO_VERSION 2
 
@@ -145,7 +147,7 @@
 #define IAX_IE_CHALLENGE			15		/*!< Challenge data for MD5/RSA - string */
 #define IAX_IE_MD5_RESULT			16		/*!< MD5 challenge result - string */
 #define IAX_IE_RSA_RESULT			17		/*!< RSA challenge result - string */
-#define IAX_IE_APPARENT_ADDR		18		/*!< Apparent address of peer - struct sockaddr_in */
+#define IAX_IE_APPARENT_ADDR			18		/*!< Apparent address of peer - struct ast_sockaddr */
 #define IAX_IE_REFRESH				19		/*!< When to refresh registration - short */
 #define IAX_IE_DPSTATUS				20		/*!< Dialplan status - short */
 #define IAX_IE_CALLNO				21		/*!< Call number of peer - short */
Index: channels/iax2/include/parser.h
===================================================================
--- channels/iax2/include/parser.h	(revision 393737)
+++ 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 393737)
+++ 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,10 +84,18 @@
 
 static void dump_addr(char *output, int maxlen, void *value, int len)
 {
-	struct sockaddr_in sin;
-	if (len == (int)sizeof(sin)) {
+	char straddr[64];
+
+	if (len == (int)sizeof(struct sockaddr_in)) {
+		struct sockaddr_in sin;
 		memcpy(&sin, value, len);
-		snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+		inet_ntop(AF_INET, &sin.sin_addr, straddr, sizeof(straddr));
+		snprintf(output, maxlen, "IPV4 %s:%d", straddr, ntohs(sin.sin_port));
+	} else if (len == (int) sizeof(struct sockaddr_in6)) {
+		struct sockaddr_in6 sin6;
+		memcpy(&sin6, value, len);
+		inet_ntop(AF_INET6, &sin6.sin6_addr, straddr, sizeof(straddr));
+		snprintf(output, maxlen, "IPV6 [%s]:%d", straddr, ntohs(sin6.sin6_port));
 	} else {
 		ast_copy_string(output, "Invalid Address", maxlen);
 	}
@@ -172,12 +181,22 @@
 
 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
+	char straddr[64];
+	socklen_t sa_len = len;
+
+	if (len == (int)sizeof(struct sockaddr_in)) {
+		struct sockaddr_in sin;
+		memcpy(&sin.sin_addr, value, sa_len);
+		inet_ntop(AF_INET, &sin.sin_addr, straddr, sizeof(straddr));
+		snprintf(output, maxlen, "%s", straddr);
+	} else if (len == (int)sizeof(struct sockaddr_in6)) {
+		struct sockaddr_in6 sin6;
+		memcpy(&sin6.sin6_addr, value, sa_len);
+		inet_ntop(AF_INET6, &sin6.sin6_addr, straddr, sizeof(straddr));
+		snprintf(output, maxlen, "%s", straddr);
+	} else {
 		ast_copy_string(output, "Invalid IPADDR", maxlen);
+	}
 }
 
 
@@ -562,8 +581,10 @@
 	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)
 {
+#define IPV4FORMAT "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [%s:%s]\n"
+#define IPV6FORMAT "   Timestamp: %05lums  SCall: %5.5d  DCall: %5.5d [[%s]:%s]\n"
 	const char *framelist[] = {
 		"(0?)",
 		"DTMF_E ",
@@ -613,6 +634,7 @@
 	const char *subclass;
 	char *dir;
 	char tmp[512];
+	char *tmp_addr, *tmp_port;
 
 	switch(rx) {
 	case 0:
@@ -665,6 +687,10 @@
 		snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
 		subclass = subclass2;
 	}
+
+	tmp_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+	tmp_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
+
 	snprintf(tmp, sizeof(tmp), 
 		 "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
 		 dir,
@@ -671,13 +697,17 @@
 		 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),
+		(ast_sockaddr_is_ipv4(addr) || ast_sockaddr_is_ipv4_mapped(addr)) ? IPV4FORMAT : IPV6FORMAT,
+		(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));
+		 tmp_addr, tmp_port);
+
 	outputf(tmp);
 	if (fh->type == AST_FRAME_IAX)
 		dump_ies(fh->iedata, datalen);
+
+#undef IPV4FORMAT
+#undef IPV6FORMAT
 }
 
 int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
@@ -695,9 +725,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)
@@ -892,7 +922,31 @@
 			ies->rsa_result = (char *)data + 2;
 			break;
 		case IAX_IE_APPARENT_ADDR:
-			ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
+			{
+				char straddr[64];
+				int portno = 0;
+
+				if (len == (int)sizeof(struct sockaddr_in)) {
+					struct sockaddr_in *sin;
+					sin = ((struct sockaddr_in *)(data + 2));
+					inet_ntop(AF_INET, &sin->sin_addr, straddr, sizeof(straddr));
+					portno = ntohs(sin->sin_port);
+				} else if (len == (int)sizeof(struct sockaddr_in6)) {
+					struct sockaddr_in6 *sin6;
+					sin6 = ((struct sockaddr_in6 *)(data + 2));
+					inet_ntop(AF_INET6, &sin6->sin6_addr, straddr, sizeof(straddr));
+					portno = ntohs(sin6->sin6_port);
+				} else {
+					snprintf(tmp, (int)sizeof(tmp), "Expecting apparent address to be %d or %d bytes long but was %d\n",
+						(int)sizeof(struct sockaddr_in), (int)sizeof(struct sockaddr_in6), len);
+					errorf(tmp);
+					break;
+				}
+
+				ast_sockaddr_parse(&ies->apparent_addr, straddr, 0);
+				ast_sockaddr_set_port(&ies->apparent_addr, portno);
+
+			}
 			break;
 		case IAX_IE_REFRESH:
 			if (len != (int)sizeof(unsigned short)) {
Index: contrib/realtime/mysql/iaxfriends.sql
===================================================================
--- contrib/realtime/mysql/iaxfriends.sql	(revision 393737)
+++ contrib/realtime/mysql/iaxfriends.sql	(working copy)
@@ -14,8 +14,8 @@
   `host` varchar(40) NULL default 'dynamic',
   `ipaddr` varchar(40) NULL, -- Must be updateable by Asterisk user
   `port` int(5) NULL, -- Must be updateable by Asterisk user
-  `defaultip` varchar(20) NULL,
-  `sourceaddress` varchar(20) NULL,
+  `defaultip` varchar(45) NULL,
+  `sourceaddress` varchar(45) NULL,
   `mask` varchar(20) NULL,
   `regexten` varchar(40) NULL,
   `regseconds` int(11) NULL, -- Must be updateable by Asterisk user
Index: include/asterisk/acl.h
===================================================================
--- include/asterisk/acl.h	(revision 393737)
+++ include/asterisk/acl.h	(working copy)
@@ -181,6 +181,23 @@
 enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockaddr *addr);
 
 /*!
+ * \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_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
+		struct ast_sockaddr *result);
+
+/*!
  * \brief Apply a set of rules to a given IP address
  *
  * \details
Index: main/acl.c
===================================================================
--- main/acl.c	(revision 393737)
+++ main/acl.c	(working copy)
@@ -359,21 +359,7 @@
  */
 #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,
+int ast_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
 		struct ast_sockaddr *result)
 {
 	int res = 0;
@@ -693,7 +679,7 @@
 			return ret;
 		}
 
-		if (apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
+		if (ast_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 +791,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_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 393737)
+++ 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);
