Add IPv6 Support To chan_iax2

This patch adds IPv6 support to chan_iax2.  Yay!

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

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

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


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400568 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Michael L. Young
2013-10-04 21:41:58 +00:00
parent 21902bf964
commit 2af53640c8
8 changed files with 839 additions and 676 deletions

View File

@@ -770,7 +770,6 @@ Stasis Message Bus
Stasis can be configured in stasis.conf. Note that these parameters operate Stasis can be configured in stasis.conf. Note that these parameters operate
at a very low level in Asterisk, and generally will not require changes. at a very low level in Asterisk, and generally will not require changes.
Channel Drivers Channel Drivers
------------------ ------------------
* When a channel driver is configured to enable jiterbuffers, they are now * When a channel driver is configured to enable jiterbuffers, they are now
@@ -815,6 +814,11 @@ chan_dahdi
specified to be created, or the keyword 'new' can be used to add channels specified to be created, or the keyword 'new' can be used to add channels
not yet created. not yet created.
chan_iax2
------------------
* IPv6 support has been added. We are now able to bind to and
communicate using IPv6 addresses.
chan_local chan_local
------------------ ------------------
* The /b option has been removed. * The /b option has been removed.

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@ struct iax_ies {
char *challenge; char *challenge;
char *md5_result; char *md5_result;
char *rsa_result; char *rsa_result;
struct sockaddr_in *apparent_addr; struct ast_sockaddr apparent_addr;
unsigned short refresh; unsigned short refresh;
unsigned short dpstatus; unsigned short dpstatus;
unsigned short callno; unsigned short callno;
@@ -153,13 +153,13 @@ struct iax_ie_data {
void iax_set_output(void (*output)(const char *data)); void iax_set_output(void (*output)(const char *data));
/* Choose a different function for errors */ /* Choose a different function for errors */
void iax_set_error(void (*output)(const char *data)); 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); void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t len);
const char *iax_ie2str(int ie); 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_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_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_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); int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsigned short value);

View File

