mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	Add RFC 3327 Path header support to chan_sip
This patch adds support for RFC 3327 "Path" headers. This can be enabled in sip.conf using the 'supportpath' setting, either on a global basis or on a peer basis. This setting enables Asterisk to route outgoing out-of-dialog requests via a set of proxies by using a pre-loaded route-set defined by the Path headers in the REGISTER request. This patch also adds Realtime support for dynamically updating the Path information for a peer. A huge thank-you to Klaus Darillion and Olle E Johansson for their efforts in writing this patch. Review: https://reviewboard.asterisk.org/r/2235/ Review: https://reviewboard.asterisk.org/r/991/ (closes issue ASTERISK-16884) Reported by: klaus3000 Tested by: klaus3000, oej, mjordan patches: path-1.8.0-patch.txt uploaded by klaus3000 (License 5054) oolong-path-support-trunk in team branch by oej (License 5267) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@382440 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		
							
								
								
									
										16
									
								
								CHANGES
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								CHANGES
									
									
									
									
									
								
							| @@ -50,6 +50,13 @@ chan_mobile | ||||
|  | ||||
|  * Added ECAM command support for Sony Ericsson phones. | ||||
|  | ||||
| chan_sip | ||||
| ------------------ | ||||
|  * Added support for RFC 3327 "Path" headers. This can be enabled in sip.conf | ||||
|    using the 'supportpath' setting, either on a global basis or on a peer basis. | ||||
|    This setting enables Asterisk to route outgoing out-of-dialog requests via a | ||||
|    set of proxies by using a pre-loaded route-set defined by the Path headers in | ||||
|    the REGISTER request. See Realtime updates for more configuration information. | ||||
|  | ||||
| Features | ||||
| ------------------- | ||||
| @@ -95,6 +102,15 @@ Core | ||||
|    reason to any string. It also allows for custom strings to be read as the | ||||
|    redirecting reason from SIP Diversion headers. | ||||
|  | ||||
| Realtime | ||||
| ------------------ | ||||
|  * Dynamic realtime tables for SIP Users can now include a 'path' field. This | ||||
|    will store the path information for that peer when it registers. Realtime | ||||
|    tables can also use the 'supportpath' field to enable Path header support. | ||||
|  | ||||
|  * LDAP realtime configurations for SIP Users now have the AstAccountPathSupport | ||||
|    objectIdentifier. This maps to the supportpath option in sip.conf.  | ||||
|  | ||||
| ------------------------------------------------------------------------------ | ||||
| --- Functionality changes from Asterisk 10 to Asterisk 11 -------------------- | ||||
| ------------------------------------------------------------------------------ | ||||
|   | ||||
							
								
								
									
										12
									
								
								CREDITS
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								CREDITS
									
									
									
									
									
								
							| @@ -22,7 +22,7 @@ | ||||
| 	* John Todd, TalkPlus, Inc.  and JR Richardson, Ntegrated Solutions.  | ||||
| 		for funding the development of SIP Session Timers support. | ||||
|  | ||||
| 	* Omnitor AB, Gunnar Hellstr<74>m, for funding work with videocaps,  | ||||
| 	* Omnitor AB, Gunnar Hellstr<74>m, for funding work with videocaps,  | ||||
| 		T.140 RED, originate with video/text and many more  | ||||
| 		contributions. | ||||
|  | ||||
| @@ -54,7 +54,7 @@ | ||||
|  | ||||
| === HARDWARE DONORS ===  | ||||
|  | ||||
|  We'd like to thank the followwing for granting access to hardware for testing. | ||||
|  We'd like to thank the following for granting access to hardware for testing. | ||||
|  | ||||
| 	* Thanks to QuickNet Technologies for their donation of an Internet | ||||
| 		PhoneJack and Linejack card to the project.   | ||||
| @@ -63,13 +63,12 @@ | ||||
| 	* Thanks to VoipSupply for their donation of Sipura ATAs to the project | ||||
| 		for T.38 testing. (http://www.voipsupply.com) | ||||
|  | ||||
|  | ||||
| 	* Thanks to Grandstream for their donation of ATAs to the project for | ||||
| 		T.38 testing. (http://www.grandstream.com) | ||||
|  | ||||
| === MISCELLANEOUS PATCHES === | ||||
|  | ||||
|  We'd like to thank the flollowing for their patches | ||||
|  We'd like to thank the following for their patches | ||||
|  | ||||
| 	* Jim Dixon - Zapata Telephony and app_rpt | ||||
| 		http://www.zapatatelephony.org/app_rpt.html | ||||
| @@ -240,7 +239,8 @@ | ||||
| 		ControlPlayback, and multiple bug fixes See  | ||||
| 		http://voip-info.org/users/view/sergee serg(AT)voipsolutions.ru | ||||
|  | ||||
| 	* Klaus Darillon - the SIPremoveHeader function in chan_sip | ||||
| 	* Klaus Darillon - the SIPremoveHeader function in chan_sip and SIP Path | ||||
| 		Support. | ||||
|  | ||||
| 	* Moises Silva (moy) - for writing LibOpenR2, and providing support for | ||||
| 		it in chan_dahdi moises.silva(AT)gmail.com | ||||
| @@ -252,7 +252,7 @@ | ||||
| 		cdr_tds rewrite, countless other improvements, fixes, and good | ||||
| 		ideas. sean(AT)malleable.com | ||||
|  | ||||
| 	* Jan Kal<61>b - Calendaring support for Exchange Server 2007+ via  | ||||
| 	* Jan Kal<61>b - Calendaring support for Exchange Server 2007+ via  | ||||
| 		Exchange Web Services. | ||||
|  | ||||
| 	* University of Oslo (uio.no), Norway - SIP Max-Forwards setting  | ||||
|   | ||||
| @@ -1187,6 +1187,8 @@ static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *a | ||||
| static void free_old_route(struct sip_route *route); | ||||
| static void list_route(struct sip_route *route); | ||||
| static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp); | ||||
| static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, char *pathbuf); | ||||
| static int copy_route(struct sip_route **dst, const struct sip_route *src); | ||||
| static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr, | ||||
| 					      struct sip_request *req, const char *uri); | ||||
| static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag); | ||||
| @@ -1360,7 +1362,7 @@ static void set_socket_transport(struct sip_socket *socket, int transport); | ||||
| static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags); | ||||
| 
 | ||||
