📄 nathelper.c
字号:
/* $Id: nathelper.c,v 1.21 2006/06/07 13:52:44 bogdan_iancu Exp $ * * Copyright (C) 2003 Porta Software Ltd * * This file is part of openser, a free SIP server. * * openser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * openser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * --------- * 2003-10-09 nat_uac_test introduced (jiri) * * 2003-11-06 nat_uac_test permitted from onreply_route (jiri) * * 2003-12-01 unforce_rtp_proxy introduced (sobomax) * * 2004-01-07 RTP proxy support updated to support new version of the * RTP proxy (20040107). * * force_rtp_proxy() now inserts a special flag * into the SDP body to indicate that this session already * proxied and ignores sessions with such flag. * * Added run-time check for version of command protocol * supported by the RTP proxy. * * 2004-01-16 Integrated slightly modified patch from Tristan Colgate, * force_rtp_proxy function with IP as a parameter (janakj) * * 2004-01-28 nat_uac_test extended to allow testing SDP body (sobomax) * * nat_uac_test extended to allow testing top Via (sobomax) * * 2004-02-21 force_rtp_proxy now accepts option argument, which * consists of string of chars, each of them turns "on" * some feature, currently supported ones are: * * `a' - flags that UA from which message is received * doesn't support symmetric RTP; * `l' - force "lookup", that is, only rewrite SDP when * corresponding session is already exists in the * RTP proxy. Only makes sense for SIP requests, * replies are always processed in "lookup" mode; * `i' - flags that message is received from UA in the * LAN. Only makes sense when RTP proxy is running * in the bridge mode. * * force_rtp_proxy can now be invoked without any arguments, * as previously, with one argument - in this case argument * is treated as option string and with two arguments, in * which case 1st argument is option string and the 2nd * one is IP address which have to be inserted into * SDP (IP address on which RTP proxy listens). * * 2004-03-12 Added support for IPv6 addresses in SDPs. Particularly, * force_rtp_proxy now can work with IPv6-aware RTP proxy, * replacing IPv4 address in SDP with IPv6 one and vice versa. * This allows creating full-fledged IPv4<->IPv6 gateway. * See 4to6.cfg file for example. * * Two new options added into force_rtp_proxy: * * `f' - instructs nathelper to ignore marks inserted * by another nathelper in transit to indicate * that the session is already goes through another * proxy. Allows creating chain of proxies. * `r' - flags that IP address in SDP should be trusted. * Without this flag, nathelper ignores address in the * SDP and uses source address of the SIP message * as media address which is passed to the RTP proxy. * * Protocol between nathelper and RTP proxy in bridge * mode has been slightly changed. Now RTP proxy expects SER * to provide 2 flags when creating or updating session * to indicate direction of this session. Each of those * flags can be either `e' or `i'. For example `ei' means * that we received INVITE from UA on the "external" network * network and will send it to the UA on "internal" one. * Also possible `ie' (internal->external), `ii' * (internal->internal) and `ee' (external->external). See * example file alg.cfg for details. * * 2004-03-15 If the rtp proxy test failed (wrong version or not started) * retry test from time to time, when some *rtpproxy* function * is invoked. Minimum interval between retries can be * configured via rtpproxy_disable_tout module parameter (default * is 60 seconds). Setting it to -1 will disable periodic * rechecks completely, setting it to 0 will force checks * for each *rtpproxy* function call. (andrei) * * 2004-03-22 Fix assignment of rtpproxy_retr and rtpproxy_tout module * parameters. * * 2004-03-22 Fix get_body position (should be called before get_callid) * (andrei) * * 2004-03-24 Fix newport for null ip address case (e.g onhold re-INVITE) * (andrei) * * 2004-09-30 added received port != via port test (andrei) * * 2004-10-10 force_socket option introduced (jiri) * * 2005-02-24 Added support for using more than one rtp proxy, in which * case traffic will be distributed evenly among them. In addition, * each such proxy can be assigned a weight, which will specify * which share of the traffic should be placed to this particular * proxy. * * Introduce failover mechanism, so that if SER detects that one * of many proxies is no longer available it temporarily decreases * its weight to 0, so that no traffic will be assigned to it. * Such "disabled" proxies are periodically checked to see if they * are back to normal in which case respective weight is restored * resulting in traffic being sent to that proxy again. * * Those features can be enabled by specifying more than one "URI" * in the rtpproxy_sock parameter, optionally followed by the weight, * which if absent is assumed to be 1, for example: * * rtpproxy_sock="unix:/foo/bar=4 udp:1.2.3.4:3456=3 udp:5.6.7.8:5432=1" * * 2005-02-25 Force for pinging the socket returned by USRLOC (bogdan) * * 2005-03-22 support for multiple media streams added (netch) * * 2005-07-11 SIP ping support added (bogdan) * * 2005-07-14 SDP origin (o=) IP may be also changed (bogdan) * * 2006-03-08 fix_nated_sdp() may take one more param to force a specific IP; * force_rtp_proxy() accepts a new flag 's' to swap creation/ * confirmation between requests/replies; * add_rcv_param() may take as parameter a flag telling if the * parameter should go to the contact URI or contact header; * (bogdan) * 2006-03-28 Support for changing session-level SDP connection (c=) IP when * media-description also includes connection information (bayan) */#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/uio.h>#include <sys/un.h>#include <ctype.h>#include <errno.h>#include <netdb.h>#include <poll.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "../../flags.h"#include "../../sr_module.h"#include "../../dprint.h"#include "../../data_lump.h"#include "../../data_lump_rpl.h"#include "../../error.h"#include "../../forward.h"#include "../../mem/mem.h"#include "../../parser/parse_from.h"#include "../../parser/parse_to.h"#include "../../parser/parse_uri.h"#include "../../parser/parser_f.h"#include "../../resolve.h"#include "../../timer.h"#include "../../trim.h"#include "../../ut.h"#include "../../items.h"#include "../../msg_translator.h"#include "../../usr_avp.h"#include "../../socket_info.h"#include "../registrar/sip_msg.h"#include "../usrloc/usrloc.h"#include "nhelpr_funcs.h"#include "sip_pinger.h" MODULE_VERSION#if !defined(AF_LOCAL)#define AF_LOCAL AF_UNIX#endif#if !defined(PF_LOCAL)#define PF_LOCAL PF_UNIX#endif/* NAT UAC test constants */#define NAT_UAC_TEST_C_1918 0x01#define NAT_UAC_TEST_RCVD 0x02#define NAT_UAC_TEST_V_1918 0x04#define NAT_UAC_TEST_S_1918 0x08#define NAT_UAC_TEST_RPORT 0x10/* Handy macros */#define STR2IOVEC(sx, ix) do {(ix).iov_base = (sx).s; (ix).iov_len = (sx).len;} while(0)#define SZ2IOVEC(sx, ix) do {(ix).iov_base = (sx); (ix).iov_len = strlen(sx);} while(0)/* Supported version of the RTP proxy command protocol */#define SUP_CPROTOVER 20040107/* Required additional version of the RTP proxy command protocol */#define REQ_CPROTOVER "20050322"#define CPORT "22222"struct rtpp_head;struct rtpp_node;static int nat_uac_test_f(struct sip_msg* msg, char* str1, char* str2);static int fix_nated_contact_f(struct sip_msg *, char *, char *);static int fix_nated_sdp_f(struct sip_msg *, char *, char *);static int extract_mediaip(str *, str *, int *, char *);static int extract_mediaport(str *, str *);static int alter_mediaip(struct sip_msg *, str *, str *, int, str *, int, int);static int alter_mediaport(struct sip_msg *, str *, str *, str *, int);static char *gencookie();static int rtpp_test(struct rtpp_node*, int, int);static char *send_rtpp_command(struct rtpp_node*, struct iovec *, int);static int unforce_rtp_proxy_f(struct sip_msg *, char *, char *);static int force_rtp_proxy0_f(struct sip_msg *, char *, char *);static int force_rtp_proxy1_f(struct sip_msg *, char *, char *);static int force_rtp_proxy2_f(struct sip_msg *, char *, char *);static int fix_nated_register_f(struct sip_msg *, char *, char *);static int fixup_fix_sdp(void** param, int param_no);static int add_rcv_param_f(struct sip_msg *, char *, char *);static char *find_sdp_line(char *, char *, char);static char *find_next_sdp_line(char *, char *, char, char *);static void nh_timer(unsigned int, void *);inline static int fixup_str2int(void**, int);static int mod_init(void);static int child_init(int);static usrloc_api_t ul;static int cblen = 0;static int natping_interval = 0;struct socket_info* force_socket = 0;static struct { const char *cnetaddr; uint32_t netaddr; uint32_t mask;} nets_1918[] = { {"10.0.0.0", 0, 0xffffffffu << 24}, {"172.16.0.0", 0, 0xffffffffu << 20}, {"192.168.0.0", 0, 0xffffffffu << 16}, {NULL, 0, 0}};static str sup_ptypes[] = { {.s = "udp", .len = 3}, {.s = "udptl", .len = 5}, {.s = "rtp/avp", .len = 7}, {.s = NULL, .len = 0}};/* * If this parameter is set then the natpinger will ping only contacts * that have the NAT flag set in user location database */static int ping_nated_only = 0;static const char sbuf[4] = {0, 0, 0, 0};static char *rtpproxy_sock = "unix:/var/run/rtpproxy.sock"; /* list */static char *force_socket_str = 0;static int rtpproxy_disable = 0;static int rtpproxy_disable_tout = 60;static int rtpproxy_retr = 5;static int rtpproxy_tout = 1;static pid_t mypid;static unsigned int myseqn = 0;static int rcv_avp_no = 42;struct rtpp_head { struct rtpp_node *rn_first; struct rtpp_node *rn_last;};struct rtpp_node { char *rn_url; /* unparsed, deletable */ int rn_umode; char *rn_address; /* substring of rn_url */ int rn_fd; /* control fd */ int rn_disabled; /* found unaccessible? */ unsigned rn_weight; /* for load balancing */ int rn_recheck_ticks; struct rtpp_node *rn_next;};/* RTP proxy balancing list */static struct rtpp_head rtpp_list;static int rtpp_node_count = 0;static cmd_export_t cmds[] = { {"fix_nated_contact", fix_nated_contact_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE}, {"fix_nated_sdp", fix_nated_sdp_f, 1, fixup_fix_sdp, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE}, {"fix_nated_sdp", fix_nated_sdp_f, 2, fixup_fix_sdp, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE}, {"unforce_rtp_proxy", unforce_rtp_proxy_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE}, {"force_rtp_proxy", force_rtp_proxy0_f, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE}, {"force_rtp_proxy", force_rtp_proxy1_f, 1, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE}, {"force_rtp_proxy", force_rtp_proxy2_f, 2, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE}, {"nat_uac_test", nat_uac_test_f, 1, fixup_str2int, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE}, {"fix_nated_register", fix_nated_register_f, 0, 0, REQUEST_ROUTE }, {"add_rcv_param", add_rcv_param_f, 0, 0, REQUEST_ROUTE }, {"add_rcv_param", add_rcv_param_f, 1, fixup_str2int, REQUEST_ROUTE }, {0, 0, 0, 0, 0}};static param_export_t params[] = { {"natping_interval", INT_PARAM, &natping_interval }, {"ping_nated_only", INT_PARAM, &ping_nated_only }, {"rtpproxy_sock", STR_PARAM, &rtpproxy_sock }, {"rtpproxy_disable", INT_PARAM, &rtpproxy_disable }, {"rtpproxy_disable_tout", INT_PARAM, &rtpproxy_disable_tout }, {"rtpproxy_retr", INT_PARAM, &rtpproxy_retr }, {"rtpproxy_tout", INT_PARAM, &rtpproxy_tout }, {"received_avp", INT_PARAM, &rcv_avp_no }, {"force_socket", STR_PARAM, &force_socket_str }, {"sipping_from", STR_PARAM, &sipping_from.s }, {"sipping_method", STR_PARAM, &sipping_method.s }, {0, 0, 0}};struct module_exports exports = { "nathelper", cmds, params, 0, /* exported statistics */ mod_init, 0, /* reply processing */ 0, /* destroy function */ child_init};static intfixup_fix_sdp(void** param, int param_no){ xl_elem_t *model; if (param_no==1) { /* flags */ return fixup_str2int( param, param_no); } /* new IP */ model=NULL; if(xl_parse_format((char*)(*param),&model,XL_DISABLE_COLORS)<0) { LOG(L_ERR, "ERROR:nathelper:fixup_fix_sdp: wrong format[%s]!\n", (char*)(*param)); return E_UNSPEC; } if (model==NULL) { LOG(L_ERR, "ERROR:nathelper:fixup_fix_sdp: empty parameter!\n"); return E_UNSPEC; } *param = (void*)model; return 0;}static intmod_init(void){ int i; bind_usrloc_t bind_usrloc; struct in_addr addr; str socket_str; if (force_socket_str) { socket_str.s=force_socket_str; socket_str.len=strlen(socket_str.s); force_socket=grep_sock_info(&socket_str,0,0); } if (natping_interval > 0) { bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LOG(L_ERR, "ERROR:nathelper:mod_init: Can't find usrloc module\n"); return -1; } if (bind_usrloc(&ul) < 0) { return -1; } /* set reply function if SIP natping is enabled */ if (sipping_from.s && sipping_from.s[0]) { if (sipping_method.s==0 || sipping_method.s[0]==0) { LOG(L_ERR,"ERROR:nathelper:mod_init: SIP ping FROM set, but " "SIP ping method is empty!\n"); return -1; } sipping_method.len = strlen(sipping_method.s); sipping_from.len = strlen(sipping_from.s); exports.response_f = sipping_rpl_filter; init_sip_ping(); } else { sipping_from.s = 0; } register_timer(nh_timer, NULL, natping_interval); } /* Prepare 1918 networks list */ for (i = 0; nets_1918[i].cnetaddr != NULL; i++) { if (inet_aton(nets_1918[i].cnetaddr, &addr) != 1) abort(); nets_1918[i].netaddr = ntohl(addr.s_addr) & nets_1918[i].mask; } memset(&rtpp_list, 0, sizeof(rtpp_list)); rtpp_node_count = 0; if (rtpproxy_disable == 0) { /* Make rtp proxies list. */ char *p, *p1, *p2, *plim; p = rtpproxy_sock; plim = p + strlen(p); for(;;) { struct rtpp_node *pnode; int weight; weight = 1; while (*p && isspace((int)*p)) ++p; if (p >= plim) break; p1 = p; while (*p && !isspace((int)*p)) ++p; if (p <= p1) break; /* may happen??? */ /* Have weight specified? If yes, scan it */ p2 = memchr(p1, '=', p - p1); if (p2 != NULL) { weight = strtoul(p2 + 1, NULL, 10); } else { p2 = p; } pnode = pkg_malloc(sizeof(struct rtpp_node)); if (pnode == NULL) { LOG(L_ERR, "nathelper: Can't allocate memory\n"); return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -