nat_helper.c

Go to the documentation of this file.
00001 /*
00002  * $Id: nat_helper.c 566 2008-06-05 12:55:00Z vingarzan $
00003  *
00004  *
00005  * Copyright (C) 2005 Porta Software Ltd.
00006  *
00007  * This file is part of ser, a free SIP server.
00008  *
00009  * ser is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * For a license to use the ser software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact iptel.org by e-mail at the following addresses:
00017  *    info@iptel.org
00018  *
00019  * ser is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027 * History:
00028  * ---------
00029  * 2003-10-09   nat_uac_test introduced (jiri)
00030  *
00031  * 2003-11-06   nat_uac_test permitted from onreply_route (jiri)
00032  *
00033  * 2003-12-01   unforce_rtp_proxy introduced (sobomax)
00034  *
00035  * 2004-01-07   RTP proxy support updated to support new version of the
00036  *      RTP proxy (20040107).
00037  *
00038  *      force_rtp_proxy() now inserts a special flag
00039  *      into the SDP body to indicate that this session already
00040  *      proxied and ignores sessions with such flag.
00041  *
00042  *      Added run-time check for version of command protocol
00043  *      supported by the RTP proxy.
00044  *
00045  * 2004-01-16   Integrated slightly modified patch from Tristan Colgate,
00046  *      force_rtp_proxy function with IP as a parameter (janakj)
00047  *
00048  * 2004-01-28   nat_uac_test extended to allow testing SDP body (sobomax)
00049  *
00050  *      nat_uac_test extended to allow testing top Via (sobomax)
00051  *
00052  * 2004-02-21   force_rtp_proxy now accepts option argument, which
00053  *      consists of string of chars, each of them turns "on"
00054  *      some feature, currently supported ones are:
00055  *
00056  *       `a' - flags that UA from which message is received
00057  *             doesn't support symmetric RTP;
00058  *       `l' - force "lookup", that is, only rewrite SDP when
00059  *             corresponding session is already exists in the
00060  *             RTP proxy. Only makes sense for SIP requests,
00061  *             replies are always processed in "lookup" mode;
00062  *       `i' - flags that message is received from UA in the
00063  *             LAN. Only makes sense when RTP proxy is running
00064  *             in the bridge mode.
00065  *
00066  *      force_rtp_proxy can now be invoked without any arguments,
00067  *      as previously, with one argument - in this case argument
00068  *      is treated as option string and with two arguments, in
00069  *      which case 1st argument is option string and the 2nd
00070  *      one is IP address which have to be inserted into
00071  *      SDP (IP address on which RTP proxy listens).
00072  *
00073  * 2004-03-12   Added support for IPv6 addresses in SDPs. Particularly,
00074  *      force_rtp_proxy now can work with IPv6-aware RTP proxy,
00075  *      replacing IPv4 address in SDP with IPv6 one and vice versa.
00076  *      This allows creating full-fledged IPv4<->IPv6 gateway.
00077  *      See 4to6.cfg file for example.
00078  *
00079  *      Two new options added into force_rtp_proxy:
00080  *
00081  *       `f' - instructs nathelper to ignore marks inserted
00082  *             by another nathelper in transit to indicate
00083  *             that the session is already goes through another
00084  *             proxy. Allows creating chain of proxies.
00085  *       `r' - flags that IP address in SDP should be trusted.
00086  *             Without this flag, nathelper ignores address in the
00087  *             SDP and uses source address of the SIP message
00088  *             as media address which is passed to the RTP proxy.
00089  *
00090  *      Protocol between nathelper and RTP proxy in bridge
00091  *      mode has been slightly changed. Now RTP proxy expects SER
00092  *      to provide 2 flags when creating or updating session
00093  *      to indicate direction of this session. Each of those
00094  *      flags can be either `e' or `i'. For example `ei' means
00095  *      that we received INVITE from UA on the "external" network
00096  *      network and will send it to the UA on "internal" one.
00097  *      Also possible `ie' (internal->external), `ii'
00098  *      (internal->internal) and `ee' (external->external). See
00099  *      example file alg.cfg for details.
00100  *
00101  * 2004-03-15   If the rtp proxy test failed (wrong version or not started)
00102  *      retry test from time to time, when some *rtpproxy* function
00103  *      is invoked. Minimum interval between retries can be
00104  *      configured via rtpproxy_disable_tout module parameter (default
00105  *      is 60 seconds). Setting it to -1 will disable periodic
00106  *      rechecks completely, setting it to 0 will force checks
00107  *      for each *rtpproxy* function call. (andrei)
00108  *
00109  * 2004-03-22   Fix assignment of rtpproxy_retr and rtpproxy_tout module
00110  *      parameters.
00111  *
00112  * 2004-03-22   Fix get_body position (should be called before get_callid)
00113  *              (andrei)
00114  *
00115  * 2004-03-24   Fix newport for null ip address case (e.g onhold re-INVITE)
00116  *              (andrei)
00117  *
00118  * 2004-09-30   added received port != via port test (andrei)
00119  *
00120  * 2004-10-10   force_socket option introduced (jiri)
00121  *
00122  * 2005-02-24   Added support for using more than one rtp proxy, in which
00123  *      case traffic will be distributed evenly among them. In addition,
00124  *      each such proxy can be assigned a weight, which will specify
00125  *      which share of the traffic should be placed to this particular
00126  *      proxy.
00127  *
00128  *      Introduce failover mechanism, so that if SER detects that one
00129  *      of many proxies is no longer available it temporarily decreases
00130  *      its weight to 0, so that no traffic will be assigned to it.
00131  *      Such "disabled" proxies are periodically checked to see if they
00132  *      are back to normal in which case respective weight is restored
00133  *      resulting in traffic being sent to that proxy again.
00134  *
00135  *      Those features can be enabled by specifying more than one "URI"
00136  *      in the rtpproxy_sock parameter, optionally followed by the weight,
00137  *      which if absent is assumed to be 1, for example:
00138  *
00139  *      rtpproxy_sock="unix:/foo/bar=4 udp:1.2.3.4:3456=3 udp:5.6.7.8:5432=1"
00140  *
00141  * 2005-02-25   Force for pinging the socket returned by USRLOC (bogdan)
00142  *
00143  * 2005-03-22   Support for multiple media streams added (netch)
00144  *
00145  * 2005-04-27   Support for doing natpinging using real SIP requests added.
00146  *      Requires tm module for doing its work. Old method (sending UDP
00147  *      with 4 zero bytes can be selected by specifying natping_method="null".
00148  *
00149  * 2005-12-23   Support for selecting particular RTP proxy node has been added.
00150  *      In force_rtp_proxy() it can be done via new N modifier, followed
00151  *      by the index (starting at 0) of the node in the rtpproxy_sock
00152  *      parameter. For example, in the example above force_rtp_proxy("N1") will
00153  *      will select node udp:1.2.3.4:3456. In unforce_rtp_proxy(), the same
00154  *      can be done by specifying index as an argument directly, i.e.
00155  *      unforce_rtp_proxy(1).
00156  *
00157  *      Since nathelper is not transaction or call stateful, care should be
00158  *      taken to ensure that force_rtp_proxy() in request path matches
00159  *      force_rtp_proxy() in reply path, that is the same node is selected.
00160  *
00161  * 2006-06-10   select nathepler.rewrite_contact
00162  *      pingcontact function (tma)
00163  */
00164 
00221 #include <stdio.h>
00222 #include <stdlib.h>
00223 #include <string.h>
00224 #include <sys/socket.h>
00225 #include <netinet/in.h>
00226 #include <arpa/inet.h>
00227 
00228 #include "../../parser/msg_parser.h"
00229 #include "../../msg_translator.h"
00230 #include "../../parser/parser_f.h"
00231 #include "../../parser/contact/contact.h"
00232 #include "../../parser/contact/parse_contact.h"
00233 #include "../../parser/parse_uri.h"
00234 #include "../../parser/hf.h"
00235 #include "../../ut.h"
00236 #include "../../forward.h"
00237 #include "mod.h"
00238 #include "registrar_storage.h"
00239 #include "nat_helper.h"
00240 
00241 static const char udp_ping[2] = { 10, 13};  
00243 extern int pcscf_nat_enable;                
00244 extern int pcscf_nat_ping;                  
00245 extern int pcscf_nat_pingall;               
00246 extern int pcscf_nat_detection_type;        
00248 #define READ(val) \
00249     (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
00250 #define advance(_ptr,_n,_str,_error) \
00251     do{\
00252         if ((_ptr)+(_n)>(_str).s+(_str).len)\
00253             goto _error;\
00254         (_ptr) = (_ptr) + (_n);\
00255     }while(0);
00256 #define one_of_16( _x , _t ) \
00257     (_x==_t[0]||_x==_t[15]||_x==_t[8]||_x==_t[2]||_x==_t[3]||_x==_t[4]\
00258     ||_x==_t[5]||_x==_t[6]||_x==_t[7]||_x==_t[1]||_x==_t[9]||_x==_t[10]\
00259     ||_x==_t[11]||_x==_t[12]||_x==_t[13]||_x==_t[14])
00260 #define one_of_8( _x , _t ) \
00261     (_x==_t[0]||_x==_t[7]||_x==_t[1]||_x==_t[2]||_x==_t[3]||_x==_t[4]\
00262     ||_x==_t[5]||_x==_t[6])
00263 
00264 
00265 network_t nets_1918[] = {
00266     {"10.0.0.0",    0, 0xffffffffu << 24},
00267     {"172.16.0.0",  0, 0xffffffffu << 20},
00268     {"192.168.0.0", 0, 0xffffffffu << 16},
00269     {NULL, 0, 0}
00270 };
00271 
00272 
00278 int is1918addr(str *saddr) {
00279     struct in_addr addr;
00280     uint32_t netaddr;
00281     int i, rval;
00282     char backup;
00283 
00284     rval = -1;
00285     backup = saddr->s[saddr->len];
00286     saddr->s[saddr->len] = '\0';
00287     if (inet_aton(saddr->s, &addr) != 1)
00288         goto is1918addr_end;
00289     netaddr = ntohl(addr.s_addr);
00290     for (i = 0; nets_1918[i].cnetaddr != NULL; i++) {
00291         if ((netaddr & nets_1918[i].mask) == nets_1918[i].netaddr) {
00292             rval = 1;
00293             goto is1918addr_end;
00294         }
00295     }
00296     rval = 0;
00297 
00298 is1918addr_end:
00299     saddr->s[saddr->len] = backup;
00300     return rval;
00301 }
00302 
00303 
00309 char * ser_memmem(const void *b1, const void *b2, size_t len1, size_t len2)
00310 {
00311     /* Initialize search pointer */
00312     char *sp = (char *) b1;
00313 
00314     /* Initialize pattern pointer */
00315     char *pp = (char *) b2;
00316 
00317     /* Initialize end of search address space pointer */
00318     char *eos = sp + len1 - len2;
00319 
00320     /* Sanity check */
00321     if(!(b1 && b2 && len1 && len2))
00322         return NULL;
00323 
00324     while (sp <= eos) {
00325         if (*sp == *pp)
00326             if (memcmp(sp, pp, len2) == 0)
00327                 return sp;
00328 
00329             sp++;
00330     }
00331 
00332     return NULL;
00333 }
00334 
00338 int nat_prepare_1918addr() {
00339     int i;
00340     struct in_addr addr;
00341     
00342     /* Prepare 1918 networks list */
00343     for (i = 0; nets_1918[i].cnetaddr != NULL; i++) {
00344         if (inet_aton(nets_1918[i].cnetaddr, &addr) != 1)
00345             abort();
00346         nets_1918[i].netaddr = ntohl(addr.s_addr) & nets_1918[i].mask;
00347     }
00348     return 1;
00349 }
00350 
00358 static inline int get_contact_uri(struct sip_msg* _m, struct sip_uri *uri, contact_t** _c)
00359 {
00360 
00361     if ((parse_headers(_m, HDR_CONTACT_F, 0) == -1) || !_m->contact)
00362         return -1;
00363     if (!_m->contact->parsed && parse_contact(_m->contact) < 0) {
00364         LOG(L_ERR, "get_contact_uri: Error while parsing Contact body\n");
00365         return -1;
00366     }
00367     *_c = ((contact_body_t*)_m->contact->parsed)->contacts;
00368     if (*_c == NULL) {
00369         LOG(L_DBG, "get_contact_uri: Error while parsing Contact body or star contact\n");
00370         return -1;
00371     }
00372     if (parse_uri((*_c)->uri.s, (*_c)->uri.len, uri) < 0 || uri->host.len <= 0) {
00373         LOG(L_ERR, "get_contact_uri: Error while parsing Contact URI\n");
00374         return -1;
00375     }
00376     return 0;
00377 }
00378 
00380 // * Checks if the contact in the message is a 1918 address
00381 // * @param msg - the SIP message
00382 // * @returns 1 if it is, 0 if not, -1 on not found
00383 // */
00384 //static int contact_1918(struct sip_msg * msg) {
00385 //  struct sip_uri uri;
00386 //  contact_t * c;
00387 //  
00388 //  if(get_contact_uri(msg, &uri, &c) == -1)
00389 //      return -1;
00390 //  
00391 //  return (is1918addr(&(uri.host)) == 1)?1:0; 
00392 //}
00393 
00399 static int via_1918(struct sip_msg * msg) {
00400     return (is1918addr(&(msg->via1->host)) == 1) ? 1 : 0;
00401 }
00402 
00408 int nat_uac_test(struct sip_msg * msg) {
00409 
00410     if(pcscf_nat_pingall)
00411         return 1;
00412         
00413     if((pcscf_nat_detection_type && NAT_UAC_TEST_RPORT) && 
00414         (msg->rcv.src_port != (msg-> via1->port ? msg->via1->port:SIP_PORT)))
00415         return 1;
00416     
00417     if((pcscf_nat_detection_type & NAT_UAC_TEST_RCVD) && received_test(msg))
00418         return 1;
00419     
00420 //  if((pcscf_nat_detection_type & NAT_UAC_TEST_C_1918) && contact_1918(msg))
00421         //return 1;
00422     
00423 //  if((pcscf_nat_detection_type & NAT_UAC_TEST_S_1918) && sdp_1918(msg))
00424 //      return 1;
00425         
00426     if((pcscf_nat_detection_type & NAT_UAC_TEST_V_1918) && via_1918(msg))
00427         return 1;
00428     
00429     return 0;
00430 }
00431 
00438 r_nat_dest* nat_msg_origin(struct sip_msg * msg) {
00439     r_nat_dest *pinhole=NULL;
00440     if (!pcscf_nat_enable) return NULL;
00441     if(pcscf_nat_pingall || nat_uac_test(msg)) {
00442         pinhole = shm_malloc(sizeof(r_nat_dest));
00443         if (pinhole == NULL) {
00444             LOG(L_ERR,"ERR:"M_NAME":nat_msg_origin:no memory\n");
00445             return NULL;
00446         }
00447         memcpy(&pinhole->nat_addr, &msg->rcv.src_ip, sizeof(struct ip_addr));
00448         pinhole -> nat_port = msg -> rcv.src_port;
00449     }
00450     return pinhole;
00451 }
00452 
00458 int requires_nat(struct sip_msg * msg) 
00459 {
00460     return pcscf_nat_enable && (pcscf_nat_pingall || nat_uac_test(msg));
00461 }
00462 
00463 
00469 int nat_send_ping(r_contact *c) {
00470     struct dest_info dst;
00471     
00472     if(c->pinhole == NULL)
00473         return 1;
00474     if(c->transport != PROTO_UDP && c->transport != PROTO_NONE)
00475         return 1;
00476     init_dest_info(&dst);
00477     dst.proto = PROTO_UDP;
00478     
00479     memset(&(dst.to), 0, sizeof(union sockaddr_union));
00480     dst.to.s.sa_family=c->pinhole->nat_addr.af;
00481     switch(dst.to.s.sa_family) {
00482         case AF_INET6:
00483             memcpy(&dst.to.sin6.sin6_addr, c->pinhole->nat_addr.u.addr, c->pinhole->nat_addr.len);
00484             //dst.to.sin6.sin6_len=sizeof(struct sockaddr_in6);
00485             dst.to.sin6.sin6_port=htons(c->pinhole->nat_port);
00486             break;
00487         case AF_INET:
00488             memcpy(&dst.to.sin.sin_addr, c->pinhole->nat_addr.u.addr, c->pinhole->nat_addr.len);
00489             //dst.to.sin.sin_len=sizeof(struct sockaddr_in);
00490             dst.to.sin.sin_port=htons(c->pinhole->nat_port);
00491             break;
00492         default:
00493             LOG(L_CRIT,"CRIT:"M_NAME":nat_send_ping: unknown address family %d\n", dst.to.s.sa_family);
00494             return -1;
00495     }
00496     dst.send_sock=get_send_socket(0, &dst.to, PROTO_UDP);
00497     if(dst.send_sock == NULL) {
00498         LOG(L_ERR,"ERR:"M_NAME":nat_send_ping: cannot get sending socket\n");
00499         return -1;
00500     }
00501     udp_send(&dst, (char *)udp_ping, sizeof(udp_ping));
00502     return 1; 
00503 }

Generated on Thu Oct 23 04:14:38 2008 for Open IMS Core CSCFs by  doxygen 1.5.2