⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nathelper.c

📁 用来作为linux中SIP SERVER,完成VOIP网络电话中服务器的功能
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: nathelper.c,v 1.67.2.5 2005/07/20 17:11:51 andrei Exp $ * * Copyright (C) 2003 Porta Software Ltd * * This file is part of ser, a free SIP server. * * ser 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 * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: *    info@iptel.org * * ser 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) * */#include "nhelpr_funcs.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 "../registrar/sip_msg.h"#include "../../msg_translator.h"#include "../usrloc/usrloc.h"#include "../../usr_avp.h"#include "../../socket_info.h"#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>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)	{(ix).iov_base = (sx).s; (ix).iov_len = (sx).len;}/* Supported version of the RTP proxy command protocol */#define	SUP_CPROTOVER	20040107#define	CPORT		"22222"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 *);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(int, int);static char *send_rtpp_command(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 add_rcv_param_f(struct sip_msg *, char *, char *);static void 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}};/* * 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";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 int umode = 0;static int controlfd;static pid_t mypid;static unsigned int myseqn = 0;static int rcv_avp_no=42;static cmd_export_t cmds[] = {	{"fix_nated_contact",  fix_nated_contact_f,    0, 0,             REQUEST_ROUTE | ONREPLY_ROUTE },	{"fix_nated_sdp",      fix_nated_sdp_f,        1, fixup_str2int, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },	{"unforce_rtp_proxy",  unforce_rtp_proxy_f,    0, 0,             REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },	{"force_rtp_proxy",    force_rtp_proxy0_f,     0, 0,             REQUEST_ROUTE | ONREPLY_ROUTE },	{"force_rtp_proxy",    force_rtp_proxy1_f,     1, 0,             REQUEST_ROUTE | ONREPLY_ROUTE },	{"force_rtp_proxy",    force_rtp_proxy2_f,     2, 0,             REQUEST_ROUTE | ONREPLY_ROUTE },	{"nat_uac_test",       nat_uac_test_f,         1, fixup_str2int, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },	{"fix_nated_register", fix_nated_register_f,   0, 0,             REQUEST_ROUTE },	{"add_rcv_param",      add_rcv_param_f,        0, 0,             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		},	{0, 0, 0}};struct module_exports exports = {	"nathelper",	cmds,	params,	mod_init,	0, /* reply processing */	0, /* destroy function */	0, /* on_break */	child_init};static intmod_init(void){	int i;	char *cp;	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, "nathelper: Can't find usrloc module\n"); 			return -1; 		}		if (bind_usrloc(&ul) < 0) {			return -1;		}		register_timer(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;	}	if (rtpproxy_disable == 0) {		/* Make rtpproxy_sock writable */		cp = pkg_malloc(strlen(rtpproxy_sock) + 1);		if (cp == NULL) {			LOG(L_ERR, "nathelper: Can't allocate memory\n");			return -1;		}		strcpy(cp, rtpproxy_sock);		rtpproxy_sock = cp;		if (strncmp(rtpproxy_sock, "udp:", 4) == 0) {			umode = 1;			rtpproxy_sock += 4;		} else if (strncmp(rtpproxy_sock, "udp6:", 5) == 0) {			umode = 6;			rtpproxy_sock += 5;		} else if (strncmp(rtpproxy_sock, "unix:", 5) == 0) {			umode = 0;			rtpproxy_sock += 5;		}	}	return 0;}static intchild_init(int rank){	int n;	char *cp;	struct addrinfo hints, *res;	if (rtpproxy_disable == 0) {		mypid = getpid();		if (umode != 0) {			cp = strrchr(rtpproxy_sock, ':');			if (cp != NULL) {				*cp = '\0';				cp++;			}			if (cp == NULL || *cp == '\0')				cp = CPORT;			memset(&hints, 0, sizeof(hints));			hints.ai_flags = 0;			hints.ai_family = (umode == 6) ? AF_INET6 : AF_INET;			hints.ai_socktype = SOCK_DGRAM;			if ((n = getaddrinfo(rtpproxy_sock, cp, &hints, &res)) != 0) {				LOG(L_ERR, "nathelper: getaddrinfo: %s\n", gai_strerror(n));				return -1;			}			controlfd = socket((umode == 6) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);			if (controlfd == -1) {				LOG(L_ERR, "nathelper: can't create socket\n");				freeaddrinfo(res);				return -1;			}			if (connect(controlfd, res->ai_addr, res->ai_addrlen) == -1) {				LOG(L_ERR, "nathelper: can't connect to a RTP proxy\n");				close(controlfd);				freeaddrinfo(res);				return -1;			}			freeaddrinfo(res);		}		rtpproxy_disable = rtpp_test(0, 1);	} else {		rtpproxy_disable_tout = -1;	}	return 0;}static intisnulladdr(str *sx, int pf){	char *cp;	if (pf == AF_INET6) {		for(cp = sx->s; cp < sx->s + sx->len; cp++)			if (*cp != '0' && *cp != ':')				return 0;		return 1;	}	return (sx->len == 7 && memcmp("0.0.0.0", sx->s, 7) == 0);}/* * ser_memmem() returns the location of the first occurrence of data * pattern b2 of size len2 in memory block b1 of size len1 or * NULL if none is found. Obtained from NetBSD. */static void *ser_memmem(const void *b1, const void *b2, size_t len1, size_t len2){	/* Initialize search pointer */	char *sp = (char *) b1;	/* Initialize pattern pointer */	char *pp = (char *) b2;	/* Initialize end of search address space pointer */	char *eos = sp + len1 - len2;	/* Sanity check */	if(!(b1 && b2 && len1 && len2))		return NULL;	while (sp <= eos) {		if (*sp == *pp)			if (memcmp(sp, pp, len2) == 0)				return sp;			sp++;	}	return NULL;}/* * Some helper functions taken verbatim from tm module. *//* * Extract tag from To header field of a response * assumes the to header is already parsed, so * make sure it really is before calling this function */static inline intget_to_tag(struct sip_msg* _m, str* _tag){	if (!_m->to) {		LOG(L_ERR, "get_to_tag(): To header field missing\n");		return -1;	}	if (get_to(_m)->tag_value.len) {		_tag->s = get_to(_m)->tag_value.s;		_tag->len = get_to(_m)->tag_value.len;	} else {		_tag->s = 0; /* fixes gcc 4.0 warnings */		_tag->len = 0;	}	return 0;}/* * Extract tag from From header field of a request */static inline intget_from_tag(struct sip_msg* _m, str* _tag){	if (parse_from_header(_m) == -1) {		LOG(L_ERR, "get_from_tag(): Error while parsing From header\n");		return -1;	}	if (get_from(_m)->tag_value.len) {		_tag->s = get_from(_m)->tag_value.s;		_tag->len = get_from(_m)->tag_value.len;	} else {		_tag->len = 0;	}	return 0;}/* * Extract Call-ID value * assumes the callid header is already parsed * (so make sure it is, before calling this function or *  it might fail even if the message _has_ a callid) */static inline intget_callid(struct sip_msg* _m, str* _cid){	if ((parse_headers(_m, HDR_CALLID, 0) == -1)) {		LOG(L_ERR, "get_callid(): parse_headers() failed\n");		return -1;	}	if (_m->callid == NULL) {		LOG(L_ERR, "get_callid(): Call-ID not found\n");		return -1;	}	_cid->s = _m->callid->body.s;	_cid->len = _m->callid->body.len;	trim(_cid);	return 0;}/* * Extract URI from the Contact header field */static inline intget_contact_uri(struct sip_msg* _m, struct sip_uri *uri, contact_t** _c){	if ((parse_headers(_m, HDR_CONTACT, 0) == -1) || !_m->contact)		return -1;	if (!_m->contact->parsed && parse_contact(_m->contact) < 0) {		LOG(L_ERR, "get_contact_uri: Error while parsing Contact body\n");		return -1;	}	*_c = ((contact_body_t*)_m->contact->parsed)->contacts;	if (*_c == NULL) {		LOG(L_ERR, "get_contact_uri: Error while parsing Contact body\n");		return -1;	}	if (parse_uri((*_c)->uri.s, (*_c)->uri.len, uri) < 0 || uri->host.len <= 0) {		LOG(L_ERR, "get_contact_uri: Error while parsing Contact URI\n");		return -1;	}	return 0;}/* * Replaces ip:port pair in the Contact: field with the source address * of the packet. */static intfix_nated_contact_f(struct sip_msg* msg, char* str1, char* str2){	int offset, len, len1;	char *cp, *buf, temp[2];	contact_t* c;	struct lump* anchor;	struct sip_uri uri;	str hostport;	if (get_contact_uri(msg, &uri, &c) == -1)		return -1;	if (uri.proto != PROTO_UDP && uri.proto != PROTO_NONE)		return -1;	if ((c->uri.s < msg->buf) || (c->uri.s > (msg->buf + msg->len))) {		LOG(L_ERR, "ERROR: you can't call fix_nated_contact twice, "		    "check your config!\n");		return -1;	}	offset = c->uri.s - msg->buf;	anchor = del_lump(msg, offset, c->uri.len, HDR_CONTACT);	if (anchor == 0)		return -1;	hostport = uri.host;	if (uri.port.len > 0)		hostport.len = uri.port.s + uri.port.len - uri.host.s;	cp = ip_addr2a(&msg->rcv.src_ip);	len = c->uri.len + strlen(cp) + 6 /* :port */ - hostport.len + 1;	buf = pkg_malloc(len);	if (buf == NULL) {		LOG(L_ERR, "ERROR: fix_nated_contact: out of memory\n");		return -1;	}	temp[0] = hostport.s[0];	temp[1] = c->uri.s[c->uri.len];	c->uri.s[c->uri.len] = hostport.s[0] = '\0';	len1 = snprintf(buf, len, "%s%s:%d%s", c->uri.s, cp, msg->rcv.src_port,	    hostport.s + hostport.len);	if (len1 < len)		len = len1;	hostport.s[0] = temp[0];	c->uri.s[c->uri.len] = temp[1];	if (insert_new_lump_after(anchor, buf, len, HDR_CONTACT) == 0) {		pkg_free(buf);		return -1;	}	c->uri.s = buf;	c->uri.len = len;	return 1;}inline static intfixup_str2int( void** param, int param_no){	unsigned long go_to;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -