Add new "route" mode to work around UNIDEN bugs (bug #2308)
authorMark Spencer <markster@digium.com>
Fri, 27 Aug 2004 02:45:35 +0000 (02:45 +0000)
committerMark Spencer <markster@digium.com>
Fri, 27 Aug 2004 02:45:35 +0000 (02:45 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3661 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
configs/sip.conf.sample

index e4f86c1..4f80781 100755 (executable)
@@ -3,9 +3,9 @@
  *
  * Implementation of Session Initiation Protocol
  * 
- * Copyright (C) 1999, Mark Spencer
+ * Copyright (C) 2004, Digium, Inc.
  *
- * Mark Spencer <markster@linux-support.net>
+ * Mark Spencer <markster@digium.com>
  *
  * This program is free software, distributed under the terms of
  * the GNU General Public License
@@ -478,8 +478,9 @@ static int sip_reloading = 0;
 #define REG_STATE_NOAUTH          6
 
 #define SIP_NAT_NEVER          0
-#define SIP_NAT_RFC3581                1
-#define SIP_NAT_ALWAYS         2
+#define SIP_NAT_RFC3581                (1 << 0)
+#define SIP_NAT_ROUTE          (1 << 2)
+#define SIP_NAT_ALWAYS         (SIP_NAT_ROUTE | SIP_NAT_RFC3581)
 
 /* sip_registry: Registrations with other SIP proxies */
 struct sip_registry {
@@ -575,7 +576,7 @@ static inline int sip_debug_test_pvt(struct sip_pvt *p)
 {
        if (sipdebug == 0)
                return 0;
-       return sip_debug_test_addr(((p->nat == SIP_NAT_ALWAYS) ? &p->recv : &p->sa));
+       return sip_debug_test_addr(((p->nat & SIP_NAT_ROUTE) ? &p->recv : &p->sa));
 }
 
 
@@ -584,7 +585,7 @@ static int __sip_xmit(struct sip_pvt *p, char *data, int len)
 {
        int res;
        char iabuf[INET_ADDRSTRLEN];
-       if (p->nat == SIP_NAT_ALWAYS)
+       if (p->nat & SIP_NAT_ROUTE)
            res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in));
        else
            res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in));
