Implement NAT trick for outbound SIP connections
authorJeremy McNamara <jj@nufone.net>
Tue, 13 Jan 2004 01:31:42 +0000 (01:31 +0000)
committerJeremy McNamara <jj@nufone.net>
Tue, 13 Jan 2004 01:31:42 +0000 (01:31 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1998 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index 242b1cb..eb11c2a 100755 (executable)
@@ -394,9 +394,12 @@ static struct sip_registry *registrations;
 static int sipsock  = -1;
 static int globalnat = 0;
 static int globalcanreinvite = REINVITE_INVITE;
-static int use_external_ip = 0;
+
 
 static struct sockaddr_in bindaddr;
+static struct sockaddr_in localnet;
+static struct sockaddr_in localmask;
+static struct sockaddr_in externip;
 
 static struct ast_frame  *sip_read(struct ast_channel *ast);
 static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req);
@@ -434,14 +437,18 @@ static void sip_destroy(struct sip_pvt *p);
 
 static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us)
 {
-       if (use_external_ip) {
-               return -1;
-       } else {
-               if (bindaddr.sin_addr.s_addr)
-                       memcpy(us, &bindaddr.sin_addr, sizeof(struct in_addr));
-               else
-                       return ast_ouraddrfor(them, us);
-               }
+       /*
+         check to see if them is contained in our localnet/mask,
+         if not, use our externip for us, otherwise use the 
+         real internal address in bindaddr
+         */
+       if (localnet.sin_addr.s_addr && externip.sin_addr.s_addr &&
+           ((htonl(them->s_addr) & htonl(localnet.sin_addr.s_addr)) != htonl(localnet.sin_addr.s_addr)))
+               memcpy(us, &externip.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);
        return 0;
 }
 
@@ -3018,6 +3025,8 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        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");
@@ -3051,9 +3060,16 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
                        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 (!use_external_ip && 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);
        }
 
@@ -6135,6 +6151,10 @@ static int reload_config(void)
        sip_prefs_free();
        
        memset(&bindaddr, 0, sizeof(bindaddr));
+       memset(&localnet, 0, sizeof(localnet));
+       memset(&localmask, 0, sizeof(localmask));
+       memset(&externip, 0, sizeof(externip));
+
        /* Initialize some reasonable defaults */
        strncpy(context, "default", sizeof(context) - 1);
        strcpy(language, "");
@@ -6195,13 +6215,21 @@ static int reload_config(void)
                        } else {
                                memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
                        }
+               } else if (!strcasecmp(v->name, "localnet")) {
+                       if (!(hp = gethostbyname(v->value)))
+                               ast_log(LOG_WARNING, "Invalid localnet keyword: %s\n", v->value);
+                       else 
+                               memcpy(&localnet.sin_addr, hp->h_addr, sizeof(localnet.sin_addr));
+               } else if (!strcasecmp(v->name, "localmask")) {
+                       if (!(hp = gethostbyname(v->value)))
+                               ast_log(LOG_WARNING, "Invalid localmask keyword: %s\n", v->value);
+                       else
+                               memcpy(&localmask.sin_addr, hp->h_addr, sizeof(localmask.sin_addr));
                } else if (!strcasecmp(v->name, "externip")) {
-                       if (!(hp = gethostbyname(v->value))) {
+                       if (!(hp = gethostbyname(v->value))) 
                                ast_log(LOG_WARNING, "Invalid address for externip keyword: %s\n", v->value);
-                       } else {
-                               memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
-                               use_external_ip = 1;
-                       }
+                       else
+                               memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
                } else if (!strcasecmp(v->name, "allow")) {
                        format = ast_getformatbyname(v->value);
                        if (format < 1) 
@@ -6276,17 +6304,16 @@ static int reload_config(void)
                }
                cat = ast_category_browse(cfg, cat);
        }
-       if (!use_external_ip) { 
-               if (ntohl(bindaddr.sin_addr.s_addr)) {
-                       memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
-               } else {
-                       hp = gethostbyname(ourhost);
-                       if (!hp) {
-                               ast_log(LOG_WARNING, "Unable to get IP address for %s, SIP disabled\n", ourhost);
-                               return 0;
-                       }
-                       memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
+       
+       if (ntohl(bindaddr.sin_addr.s_addr)) {
+               memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
+       } else {
+               hp = gethostbyname(ourhost);
+               if (!hp) {
+                       ast_log(LOG_WARNING, "Unable to get IP address for %s, SIP disabled\n", ourhost);
+                       return 0;
                }
+               memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
        }
        if (!ntohs(bindaddr.sin_port))
                bindaddr.sin_port = ntohs(DEFAULT_SIP_PORT);