| /* Realtime device support */ | ||||
| static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms); | ||||
| static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path); | ||||
| static void update_peer(struct sip_peer *p, int expire); | ||||
| static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config); | ||||
| static const char *get_name_from_variable(const struct ast_variable *var); | ||||
| @@ -1442,6 +1444,7 @@ static int add_digit(struct sip_request *req, char digit, unsigned int duration, | ||||
| static int add_rpid(struct sip_request *req, struct sip_pvt *p); | ||||
| static int add_vidupdate(struct sip_request *req); | ||||
| static void add_route(struct sip_request *req, struct sip_route *route); | ||||
| static void make_route_list(struct sip_route *route, char *r, int rem); | ||||
| static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field); | ||||
| static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field); | ||||
| static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field); | ||||
| @@ -5112,7 +5115,7 @@ static int sip_sendtext(struct ast_channel *ast, const char *text) | ||||
| 	that name and store that in the "regserver" field in the sippeers | ||||
| 	table to facilitate multi-server setups. | ||||
| */ | ||||
| static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms) | ||||
| static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *defaultuser, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path) | ||||
| { | ||||
| 	char port[10]; | ||||
| 	char ipaddr[INET6_ADDRSTRLEN]; | ||||
| @@ -5135,10 +5138,11 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr | ||||
| 	ast_copy_string(ipaddr, ast_sockaddr_isnull(addr) ? "" : ast_sockaddr_stringify_addr(addr), sizeof(ipaddr)); | ||||
| 	ast_copy_string(port, ast_sockaddr_port(addr) ? ast_sockaddr_stringify_port(addr) : "", sizeof(port)); | ||||
| 
 | ||||
| 	if (ast_strlen_zero(sysname))	/* No system name, disable this */ | ||||
| 	if (ast_strlen_zero(sysname)) {	/* No system name, disable this */ | ||||
| 		sysname = NULL; | ||||
| 	else if (sip_cfg.rtsave_sysname) | ||||
| 	} else if (sip_cfg.rtsave_sysname) { | ||||
| 		syslabel = "regserver"; | ||||
| 	} | ||||
| 
 | ||||
| 	/* XXX IMPORTANT: Anytime you add a new parameter to be updated, you
 | ||||
|          *  must also add it to contrib/scripts/asterisk.ldap-schema, | ||||
| @@ -5146,18 +5150,38 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr | ||||
|          *  and to configs/res_ldap.conf.sample as described in | ||||
|          *  bugs 15156 and 15895 | ||||
|          */ | ||||
| 	if (fc) { | ||||
| 		ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, | ||||
| 			"port", port, "regseconds", regseconds, | ||||
| 			deprecated_username ? "username" : "defaultuser", defaultuser, | ||||
| 			"useragent", useragent, "lastms", str_lastms, | ||||
| 			fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */ | ||||
| 
 | ||||
| 	/* This is ugly, we need something better ;-) */ | ||||
| 	if (sip_cfg.rtsave_path) { | ||||
| 		if (fc) { | ||||
| 			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, | ||||
| 				"port", port, "regseconds", regseconds, | ||||
| 				deprecated_username ? "username" : "defaultuser", defaultuser, | ||||
| 				"useragent", useragent, "lastms", str_lastms, | ||||
| 				"path", path,			/* Path data can be NULL */ | ||||
| 				fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */ | ||||
| 		} else { | ||||
| 			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, | ||||
| 				"port", port, "regseconds", regseconds, | ||||
| 				"useragent", useragent, "lastms", str_lastms, | ||||
| 				deprecated_username ? "username" : "defaultuser", defaultuser, | ||||
| 				"path", path,			/* Path data can be NULL */ | ||||
| 				syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */ | ||||
| 		} | ||||
| 	} else { | ||||
| 		ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, | ||||
| 			"port", port, "regseconds", regseconds, | ||||
| 			"useragent", useragent, "lastms", str_lastms, | ||||
| 			deprecated_username ? "username" : "defaultuser", defaultuser, | ||||
| 			syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */ | ||||
| 		if (fc) { | ||||
| 			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, | ||||
| 				"port", port, "regseconds", regseconds, | ||||
| 				deprecated_username ? "username" : "defaultuser", defaultuser, | ||||
| 				"useragent", useragent, "lastms", str_lastms, | ||||
| 				fc, fullcontact, syslabel, sysname, SENTINEL); /* note fc and syslabel _can_ be NULL */ | ||||
| 		} else { | ||||
| 			ast_update_realtime(tablename, "name", peername, "ipaddr", ipaddr, | ||||
| 				"port", port, "regseconds", regseconds, | ||||
| 				"useragent", useragent, "lastms", str_lastms, | ||||
| 				deprecated_username ? "username" : "defaultuser", defaultuser, | ||||
| 				syslabel, sysname, SENTINEL); /* note syslabel _can_ be NULL */ | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -5252,6 +5276,10 @@ static void sip_destroy_peer(struct sip_peer *peer) | ||||
| 		ast_variables_destroy(peer->chanvars); | ||||
| 		peer->chanvars = NULL; | ||||
| 	} | ||||
| 	if (peer->path) { | ||||
| 		free_old_route(peer->path); | ||||
| 		peer->path = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	register_peer_exten(peer, FALSE); | ||||
| 	ast_free_acl_list(peer->acl); | ||||
| @@ -5294,7 +5322,9 @@ static void update_peer(struct sip_peer *p, int expire) | ||||
| 	int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS); | ||||
| 	if (sip_cfg.peer_rtupdate && | ||||
| 	    (p->is_realtime || rtcachefriends)) { | ||||
| 		realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms); | ||||
| 		char path[SIPBUFSIZE * 2]; | ||||
| 		make_route_list(p->path, path, sizeof(path)); | ||||
| 		realtime_update_peer(p->name, &p->addr, p->username, p->fullcontact, p->useragent, expire, p->deprecated_username, p->lastms, path); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -5989,6 +6019,8 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int __set_address_from_contact(const char *fullcontact, struct ast_sockaddr *addr, int tcp); | ||||
| 
 | ||||
| /*! \brief Create address structure from peer reference.
 | ||||
|  *	This function copies data from peer to the dialog, so we don't have to look up the peer | ||||
|  *	again from memory or database during the life time of the dialog. | ||||
| @@ -6029,6 +6061,12 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) | ||||
| 	dialog->rtptimeout = peer->rtptimeout; | ||||
| 	dialog->rtpholdtimeout = peer->rtpholdtimeout; | ||||
| 	dialog->rtpkeepalive = peer->rtpkeepalive; | ||||
| 	copy_route(&dialog->route, peer->path); | ||||
| 	if (dialog->route) { | ||||
| 		/* Parse SIP URI of first route-set hop and use it as target address */ | ||||
| 		__set_address_from_contact(dialog->route->hop, &dialog->sa, dialog->socket.type == SIP_TRANSPORT_TLS ? 1 : 0); | ||||
| 	} | ||||
| 
 | ||||
| 	if (dialog_initialize_rtp(dialog)) { | ||||
| 		return -1; | ||||
| 	} | ||||
| @@ -6391,7 +6429,7 @@ static int sip_call(struct ast_channel *ast, const char *dest, int timeout) | ||||
| 	ast_clear_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38); | ||||
| 
 | ||||
| 	if (p->options->transfer) { | ||||
| 		char buf[SIPBUFSIZE/2]; | ||||
| 		char buf[SIPBUFSIZE / 2]; | ||||
| 
 | ||||
| 		if (referer) { | ||||
| 			if (sipdebug) | ||||
| @@ -11342,12 +11380,14 @@ static int process_sdp_a_image(const char *a, struct sip_pvt *p) | ||||
|  *  is supported for this dialog. */ | ||||
| static int add_supported(struct sip_pvt *pvt, struct sip_request *req) | ||||
| { | ||||
| 	char supported_value[SIPBUFSIZE]; | ||||
| 	int res; | ||||
| 	if (st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) { | ||||
| 		res = add_header(req, "Supported", "replaces, timer"); | ||||
| 	} else { | ||||
| 		res = add_header(req, "Supported", "replaces"); | ||||
| 	} | ||||
| 
 | ||||
| 	sprintf(supported_value, "replaces%s%s", | ||||
| 		(st_get_mode(pvt, 0) != SESSION_TIMER_MODE_REFUSE) ? ", timer" : "", | ||||
| 		ast_test_flag(&pvt->flags[0], SIP_USEPATH) ? ", path" : ""); | ||||
| 	res = add_header(req, "Supported", supported_value); | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| @@ -11523,12 +11563,21 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st | ||||
| /*! \brief Add route header into request per learned route */ | ||||
| static void add_route(struct sip_request *req, struct sip_route *route) | ||||
| { | ||||
| 	char r[SIPBUFSIZE*2], *p; | ||||
| 	int n, rem = sizeof(r); | ||||
| 	char r[SIPBUFSIZE * 2]; | ||||
| 
 | ||||
| 	if (!route) | ||||
| 		return; | ||||
| 
 | ||||
| 	make_route_list(route, r, sizeof(r)); | ||||
| 	add_header(req, "Route", r); | ||||
| } | ||||
| 
 | ||||
| /*! \brief Make the comma separated list of route headers from the route list */ | ||||
| static void make_route_list(struct sip_route *route, char *r, int rem) | ||||
| { | ||||
| 	char *p; | ||||
| 	int n; | ||||
| 
 | ||||
| 	p = r; | ||||
| 	for (;route ; route = route->next) { | ||||
| 		n = strlen(route->hop); | ||||
| @@ -11545,7 +11594,6 @@ static void add_route(struct sip_request *req, struct sip_route *route) | ||||
| 		rem -= (n+2); | ||||
| 	} | ||||
| 	*p = '\0'; | ||||
| 	add_header(req, "Route", r); | ||||
| } | ||||
| 
 | ||||
| /*! \brief Set destination from SIP URI
 | ||||
| @@ -11822,6 +11870,9 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg | ||||
| 			snprintf(contact, sizeof(contact), "%s%s%s;expires=%d", brackets ? "" : "<", contact_uri, brackets ? "" : ">", p->expiry); | ||||
| 			add_header(resp, "Contact", contact);	/* Not when we unregister */ | ||||
| 		} | ||||
| 		if (p->method == SIP_REGISTER && ast_test_flag(&p->flags[0], SIP_USEPATH)) { | ||||
| 			copy_header(resp, req, "Path"); | ||||
| 		} | ||||
| 	} else if (!ast_strlen_zero(p->our_contact) && resp_needs_contact(msg, p->method)) { | ||||
| 		add_header(resp, "Contact", p->our_contact); | ||||
| 	} | ||||
| @@ -15337,6 +15388,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * | ||||
| 	add_header(&req, "To", to); | ||||
| 	add_header(&req, "Call-ID", p->callid); | ||||
| 	add_header(&req, "CSeq", tmp); | ||||
| 	add_supported(p, &req); | ||||
| 	if (!ast_strlen_zero(global_useragent)) | ||||
| 		add_header(&req, "User-Agent", global_useragent); | ||||
| 
 | ||||
| @@ -15648,6 +15700,7 @@ static void destroy_association(struct sip_peer *peer) | ||||
| 			ast_update_realtime(tablename, "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "regserver", "", "useragent", "", "lastms", "0", SENTINEL); | ||||
| 		} else { | ||||
| 			ast_db_del("SIP/Registry", peer->name); | ||||
| 			ast_db_del("SIP/RegistryPath", peer->name); | ||||
| 			ast_db_del("SIP/PeerMethods", peer->name); | ||||
| 		} | ||||
| 	} | ||||
| @@ -15751,6 +15804,7 @@ static int sip_poke_peer_s(const void *data) | ||||
| static void reg_source_db(struct sip_peer *peer) | ||||
| { | ||||
| 	char data[256]; | ||||
| 	char path[SIPBUFSIZE * 2]; | ||||
| 	struct ast_sockaddr sa; | ||||
| 	int expire; | ||||
| 	char full_addr[128]; | ||||
| @@ -15809,6 +15863,9 @@ static void reg_source_db(struct sip_peer *peer) | ||||
| 			sip_unref_peer(peer, "remove registration ref"), | ||||
| 			sip_ref_peer(peer, "add registration ref")); | ||||
| 	register_peer_exten(peer, TRUE); | ||||
| 	if (!ast_db_get("SIP/RegistryPath", peer->name, path, sizeof(path))) { | ||||
| 		build_path(NULL, peer, NULL, path); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*! \brief Save contact header for 200 OK on INVITE */ | ||||
| @@ -16104,11 +16161,21 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st | ||||
| 		} | ||||
| 	} | ||||
| 	pvt->expiry = expire; | ||||
| 	if (!build_path(pvt, peer, req, NULL)) { | ||||
| 		/* Tell the dialog to use the Path header in the response */ | ||||
| 		ast_set2_flag(&pvt->flags[0], 1, SIP_USEPATH); | ||||
| 	} | ||||
| 	snprintf(data, sizeof(data), "%s:%d:%s:%s", ast_sockaddr_stringify(&peer->addr), | ||||
| 		 expire, peer->username, peer->fullcontact); | ||||
| 	/* We might not immediately be able to reconnect via TCP, but try caching it anyhow */ | ||||
| 	if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate) | ||||
| 	if (!peer->rt_fromcontact || !sip_cfg.peer_rtupdate) { | ||||
| 		char path[SIPBUFSIZE * 2]; | ||||
| 		if (peer->path) { | ||||
| 			make_route_list(peer->path, path, sizeof(path)); | ||||
| 			ast_db_put("SIP/RegistryPath", peer->name, path); | ||||
| 		} | ||||
| 		ast_db_put("SIP/Registry", peer->name, data); | ||||
| 	} | ||||
| 	manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Registered\r\nAddress: %s\r\n", peer->name,  ast_sockaddr_stringify(&peer->addr)); | ||||
| 
 | ||||