@@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/config.h" #include "asterisk/config.h"
#include "asterisk/lock.h" #include "asterisk/lock.h"
#include "asterisk/threadstorage.h" #include "asterisk/threadstorage.h"
#include "asterisk/netsock2.h"
#include "include/iax2.h" #include "include/iax2.h"
#include "include/parser.h" #include "include/parser.h"
@@ -83,13 +84,23 @@ static void (*errorf)(const char *str) = internalerror;
static void dump_addr(char *output, int maxlen, void *value, int len) static void dump_addr(char *output, int maxlen, void *value, int len)
{ {
struct sockaddr_in sin; struct ast_sockaddr addr;
if (len == (int)sizeof(sin)) {
memcpy(&sin, value, len); if (len == (int)sizeof(struct sockaddr_in)) {
snprintf(output, maxlen, "IPV4 %s:%d", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); addr.ss.ss_family = AF_INET;
} else if (len == (int) sizeof(struct sockaddr_in6)) {
addr.ss.ss_family = AF_INET6;
} else { } else {
ast_copy_string(output, "Invalid Address", maxlen); ast_copy_string(output, "Invalid Address", maxlen);
return;
} }
memcpy(&addr, value, len);
addr.len = len;
snprintf(output, maxlen, "%s %s",
ast_sockaddr_is_ipv4(&addr) || ast_sockaddr_is_ipv4_mapped(&addr) ? "IPV4" : "IPV6",
ast_sockaddr_stringify(&addr));
} }
static void dump_string_hex(char *output, int maxlen, void *value, int len) static void dump_string_hex(char *output, int maxlen, void *value, int len)
@@ -172,12 +183,23 @@ static void dump_datetime(char *output, int maxlen, void *value, int len)
static void dump_ipaddr(char *output, int maxlen, void *value, int len) static void dump_ipaddr(char *output, int maxlen, void *value, int len)
{ {
struct sockaddr_in sin; struct ast_sockaddr addr;
if (len == (int)sizeof(unsigned int)) { char *str_addr;
memcpy(&sin.sin_addr, value, len);
snprintf(output, maxlen, "%s", ast_inet_ntoa(sin.sin_addr)); if (len == (int)sizeof(struct sockaddr_in)) {
} else addr.ss.ss_family = AF_INET;
} else if (len == (int)sizeof(struct sockaddr_in6)) {
addr.ss.ss_family = AF_INET6;
} else {
ast_copy_string(output, "Invalid IPADDR", maxlen); ast_copy_string(output, "Invalid IPADDR", maxlen);
return;
}
memcpy(&addr, value, len);
addr.len = len;
str_addr = ast_sockaddr_stringify(&addr);
ast_copy_string(output, str_addr, maxlen);
} }
@@ -564,7 +586,7 @@ void iax_frame_subclass2str(enum iax_frame_subclass subclass, char *str, size_t
ast_copy_string(str, cmd, len); ast_copy_string(str, cmd, len);
} }
void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen) void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen)
{ {
const char *framelist[] = { const char *framelist[] = {
"(0?)", "(0?)",
@@ -677,19 +699,22 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s
snprintf(subclass2, sizeof(subclass2), "%d", fh->csub); snprintf(subclass2, sizeof(subclass2), "%d", fh->csub);
subclass = subclass2; subclass = subclass2;
} }
snprintf(tmp, sizeof(tmp),
"%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n", snprintf(tmp, sizeof(tmp),
"%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s Subclass: %s\n",
dir, dir,
retries, fh->oseqno, fh->iseqno, class, subclass); retries, fh->oseqno, fh->iseqno, class, subclass);
outputf(tmp); outputf(tmp);
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp), " Timestamp: %05lums SCall: %5.5d DCall: %5.5d %s\n",
" Timestamp: %05lums SCall: %5.5d DCall: %5.5d [%s:%d]\n", (unsigned long)ntohl(fh->ts),
(unsigned long)ntohl(fh->ts), ntohs(fh->scallno) & ~IAX_FLAG_FULL,
ntohs(fh->scallno) & ~IAX_FLAG_FULL, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS,
ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); ast_sockaddr_stringify(addr));
outputf(tmp); outputf(tmp);
if (fh->type == AST_FRAME_IAX) if (fh->type == AST_FRAME_IAX)
dump_ies(fh->iedata, datalen); dump_ies(fh->iedata, datalen);
} }
int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen) int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *data, int datalen)
@@ -707,9 +732,9 @@ int iax_ie_append_raw(struct iax_ie_data *ied, unsigned char ie, const void *dat
return 0; 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) int iax_ie_append_versioned_uint64(struct iax_ie_data *ied, unsigned char ie, unsigned char version, uint64_t value)
@@ -904,7 +929,8 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
ies->rsa_result = (char *)data + 2; ies->rsa_result = (char *)data + 2;
break; break;
case IAX_IE_APPARENT_ADDR: case IAX_IE_APPARENT_ADDR:
ies->apparent_addr = ((struct sockaddr_in *)(data + 2)); memcpy(&ies->apparent_addr , (struct ast_sockaddr *) (data + 2), len);
ies->apparent_addr.len = len;
break; break;
case IAX_IE_REFRESH: case IAX_IE_REFRESH:
if (len != (int)sizeof(unsigned short)) { if (len != (int)sizeof(unsigned short)) {

View File

@@ -50,6 +50,18 @@ enum ast_transport {
AST_TRANSPORT_WSS = 1 << 4, AST_TRANSPORT_WSS = 1 << 4,
}; };
/*!
* \brief
* Isolate a 32-bit section of an IPv6 address
*
* An IPv6 address can be divided into 4 32-bit chunks. This gives
* easy access to one of these chunks.
*
* \param sin6 A pointer to a struct sockaddr_in6
* \param index Which 32-bit chunk to operate on. Must be in the range 0-3.
*/
#define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
/*! /*!
* \brief Socket address structure. * \brief Socket address structure.
* *
@@ -399,6 +411,23 @@ int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags);
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
int flags, int family); int flags, int family);
/*!
* \brief
* Apply a netmask to an address and store the result in a separate structure.
*
* When dealing with IPv6 addresses, one cannot apply a netmask with a simple
* logical AND operation. Futhermore, the incoming address may be an IPv4
* address and needs to be mapped properly before attempting to apply a rule.
*
* \param addr The IP address to apply the mask to.
* \param netmask The netmask configured in the host access rule.
* \param result The resultant address after applying the netmask to the given address
* \retval 0 Successfully applied netmask
* \retval -1 Failed to apply netmask
*/
int ast_sockaddr_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
struct ast_sockaddr *result);
/*! /*!
* \since 1.8 * \since 1.8
* *

View File

@@ -347,63 +347,6 @@ struct ast_acl_list *ast_duplicate_acl_list(struct ast_acl_list *original)
return clone; return clone;
} }
/*!
* \brief
* Isolate a 32-bit section of an IPv6 address
*
* An IPv6 address can be divided into 4 32-bit chunks. This gives
* easy access to one of these chunks.
*
* \param sin6 A pointer to a struct sockaddr_in6
* \param index Which 32-bit chunk to operate on. Must be in the range 0-3.
*/
#define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
/*!
* \brief
* Apply a netmask to an address and store the result in a separate structure.
*
* When dealing with IPv6 addresses, one cannot apply a netmask with a simple
* logical and operation. Furthermore, the incoming address may be an IPv4 address
* and need to be mapped properly before attempting to apply a rule.
*
* \param addr The IP address to apply the mask to.
* \param netmask The netmask configured in the host access rule.
* \param result The resultant address after applying the netmask to the given address
* \retval 0 Successfully applied netmask
* \retval -1 Failed to apply netmask
*/
static int apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
struct ast_sockaddr *result)
{
int res = 0;
if (ast_sockaddr_is_ipv4(addr)) {
struct sockaddr_in result4 = { 0, };
struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr->ss;
struct sockaddr_in *mask4 = (struct sockaddr_in *) &netmask->ss;
result4.sin_family = AF_INET;
result4.sin_addr.s_addr = addr4->sin_addr.s_addr & mask4->sin_addr.s_addr;
ast_sockaddr_from_sin(result, &result4);
} else if (ast_sockaddr_is_ipv6(addr)) {
struct sockaddr_in6 result6 = { 0, };
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr->ss;
struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *) &netmask->ss;
int i;
result6.sin6_family = AF_INET6;
for (i = 0; i < 4; ++i) {
V6_WORD(&result6, i) = V6_WORD(addr6, i) & V6_WORD(mask6, i);
}
memcpy(&result->ss, &result6, sizeof(result6));
result->len = sizeof(result6);
} else {
/* Unsupported address scheme */
res = -1;
}
return res;
}
/*! /*!
* \brief * \brief
* Parse a netmask in CIDR notation * Parse a netmask in CIDR notation
@@ -468,8 +411,6 @@ static int parse_cidr_mask(struct ast_sockaddr *addr, int is_v4, const char *mas
return 0; return 0;
} }
void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag) void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
{ {
struct ast_acl *acl = NULL; struct ast_acl *acl = NULL;
@@ -693,7 +634,7 @@ struct ast_ha *ast_append_ha(const char *sense, const char *stuff, struct ast_ha
return ret; return ret;
} }
if (apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) { if (ast_sockaddr_apply_netmask(&ha->addr, &ha->netmask, &ha->addr)) {
/* This shouldn't happen because ast_sockaddr_parse would /* This shouldn't happen because ast_sockaddr_parse would
* have failed much earlier on an unsupported address scheme * have failed much earlier on an unsupported address scheme
*/ */
@@ -805,7 +746,7 @@ enum ast_acl_sense ast_apply_ha(const struct ast_ha *ha, const struct ast_sockad
/* For each rule, if this address and the netmask = the net address /* For each rule, if this address and the netmask = the net address
apply the current rule */ apply the current rule */
if (apply_netmask(addr_to_use, &current_ha->netmask, &result)) { if (ast_sockaddr_apply_netmask(addr_to_use, &current_ha->netmask, &result)) {
/* Unlikely to happen since we know the address to be IPv4 or IPv6 */ /* Unlikely to happen since we know the address to be IPv4 or IPv6 */
continue; continue;
} }

View File

@@ -117,7 +117,7 @@ struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct i
const int reuseFlag = 1; const int reuseFlag = 1;
/* Make a UDP socket */ /* 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) { if (netsocket < 0) {
ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno));
@@ -155,7 +155,7 @@ struct ast_netsock *ast_netsock_bindaddr(struct ast_netsock_list *list, struct i
ns->ioc = ioc; ns->ioc = ioc;
ns->sockfd = netsocket; ns->sockfd = netsocket;
ns->data = data; ns->data = data;
memcpy(&ns->bindaddr, bindaddr, sizeof(ns->bindaddr)); ast_sockaddr_copy(&ns->bindaddr, bindaddr);
ASTOBJ_CONTAINER_LINK(list, ns); ASTOBJ_CONTAINER_LINK(list, ns);
return ns; return ns;
@@ -171,10 +171,6 @@ struct ast_netsock *ast_netsock_bind(struct ast_netsock_list *list, struct io_co
struct ast_sockaddr addr; struct ast_sockaddr addr;
if (ast_sockaddr_parse(&addr, bindinfo, 0)) { 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)) { if (!ast_sockaddr_port(&addr)) {
ast_sockaddr_set_port(&addr, defaultport); ast_sockaddr_set_port(&addr, defaultport);

View File

@@ -297,6 +297,37 @@ cleanup:
return res_cnt; return res_cnt;
} }
int ast_sockaddr_apply_netmask(const struct ast_sockaddr *addr, const struct ast_sockaddr *netmask,
struct ast_sockaddr *result)
{
int res = 0;
if (ast_sockaddr_is_ipv4(addr)) {
struct sockaddr_in result4 = { 0, };
struct sockaddr_in *addr4 = (struct sockaddr_in *) &addr->ss;
struct sockaddr_in *mask4 = (struct sockaddr_in *) &netmask->ss;
result4.sin_family = AF_INET;
result4.sin_addr.s_addr = addr4->sin_addr.s_addr & mask4->sin_addr.s_addr;
ast_sockaddr_from_sin(result, &result4);
} else if (ast_sockaddr_is_ipv6(addr)) {
struct sockaddr_in6 result6 = { 0, };
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &addr->ss;
struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *) &netmask->ss;
int i;
result6.sin6_family = AF_INET6;
for (i = 0; i < 4; ++i) {
V6_WORD(&result6, i) = V6_WORD(addr6, i) & V6_WORD(mask6, i);
}
memcpy(&result->ss, &result6, sizeof(result6));
result->len = sizeof(result6);
} else {
/* Unsupported address scheme */
res = -1;
}
return res;
}
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b) int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
{ {
const struct ast_sockaddr *a_tmp, *b_tmp; const struct ast_sockaddr *a_tmp, *b_tmp;