@@ -663,7 +664,7 @@ static int retrans_pkt(void *data)
        if (pkt->retrans < MAX_RETRANS) {
                pkt->retrans++;
                if (sip_debug_test_pvt(pkt->owner)) {
-                       if (pkt->owner->nat == SIP_NAT_ALWAYS)
+                       if (pkt->owner->nat & SIP_NAT_ROUTE)
                                ast_verbose("Retransmitting #%d (NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->recv.sin_addr), ntohs(pkt->owner->recv.sin_port));
                        else
                                ast_verbose("Retransmitting #%d (no NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port));
@@ -863,7 +864,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, int reliabl
        struct sip_request tmp;
        char tmpmsg[80];
        if (sip_debug_test_pvt(p)) {
-               if (p->nat == SIP_NAT_ALWAYS)
+               if (p->nat & SIP_NAT_ROUTE)
                        ast_verbose("%sTransmitting (NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
                else
                        ast_verbose("%sTransmitting (no NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
@@ -896,7 +897,7 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, int reliable
        struct sip_request tmp;
        char tmpmsg[80];
        if (sip_debug_test_pvt(p)) {
-               if (p->nat == SIP_NAT_ALWAYS)
+               if (p->nat & SIP_NAT_ROUTE)
                        ast_verbose("%sTransmitting:\n%s (NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
                else
                        ast_verbose("%sTransmitting:\n%s (no NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
@@ -1275,12 +1276,12 @@ static int create_addr(struct sip_pvt *r, char *opeer)
                        r->capability = p->capability;
                        r->nat = p->nat;
                        if (r->rtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (r->nat == SIP_NAT_ALWAYS));
-                               ast_rtp_setnat(r->rtp, (r->nat == SIP_NAT_ALWAYS));
+                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (r->nat & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(r->rtp, (r->nat & SIP_NAT_ROUTE));
                        }
                        if (r->vrtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (r->nat == SIP_NAT_ALWAYS));
-                               ast_rtp_setnat(r->vrtp, (r->nat == SIP_NAT_ALWAYS));
+                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (r->nat & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(r->vrtp, (r->nat & SIP_NAT_ROUTE));
                        }
                        strncpy(r->peername, p->username, sizeof(r->peername)-1);
                        strncpy(r->authname, p->username, sizeof(r->authname)-1);
@@ -2304,9 +2305,9 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useg
                /* Setup NAT structure according to global settings if we have an address */
                p->nat = global_nat;
                memcpy(&p->recv, sin, sizeof(p->recv));
-               ast_rtp_setnat(p->rtp, (p->nat == SIP_NAT_ALWAYS));
+               ast_rtp_setnat(p->rtp, (p->nat & SIP_NAT_ROUTE));
                if (p->vrtp)
-                       ast_rtp_setnat(p->vrtp, (p->nat == SIP_NAT_ALWAYS));
+                       ast_rtp_setnat(p->vrtp, (p->nat & SIP_NAT_ROUTE));
        }
 
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
@@ -3124,7 +3125,7 @@ static int reqprep(struct sip_request *req, struct sip_pvt *p, char *msg, int se
        
        if (newbranch) {
                p->branch ^= rand();
-               if (p->nat != SIP_NAT_NEVER)
+               if (p->nat & SIP_NAT_RFC3581)
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
                else /* Some implementations (e.g. Uniden UIP200) can't handle rport being in the message!! */
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -3719,7 +3720,7 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, ch
        if (init) {
                /* Bump branch even on initial requests */
                p->branch ^= rand();
-               if (p->nat != SIP_NAT_NEVER)
+               if (p->nat & SIP_NAT_RFC3581)
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
                else /* Work around buggy UNIDEN UIP200 firmware */
                        snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -4087,7 +4088,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        p->ocseq = r->ocseq;
 
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat != SIP_NAT_NEVER)
+       if (p->nat & SIP_NAT_RFC3581)
                snprintf(via, sizeof(via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else /* Work around buggy UNIDEN UIP200 firmware */
                snprintf(via, sizeof(via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -4338,7 +4339,7 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
        } else
                port = DEFAULT_SIP_PORT;
        memcpy(&oldsin, &p->addr, sizeof(oldsin));
-       if (p->nat != SIP_NAT_ALWAYS) {
+       if (p->nat & SIP_NAT_RFC3581) {
                /* XXX This could block for a long time XXX */
                hp = ast_gethostbyname(n, &ahp);
                if (!hp)  {
@@ -5088,9 +5089,9 @@ static int check_via(struct sip_pvt *p, struct sip_request *req)
                p->sa.sin_port = htons(pt ? atoi(pt) : DEFAULT_SIP_PORT);
                c = strstr(via, ";rport");
                if (c && (c[6] != '='))
-                       p->nat = SIP_NAT_ALWAYS;
+                       p->nat |= SIP_NAT_ROUTE;
                if (sip_debug_test_pvt(p)) {
-                       if (p->nat == SIP_NAT_ALWAYS)
+                       if (p->nat & SIP_NAT_ROUTE)
                                ast_verbose("Sending to %s : %d (NAT)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
                        else
                                ast_verbose("Sending to %s : %d (non-NAT)\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port));
@@ -5249,12 +5250,12 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                }
 
                if (p->rtp) {
-                       ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (p->nat == SIP_NAT_ALWAYS));
-                       ast_rtp_setnat(p->rtp, (p->nat == SIP_NAT_ALWAYS));
+                       ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (p->nat & SIP_NAT_ROUTE));
+                       ast_rtp_setnat(p->rtp, (p->nat & SIP_NAT_ROUTE));
                }
                if (p->vrtp) {
-                       ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (p->nat == SIP_NAT_ALWAYS));
-                       ast_rtp_setnat(p->vrtp, (p->nat == SIP_NAT_ALWAYS));
+                       ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (p->nat & SIP_NAT_ROUTE));
+                       ast_rtp_setnat(p->vrtp, (p->nat & SIP_NAT_ROUTE));
                }
                if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, user->md5secret, cmd, uri, reliable, ignore))) {
                        sip_cancel_destroy(p);
@@ -5324,12 +5325,12 @@ static int check_user_full(struct sip_pvt *p, struct sip_request *req, char *cmd
                        p->ospauth = peer->ospauth;
 #endif
                        if (p->rtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (p->nat == SIP_NAT_ALWAYS));
-                               ast_rtp_setnat(p->rtp, (p->nat == SIP_NAT_ALWAYS));
+                               ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (p->nat & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(p->rtp, (p->nat & SIP_NAT_ROUTE));
                        }
                        if (p->vrtp) {
-                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (p->nat == SIP_NAT_ALWAYS));
-                               ast_rtp_setnat(p->vrtp, (p->nat == SIP_NAT_ALWAYS));
+                               ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (p->nat & SIP_NAT_ROUTE));
+                               ast_rtp_setnat(p->vrtp, (p->nat & SIP_NAT_ROUTE));
                        }
                        strncpy(p->peersecret, peer->secret, sizeof(p->peersecret)-1);
                        p->peersecret[sizeof(p->peersecret)-1] = '\0';
@@ -5466,6 +5467,22 @@ static int sip_show_inuse(int fd, int argc, char *argv[]) {
 #undef FORMAT
 #undef FORMAT2
 }
+
+static char *nat2str(int nat)
+{
+       switch(nat) {
+       case SIP_NAT_NEVER:
+               return "No";
+       case SIP_NAT_ROUTE:
+               return "Route";
+       case SIP_NAT_ALWAYS:
+               return "Always";
+       case SIP_NAT_RFC3581:
+               return "RFC3581";
+       default:
+               return "Unknown";
+       }
+}
                            
 /*--- sip_show_users: CLI Command 'SIP Show Users' ---*/
 static int sip_show_users(int fd, int argc, char *argv[])
@@ -5482,7 +5499,7 @@ static int sip_show_users(int fd, int argc, char *argv[])
                                user->accountcode,
                                user->context,
                                user->ha ? "Yes" : "No",
-                               user->nat ? ((user->nat == SIP_NAT_ALWAYS) ? "Yes" : "RFC3581" ): "No");
+                               nat2str(user->nat));
        }
        ast_mutex_unlock(&userl.lock);
        return RESULT_SUCCESS;
@@ -5526,7 +5543,7 @@ static int sip_show_peers(int fd, int argc, char *argv[])
                        snprintf(srch, sizeof(srch), FORMAT, name,
                                peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
                                peer->dynamic ? " D " : "   ",  /* Dynamic or not? */
-                               (peer->nat == SIP_NAT_ALWAYS) ? " N " : "   ",  /* NAT=yes? */
+                               (peer->nat & SIP_NAT_ROUTE) ? " N " : "   ",    /* NAT=yes? */
                                peer->ha ? " A " : "   ",       /* permit/deny */
                                nm,
                                ntohs(peer->addr.sin_port), status);
@@ -5547,7 +5564,7 @@ static int sip_show_peers(int fd, int argc, char *argv[])
                    ast_cli(fd, FORMAT, name, 
                        peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
                         peer->dynamic ? " D " : "   ",  /* Dynamic or not? */
-                        (peer->nat == SIP_NAT_ALWAYS) ? " N " : "   ", /* NAT=yes? */
+                        (peer->nat & SIP_NAT_ROUTE) ? " N " : "   ",   /* NAT=yes? */
                         peer->ha ? " A " : "   ",       /* permit/deny */
                        nm,
                        ntohs(peer->addr.sin_port), status);
@@ -5630,7 +5647,7 @@ static int sip_show_peer(int fd, int argc, char *argv[])
                ast_cli(fd, "  Expire       : %d\n", peer->expire);
                ast_cli(fd, "  Expiry       : %d\n", peer->expiry);
                ast_cli(fd, "  Insecure     : %s\n", (peer->insecure?((peer->insecure == 2)?"Very":"Yes"):"No") );
-               ast_cli(fd, "  Nat          : %s\n", (peer->nat?((peer->nat == SIP_NAT_ALWAYS) ? "Yes" : "RFC3581"):"No"));
+               ast_cli(fd, "  Nat          : %s\n", nat2str(peer->nat));
                ast_cli(fd, "  ACL          : %s\n", (peer->ha?"Yes":"No"));
                ast_cli(fd, "  CanReinvite  : %s\n", (peer->canreinvite?"Yes":"No"));
                ast_cli(fd, "  PromiscRedir : %s\n", (peer->promiscredir?"Yes":"No"));
@@ -5834,7 +5851,7 @@ static int sip_show_channel(int fd, int argc, char *argv[])
                        ast_cli(fd, "  Format                  %s\n", ast_getformatname(cur->owner ? cur->owner->nativeformats : 0) );
                        ast_cli(fd, "  Theoretical Address:    %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), ntohs(cur->sa.sin_port));
                        ast_cli(fd, "  Received Address:       %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->recv.sin_addr), ntohs(cur->recv.sin_port));
-                       ast_cli(fd, "  NAT Support:            %s\n", cur->nat ? ((cur->nat == SIP_NAT_ALWAYS) ? "Yes" : "RFC3581"): "No");
+                       ast_cli(fd, "  NAT Support:            %s\n", nat2str(cur->nat));
                        ast_cli(fd, "  Our Tag:                %08d\n", cur->tag);
                        ast_cli(fd, "  Their Tag:              %s\n", cur->theirtag);
                        ast_cli(fd, "  SIP User agent:         %s\n", cur->useragent);
@@ -7531,7 +7548,7 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer)
        if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
                memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat != SIP_NAT_NEVER)
+       if (p->nat & SIP_NAT_RFC3581)
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else /* UNIDEN UIP200 bug */
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -7747,7 +7764,7 @@ static int sip_poke_peer(struct sip_peer *peer)
        if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
                memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat != SIP_NAT_NEVER)
+       if (p->nat & SIP_NAT_RFC3581)
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -7869,7 +7886,7 @@ static struct ast_channel *sip_request(char *type, int format, void *data)
        if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
                memcpy(&p->ourip, &__ourip, sizeof(p->ourip));
        /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-       if (p->nat != SIP_NAT_NEVER)
+       if (p->nat & SIP_NAT_RFC3581)
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
        else /* UNIDEN bug */
                snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
@@ -7947,6 +7964,8 @@ static struct sip_user *build_user(char *name, struct ast_variable *v)
                        } else if (!strcasecmp(v->name, "nat")) {
                                if (!strcasecmp(v->value, "never"))
                                        user->nat = SIP_NAT_NEVER;
+                               else if (!strcasecmp(v->value, "route"))
+                                       user->nat = SIP_NAT_ROUTE;
                                else if (ast_true(v->value))
                                        user->nat = SIP_NAT_ALWAYS;
                                else
@@ -8129,6 +8148,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
                        } else if (!strcasecmp(v->name, "nat")) {
                                if (!strcasecmp(v->value, "rfc3581"))
                                        peer->nat = SIP_NAT_RFC3581;
+                               else if (!strcasecmp(v->value, "route")) 
+                                       peer->nat = SIP_NAT_ROUTE;
                                else if (ast_true(v->value))
                                        peer->nat = SIP_NAT_ALWAYS;
                                else
@@ -8378,6 +8399,8 @@ static int reload_config(void)
                } else if (!strcasecmp(v->name, "nat")) {
                        if (!strcasecmp(v->value, "rfc3581"))
                                global_nat = SIP_NAT_RFC3581;
+                       else if (!strcasecmp(v->value, "route"))
+                               global_nat = SIP_NAT_ROUTE;
                        else if (ast_true(v->value))
                                global_nat = SIP_NAT_ALWAYS;
                        else
index 5ca408e..8dc3d32 100755 (executable)
@@ -66,6 +66,7 @@ srvlookup=yes                 ; Enable DNS SRV lookups on outbound calls
                                 ; yes = Always ignore info and assume NAT
                                 ; no = Use NAT mode only according to RFC3581 
                                 ; never = Never attempt NAT mode or RFC3581 support
+                               ; route = Assume NAT, don't send rport (work around more UNIDEN bugs)
 ;promiscredir = no      ; If yes, allows 302 or REDIR to non-local SIP address
 ;                       ; Note that promiscredir when redirects are made to the
 ;                       ; local system will cause loops since SIP is incapable