| 	/* Is this a new IP address for us? */ | ||||
| @@ -16144,10 +16211,10 @@ static void free_old_route(struct sip_route *route) | ||||
| static void list_route(struct sip_route *route) | ||||
| { | ||||
| 	if (!route) { | ||||
| 		ast_verbose("list_route: no route\n"); | ||||
| 		ast_verbose("list_route: no route/path\n"); | ||||
| 	} else { | ||||
| 		for (;route; route = route->next) | ||||
| 			ast_verbose("list_route: hop: <%s>\n", route->hop); | ||||
| 			ast_verbose("list_route: route/path hop: <%s>\n", route->hop); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -16277,6 +16344,134 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*! \internal \brief Create a new route
 | ||||
|  * \retval NULL on error | ||||
|  * \retval sip_route on success | ||||
|  */ | ||||
| static struct sip_route *create_route(const char *hop, struct sip_route *prev) | ||||
| { | ||||
| 	struct sip_route *route; | ||||
| 	int len; | ||||
| 
 | ||||
| 	if (ast_strlen_zero(hop)) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	len = strlen(hop) + 1; | ||||
| 
 | ||||
| 	/* ast_calloc is not needed because all fields are initialized in
 | ||||
| 	 * this block */ | ||||
| 	route = ast_malloc(sizeof(*route) + len); | ||||
| 	if (!route) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	ast_copy_string(route->hop, hop, len); | ||||
| 
 | ||||
| 	route->next = NULL; | ||||
| 	if (prev) { | ||||
| 		prev->next = route; | ||||
| 	} | ||||
| 	return route; | ||||
| } | ||||
| 
 | ||||
| /*! \internal \brief copy route-set
 | ||||
|  * \retval non-zero on failure | ||||
|  * \retval 0 on success | ||||
|  */ | ||||
| static int copy_route(struct sip_route **dst, const struct sip_route *src) | ||||
| { | ||||
| 	struct sip_route *thishop, *head, *tail; | ||||
| 
 | ||||
| 	/* Build a tailq, then assign it to **d when done. */ | ||||
| 	head = NULL; | ||||
| 	tail = head; | ||||
| 	for (; src; src = src->next) { | ||||
| 		thishop = create_route(src->hop, tail); | ||||
| 		if (!thishop) { | ||||
| 			return -1; | ||||
| 		} | ||||
| 		if (!head) { | ||||
| 			head = thishop; | ||||
| 		} | ||||
| 		tail = thishop; | ||||
| 
 | ||||
| 		ast_debug(2, "copy_route: copied hop: <%s>\n", thishop->hop); | ||||
| 	} | ||||
| 	*dst = head; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*! \brief Build route list from Path header
 | ||||
|  *  RFC 3327 requires that the Path header contains SIP URIs with lr paramter. | ||||
|  *  Thus, we do not care about strict routing SIP routers | ||||
|  */ | ||||
| static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, char *pathbuf) | ||||
| { | ||||
| 	struct sip_route *thishop, *head, *tail; | ||||
| 	int start = 0; | ||||
| 	int len; | ||||
| 	char *pr; | ||||
| 
 | ||||
| 	if (peer->path) { | ||||
| 		free_old_route(peer->path); | ||||
| 		peer->path = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!ast_test_flag(&peer->flags[0], SIP_USEPATH)) { | ||||
| 		ast_debug(2, "build_path: do not use Path headers\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	ast_debug(2, "build_path: try to build pre-loaded route-set by parsing Path headers\n"); | ||||
| 
 | ||||
| 	/* Build a tailq, then assign it to peer->path when done. */ | ||||
| 	head = NULL; | ||||
| 	tail = head; | ||||
| 	/* 1st we pass through all the hops in any Path headers */ | ||||
| 	for (;;) { | ||||
| 		/* Either loop over the request's Path headers or parse the buffer */ | ||||
| 		if (req) { | ||||
| 			pr = ast_strdupa(__get_header(req, "Path", &start)); | ||||
| 			if (*pr == '\0') { | ||||
| 				break; | ||||
| 			} | ||||
| 		} else if (pathbuf) { | ||||
| 			if (start == 0) { | ||||
| 				pr = ast_strdupa(pathbuf); | ||||
| 				start++; | ||||
| 			} else { | ||||
| 				break; | ||||
| 			} | ||||
| 		} else { | ||||
| 			break; | ||||
| 		} | ||||
| 		for (; (pr = strchr(pr, '<')) ; pr += (len + 1)) { | ||||
| 			/* Parse out each route entry */ | ||||
| 			++pr; | ||||
| 			len = strcspn(pr, ">"); | ||||
| 			*(pr + len) = '\0'; | ||||
| 			thishop = create_route(pr, tail); | ||||
| 			if (!thishop) { | ||||
| 				return -1; | ||||
| 			} | ||||
| 
 | ||||
| 			if (!head) { | ||||
| 				head = thishop; | ||||
| 			} | ||||
| 			tail = thishop; | ||||
| 			ast_debug(2, "build_path: Path hop: <%s>\n", thishop->hop); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Store as new route */ | ||||
| 	peer->path = head; | ||||
| 
 | ||||
| 	/* For debugging dump what we ended up with */ | ||||
| 	if (p && sip_debug_test_pvt(p)) { | ||||
| 		list_route(peer->path); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*! \brief builds the sip_pvt's nonce field which is used for the authentication 
 | ||||
|  *  challenge.  When forceupdate is not set, the nonce is only updated if | ||||
|  *  the current one is stale.  In this case, a stalenonce is one which | ||||
| @@ -19984,6 +20179,20 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct | ||||
| 		ast_cli(fd, "  Ign SDP ver  : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_IGNORESDPVERSION))); | ||||
| 		ast_cli(fd, "  Trust RPID   : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_TRUSTRPID))); | ||||
| 		ast_cli(fd, "  Send RPID    : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_SENDRPID))); | ||||
| 		ast_cli(fd, "  Path support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[0], SIP_USEPATH))); | ||||
| 		ast_cli(fd, "  Path         : "); | ||||
| 		if (!peer->path) { | ||||
| 			ast_cli(fd, "N/A\n"); | ||||
| 		} else { | ||||
| 			struct sip_route *r = peer->path; | ||||
| 			int first = 1; | ||||
| 			while (r) { | ||||
| 				ast_cli(fd, "%s<%s>", first ? "" : ", ", r->hop); | ||||
| 				first = 0; | ||||
| 				r = r->next; | ||||
| 			} | ||||
| 			ast_cli(fd, "\n"); | ||||
| 		} | ||||
| 		ast_cli(fd, "  Subscriptions: %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))); | ||||
| 		ast_cli(fd, "  Overlap dial : %s\n", allowoverlap2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWOVERLAP))); | ||||
| 		if (peer->outboundproxy) | ||||
| @@ -20577,6 +20786,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ | ||||
| 	ast_cli(a->fd, "  Allow promisc. redir:   %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR))); | ||||
| 	ast_cli(a->fd, "  Enable call counters:   %s\n", AST_CLI_YESNO(global_callcounter)); | ||||
| 	ast_cli(a->fd, "  SIP domain support:     %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list))); | ||||
| 	ast_cli(a->fd, "  Path support :          %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_USEPATH))); | ||||
| 	ast_cli(a->fd, "  Realm. auth:            %s\n", AST_CLI_YESNO(credentials != NULL)); | ||||
| 	if (credentials) { | ||||
| 		struct sip_auth *auth; | ||||
| @@ -20750,6 +20960,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ | ||||
| 		ast_cli(a->fd, "  Update:                 %s\n", AST_CLI_YESNO(sip_cfg.peer_rtupdate)); | ||||
| 		ast_cli(a->fd, "  Ignore Reg. Expire:     %s\n", AST_CLI_YESNO(sip_cfg.ignore_regexpire)); | ||||
| 		ast_cli(a->fd, "  Save sys. name:         %s\n", AST_CLI_YESNO(sip_cfg.rtsave_sysname)); | ||||
| 		ast_cli(a->fd, "  Save path header:       %s\n", AST_CLI_YESNO(sip_cfg.rtsave_path)); | ||||
| 		ast_cli(a->fd, "  Auto Clear:             %d (%s)\n", sip_cfg.rtautoclear, ast_test_flag(&global_flags[1], SIP_PAGE2_RTAUTOCLEAR) ? "Enabled" : "Disabled"); | ||||
| 	} | ||||
| 	ast_cli(a->fd, "\n----\n"); | ||||
| @@ -23342,7 +23553,7 @@ static int handle_response_register(struct sip_pvt *p, int resp, const char *res | ||||
| { | ||||
| 	int expires, expires_ms; | ||||
| 	struct sip_registry *r; | ||||
| 	r=p->registry; | ||||
| 	r = p->registry; | ||||
| 	 | ||||
| 	switch (resp) { | ||||
| 	case 401:	/* Unauthorized */ | ||||
| @@ -29492,6 +29703,11 @@ static int sip_poke_peer(struct sip_peer *peer, int force) | ||||
| 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY); | ||||
| 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY); | ||||
| 	ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY); | ||||
| 	copy_route(&p->route, peer->path); | ||||
| 	if (p->route) { | ||||
| 		/* Parse SIP URI of first route-set hop and use it as target address */ | ||||
| 		__set_address_from_contact(p->route->hop, &p->sa, p->socket.type == SIP_TRANSPORT_TLS ? 1 : 0);	 | ||||
| 	} | ||||
| 
 | ||||
| 	/* Send OPTIONs to peer's fullcontact */ | ||||
| 	if (!ast_strlen_zero(peer->fullcontact)) { | ||||
| @@ -29946,6 +30162,9 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask | ||||
| 	if (!strcasecmp(v->name, "trustrpid")) { | ||||
| 		ast_set_flag(&mask[0], SIP_TRUSTRPID); | ||||
| 		ast_set2_flag(&flags[0], ast_true(v->value), SIP_TRUSTRPID); | ||||
| 	} else if (!strcasecmp(v->name, "supportpath")) { | ||||
| 		ast_set_flag(&mask[0], SIP_USEPATH); | ||||
| 		ast_set2_flag(&flags[0], ast_true(v->value), SIP_USEPATH); | ||||
| 	} else if (!strcasecmp(v->name, "sendrpid")) { | ||||
| 		ast_set_flag(&mask[0], SIP_SENDRPID); | ||||
| 		if (!strcasecmp(v->value, "pai")) { | ||||
| @@ -31528,6 +31747,8 @@ static int reload_config(enum channelreloadreason reason) | ||||
| 			ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS); | ||||
| 		} else if (!strcasecmp(v->name, "rtsavesysname")) { | ||||
| 			sip_cfg.rtsave_sysname = ast_true(v->value); | ||||
| 		} else if (!strcasecmp(v->name, "rtsavepath")) { | ||||
| 			sip_cfg.rtsave_path = ast_true(v->value); | ||||
| 		} else if (!strcasecmp(v->name, "rtupdate")) { | ||||
| 			sip_cfg.peer_rtupdate = ast_true(v->value); | ||||
| 		} else if (!strcasecmp(v->name, "ignoreregexpire")) { | ||||
|   | ||||
| @@ -294,6 +294,7 @@ | ||||
| #define SIP_PROG_INBAND_NO     (1 << 25) | ||||
| #define SIP_PROG_INBAND_YES    (2 << 25) | ||||
|  | ||||
| #define SIP_USEPATH          (1 << 27) /*!< GDP: Trust and use incoming Path headers? */ | ||||
| #define SIP_SENDRPID         (3 << 29) /*!< DP: Remote Party-ID Support */ | ||||
| #define SIP_SENDRPID_NO      (0 << 29) | ||||
| #define SIP_SENDRPID_PAI     (1 << 29) /*!< Use "P-Asserted-Identity" for rpid */ | ||||
| @@ -304,7 +305,7 @@ | ||||
| #define SIP_FLAGS_TO_COPY \ | ||||
| 	(SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \ | ||||
| 	 SIP_PROG_INBAND | SIP_USECLIENTCODE | SIP_NAT_FORCE_RPORT | SIP_G726_NONSTANDARD | \ | ||||
| 	 SIP_USEREQPHONE | SIP_INSECURE) | ||||
| 	 SIP_USEREQPHONE | SIP_INSECURE | SIP_USEPATH) | ||||
| /*@}*/ | ||||
|  | ||||
| /*! \name SIPflags2 | ||||
| @@ -737,6 +738,7 @@ struct __show_chan_arg { | ||||
| struct sip_settings { | ||||
| 	int peer_rtupdate;          /*!< G: Update database with registration data for peer? */ | ||||
| 	int rtsave_sysname;         /*!< G: Save system name at registration? */ | ||||
| 	int rtsave_path;            /*!< G: Save path header on registration */ | ||||
| 	int ignore_regexpire;       /*!< G: Ignore expiration of peer  */ | ||||
| 	int rtautoclear;            /*!< Realtime ?? */ | ||||
| 	int directrtpsetup;         /*!< Enable support for Direct RTP setup (no re-invites) */ | ||||
| @@ -1368,6 +1370,7 @@ struct sip_peer { | ||||
| 	int timer_t1;                   /*!<  The maximum T1 value for the peer */ | ||||
| 	int timer_b;                    /*!<  The maximum timer B (transaction timeouts) */ | ||||
| 	int fromdomainport;             /*!<  The From: domain port */ | ||||
| 	struct sip_route *path;         /*!<  Head of linked list of out-of-dialog outgoing routing steps (fm Path headers) */ | ||||
|  | ||||
| 	/*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */ | ||||
| 	enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */ | ||||
|   | ||||
| @@ -121,6 +121,7 @@ ipaddr = AstAccountIPAddress | ||||
| defaultuser = AstAccountDefaultUser | ||||
| regserver = AstAccountRegistrationServer | ||||
| lastms = AstAccountLastQualifyMilliseconds | ||||
| supportpath = AstAccountPathSupport | ||||
| additionalFilter=(objectClass=AsteriskSIPUser) | ||||
|  | ||||
| ; | ||||
|   | ||||
| @@ -442,6 +442,21 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls | ||||
| ;outboundproxy=[2001:db8::1]:5062               ; IPv6 address literal with explicit port | ||||
| ;                                               ; (could also be tcp,udp) - defining transports on the proxy line only | ||||
| ;                                               ; applies for the global proxy, otherwise use the transport= option | ||||
|  | ||||
| ;supportpath=yes		; This activates parsing and handling of Path header as defined in RFC 3327. This enables | ||||
| 				; Asterisk to route outgoing out-of-dialog requests via a set of proxies by using a pre-loaded | ||||
| 				; route-set defined by the Path headers in the REGISTER request. | ||||
| 				; NOTE: There are multiple things to consider with this setting: | ||||
| 				;  * As this influences routing of SIP requests make sure to not trust Path headers provided | ||||
| 				;    by the user's SIP client (the proxy in front of Asterisk should remove existing user | ||||
| 				;    provided Path headers). | ||||
| 				;  * When a peer has both a path and outboundproxy set, the path will be added to Route: header | ||||
| 				;    but routing to next hop is done using the outboundproxy. | ||||
| 				;  * If set globally, not only will all peers use the Path header, but outbound REGISTER | ||||
| 				;    requests from Asterisk will add path to the Supported header. | ||||
|  | ||||
| ;rtsavepath=yes                 ; If using dynamic realtime, store the path headers | ||||
|  | ||||
| ;matchexternaddrlocally = yes     ; Only substitute the externaddr or externhost setting if it matches | ||||
|                                 ; your localnet setting. Unless you have some sort of strange network | ||||
|                                 ; setup you will not need to enable this. | ||||
|   | ||||
| @@ -79,6 +79,7 @@ CREATE TABLE IF NOT EXISTS `sippeers` ( | ||||
|       `callingpres` enum('allowed_not_screened','allowed_passed_screen','allowed_failed_screen','allowed','prohib_not_screened','prohib_passed_screen','prohib_failed_screen','prohib') DEFAULT NULL, | ||||
|       `mohinterpret` varchar(40) DEFAULT NULL, | ||||
|       `mohsuggest` varchar(40) DEFAULT NULL, | ||||
|       `path` varchar(256) DEFAULT NULL, | ||||
|       `parkinglot` varchar(40) DEFAULT NULL, | ||||
|       `hasvoicemail` enum('yes','no') DEFAULT NULL, | ||||
|       `subscribemwi` enum('yes','no') DEFAULT NULL, | ||||
| @@ -90,6 +91,7 @@ CREATE TABLE IF NOT EXISTS `sippeers` ( | ||||
|       `ignoresdpversion` enum('yes','no') DEFAULT NULL, | ||||
|       `allowtransfer` enum('yes','no') DEFAULT NULL, | ||||
|       `dynamic` enum('yes','no') DEFAULT NULL, | ||||
|       `supportpath` enum('yes','no') DEFAULT NULL, | ||||
|       PRIMARY KEY (`id`), | ||||
|       UNIQUE KEY `name` (`name`), | ||||
|       KEY `ipaddr` (`ipaddr`,`port`), | ||||
|   | ||||
| @@ -38,6 +38,7 @@ amaflags character varying(7), | ||||
| callgroup character varying(10), | ||||
| callerid character varying(80), | ||||
| canreinvite character varying(3) DEFAULT 'yes', | ||||
| supportpath character varying(3) DEFAULT 'no', | ||||
| context character varying(80), | ||||
| defaultip character varying(15), | ||||
| dtmfmode character varying(7), | ||||
| @@ -70,6 +71,7 @@ cancallforward character varying(3) DEFAULT 'yes', | ||||
| lastms integer DEFAULT 0 NOT NULL, | ||||
| defaultuser character varying(80), | ||||
| fullcontact character varying(80), | ||||
| path character varying(256), | ||||
| regserver character varying(30), | ||||
| useragent character varying(40), | ||||
| callbackextension character varying(40) | ||||
|   | ||||
| @@ -112,7 +112,7 @@ objectIdentifier AstAccountSetVar AstAttrType:66 | ||||
| objectIdentifier AstAccountAllowOverlap AstAttrType:67 | ||||
| objectIdentifier AstAccountVideoSupport AstAttrType:68 | ||||
| objectIdentifier AstAccountIgnoreSDPVersion AstAttrType:69 | ||||
|  | ||||
| objectIdentifier AstAccountPathSupport AstAttrType:70 | ||||
|  | ||||
| ############################################################################# | ||||
| # Object Class OIDs | ||||
| @@ -640,6 +640,13 @@ attributetype ( AstAccountIgnoreSDPVersion | ||||
|         SUBSTR caseIgnoreSubstringsMatch | ||||
|         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) | ||||
|  | ||||
| attributetype ( AstAccountPathSupport | ||||
|         NAME 'AstAccountPathSupport' | ||||
|         DESC 'Asterisk account support Path RFC 3327' | ||||
|         EQUALITY caseIgnoreMatch | ||||
|         SUBSTR caseIgnoreSubstringsMatch | ||||
|         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) | ||||
|  | ||||
| ############################################################################# | ||||
| # Object Class definitions | ||||
| # | ||||
| @@ -762,7 +769,8 @@ objectclass ( AsteriskSIPUser | ||||
|         AstAccountTransport $ | ||||
|         AstAccountType $  | ||||
|         AstAccountUserAgent $	 | ||||
|         AstAccountVideoSupport | ||||
|         AstAccountVideoSupport $ | ||||
|         AstAccountPathSupport | ||||
|     ) | ||||
|     ) | ||||
|  | ||||
|   | ||||
| @@ -108,6 +108,7 @@ olcObjectIdentifier: AstAccountSetVar AstAttrType:66 | ||||
| olcObjectIdentifier: AstAccountAllowOverlap AstAttrType:67 | ||||
| olcObjectIdentifier: AstAccountVideoSupport AstAttrType:68 | ||||
| olcObjectIdentifier: AstAccountIgnoreSDPVersion AstAttrType:69 | ||||
| olcObjectIdentifier: AstAccountPathSupport AstAttrType:70 | ||||
| # | ||||
| # | ||||
| ############################################################################# | ||||
| @@ -636,6 +637,13 @@ olcAttributeTypes: ( AstAccountIgnoreSDPVersion | ||||
|         SUBSTR caseIgnoreSubstringsMatch | ||||
|         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) | ||||
| # | ||||
| olcAttributeTypes: ( AstAccountPathSupport | ||||
|         NAME 'AstAccountPathSupport' | ||||
|         DESC 'Asterisk account support Path RFC 3327' | ||||
|         EQUALITY caseIgnoreMatch | ||||
|         SUBSTR caseIgnoreSubstringsMatch | ||||
|         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) | ||||
| # | ||||
| ############################################################################# | ||||
| # Object Class definitions | ||||
| # | ||||
| @@ -758,7 +766,8 @@ olcObjectClasses: ( AsteriskSIPUser | ||||
|         AstAccountTransport $ | ||||
|         AstAccountType $ | ||||
|         AstAccountUserAgent $ | ||||
|         AstAccountVideoSupport | ||||
|         AstAccountVideoSupport $ | ||||
|         AstAccountPathSupport | ||||
|     ) | ||||
|     ) | ||||
| # | ||||
|   | ||||
		Reference in New Issue
	
	Block a user