[Asterisk-Dev] NAT patch for chan_sip.c
William Waites
asterisk at lists.styx.org
Thu Oct 30 10:59:28 MST 2003
This is not thoroughly tested, but seems to work for me. It consists in
three changes:
1. introduction of inside_net, inside_mask and outside_addr global
parameters for sip.conf
2. change transmit_register to call ast_sip_ouraddrfor() before
building the contact header
3. change ast_sip_ouraddrfor() to check if the destination is
internal or external. if internal, continue as usual, if external
return outside_addr in *us
Consider this patch suitably disclaimed, and without any warranty
whatsoever. This code was produced on behalf of NTG Clarity Networks,
Montréal.
Index: chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.203
diff -u -r1.203 chan_sip.c
--- chan_sip.c 25 Oct 2003 17:41:02 -0000 1.203
+++ chan_sip.c 30 Oct 2003 17:23:54 -0000
@@ -390,6 +390,9 @@
static struct sockaddr_in bindaddr;
+static struct sockaddr_in inside_net;
+static struct sockaddr_in inside_mask;
+static struct sockaddr_in outside_addr;
static struct ast_frame *sip_read(struct ast_channel *ast);
static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request
*req);
@@ -425,7 +428,15 @@
static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us)
{
- if (bindaddr.sin_addr.s_addr)
+ /*
+ check to see if them is contained in our inside_net/mask,
+ if not, use our outside_addr for us, otherwise use the
+ real internal address in bindaddr
+ */
+ if (inside_net.sin_addr.s_addr && outside_addr.sin_addr.s_addr &&
+ ((htonl(them->s_addr) & htonl(inside_net.sin_addr.s_addr)) !=
htonl(inside_net.sin_addr.s_addr)))
+ memcpy(us, &outside_addr.sin_addr, sizeof(struct in_addr));
+ else if (bindaddr.sin_addr.s_addr)
memcpy(us, &bindaddr.sin_addr, sizeof(struct in_addr));
else
return ast_ouraddrfor(them, us);
@@ -2951,6 +2962,8 @@
char via[80];
char addr[80];
struct sip_pvt *p;
+ struct hostent *hp;
+
/* exit if we are already in process with this registrar ?*/
if ( r == NULL || ((auth==NULL) && (r->regstate==REG_STATE_REGSENT ||
r->regstate==REG_STATE_AUTHSENT))) {
ast_log(LOG_NOTICE, "Strange, trying to register when
registration already pending\n");
@@ -2984,9 +2997,16 @@
strncpy(p->peername, r->username, sizeof(p->peername)-1);
strncpy(p->username, r->username, sizeof(p->username)-1);
strncpy(p->exten, r->contact, sizeof(p->exten) - 1);
- /* Always bind to our IP if specified */
- if (bindaddr.sin_addr.s_addr)
- memcpy(&p->ourip, &bindaddr.sin_addr, sizeof(p->ourip));
+
+ /*
+ check which address we should use in our contact header
+ based on whether the remote host is on the external or
+ internal network so we can register through nat
+ */
+ if ((hp = gethostbyname(r->hostname))) {
+ if (ast_sip_ouraddrfor((struct in_addr *)hp->h_addr,
&p->ourip))
+ memcpy(&p->ourip, &bindaddr.sin_addr,
sizeof(p->ourip));
+ }
build_contact(p);
}
@@ -5921,6 +5941,10 @@
sip_prefs_free();
memset(&bindaddr, 0, sizeof(bindaddr));
+ memset(&inside_net, 0, sizeof(inside_net));
+ memset(&inside_mask, 0, sizeof(inside_mask));
+ memset(&outside_addr, 0, sizeof(outside_addr));
+
/* Initialize some reasonable defaults */
strncpy(context, "default", sizeof(context) - 1);
strcpy(language, "");
@@ -5979,6 +6003,21 @@
} else {
memcpy(&bindaddr.sin_addr, hp->h_addr,
sizeof(bindaddr.sin_addr));
}
+ } else if (!strcasecmp(v->name, "inside_net")) {
+ if (!(hp = gethostbyname(v->value)))
+ ast_log(LOG_WARNING, "Invalid INSIDE_NET:
%s\n", v->value);
+ else
+ memcpy(&inside_net.sin_addr, hp->h_addr,
sizeof(inside_net.sin_addr));
+ } else if (!strcasecmp(v->name, "inside_mask")) {
+ if (!(hp = gethostbyname(v->value)))
+ ast_log(LOG_WARNING, "Invalid INSIDE_MASK:
%s\n", v->value);
+ else
+ memcpy(&inside_mask.sin_addr, hp->h_addr,
sizeof(inside_mask.sin_addr));
+ } else if (!strcasecmp(v->name, "outside_addr")) {
+ if (!(hp = gethostbyname(v->value)))
+ ast_log(LOG_WARNING, "Invalid OUTSIDE_MASK:
%s\n", v->value);
+ else
+ memcpy(&outside_addr.sin_addr, hp->h_addr,
sizeof(outside_addr.sin_addr));
} else if (!strcasecmp(v->name, "allow")) {
format = ast_getformatbyname(v->value);
if (format < 1)
More information about the asterisk-dev
mailing list