- Added handling of Max-Forwards header

- a detected via loop results in an 482 Loop detected
This commit is contained in:
Thomas Ries 2004-02-01 16:55:37 +00:00
parent 2315f495d4
commit af152d2bf4
7 changed files with 197 additions and 106 deletions

View File

@ -1,6 +1,8 @@
0.5.3 0.5.3
===== =====
31-Jan-2004: - Allow 2 of my vias in header to let 2 UA's sitting 1-Feb-2004: - Added handling of Max-Forwards header
- a detected via loop results in an 482 Loop detected
31-Jan-2004: - Allow 2 of my vias in header to let 2 UA's sitting
behind the same siproxd to have conversation together behind the same siproxd to have conversation together
UA1 -->--\ /-->--\ UA1 -->--\ /-->--\
siproxd Registrar siproxd Registrar
@ -22,19 +24,20 @@
0.5.2 0.5.2
===== =====
30-Jan-2004: - If RTP proxy is disabled, don't rewrite incomming 31-Jan-2004: - Released 0.5.2
30-Jan-2004: - If RTP proxy is disabled, don't rewrite incomming
SDP bodies (patch from Robert Högberg) SDP bodies (patch from Robert Högberg)
29-Jan-2004: - new doc/RFC3261_compliance.txt and comments in the 29-Jan-2004: - new doc/RFC3261_compliance.txt and comments in the
code that refer to the RFC. code that refer to the RFC.
28-Jan-2004: - don't die on INVITE requests that include no Contact 28-Jan-2004: - don't die on INVITE requests that include no Contact
header - which is legal. (patch from Robert Högberg) header - which is legal. (patch from Robert Högberg)
- RTP proxy: don't try to forward empty RTP packets - RTP proxy: don't try to forward empty RTP packets
- renamed some variables of rtp_proxytable_t to make - renamed some variables of rtp_proxytable_t to make
better sense (changed meaning in fullduplex RTP proxy) better sense (changed meaning in fullduplex RTP proxy)
27-Jan-2004: - added doc/KNOWN_BUGS 27-Jan-2004: - added doc/KNOWN_BUGS
- better branch parameter calculation (via header), - better branch parameter calculation (via header),
now honors RFC3261 for stateless proxies (section 16.11) now honors RFC3261 for stateless proxies (section 16.11)
- SIP request: remove a Route-header pointing to myself. - SIP request: remove a Route header pointing to myself.
This was an issue with Linphone 0.12.1. This was an issue with Linphone 0.12.1.
(patch from Robert Högberg). (patch from Robert Högberg).
- removed IPCHAINS & IPTABLES (netfilter) proxy support - removed IPCHAINS & IPTABLES (netfilter) proxy support
@ -42,13 +45,13 @@
use one single port (and socket) on each side (inbound/ use one single port (and socket) on each side (inbound/
outbound) to send and receive RTP traffic for every outbound) to send and receive RTP traffic for every
active stream (patch from Christof Meerwald). active stream (patch from Christof Meerwald).
22-Jan-2004: - ./configure option: --enable-static to build 22-Jan-2004: - ./configure option: --enable-static to build
a completely statically linked executable a completely statically linked executable
- REGISTER honors the expires parameter - REGISTER honors the expires parameter
of the contact header of the contact header
- Contact header of REGISTER response must be - Contact header of REGISTER response must be
rewritten back to the local (true) URL rewritten back to the local (true) URL
18-Jan-2004: - security_check_raw: 18-Jan-2004: - security_check_raw:
size check: >= 16 bytes size check: >= 16 bytes
- at exit, check registration file to be writable - at exit, check registration file to be writable
- no WARNING if SIP user-agent header is not supplied. - no WARNING if SIP user-agent header is not supplied.
@ -57,6 +60,7 @@
0.5.1 0.5.1
===== =====
22-Dec-2003: - Released 0.5.1
21-Dec-2003: - possibility to log call establishment 21-Dec-2003: - possibility to log call establishment
17-Dec-2003: - full duplex RTP proxy (many thanks to Chris Ross for 17-Dec-2003: - full duplex RTP proxy (many thanks to Chris Ross for
his work on this). Up to now, only the RTP *Relay* his work on this). Up to now, only the RTP *Relay*

26
TODO
View File

@ -22,31 +22,9 @@ TODOs, in random order:
- via loop detection: send 482 error code - via loop detection: send 482 error code
- support Record-Route header
- feature: don't bind to 0.0.0.0 address, but only to inbound/outbound IF's - feature: don't bind to 0.0.0.0 address, but only to inbound/outbound IF's
(defined by IFNAME) (defined by IFNAME)
- support IPTABLES for RTP proxying -> use libiptc RFC3261 non-compliance:
- Record-Route header handling
- rtpproxy_masq:
RACE CONDITIONS! A slot may be timed out, even if the actual
masquerading tunnel is still active. A following new
INVITE then tries to use the believed free port -> Buh
- Can we poll (/proc/something) to figure out if the tunnel
is still active before deleting? This would require knowledge
of the text layout in /proc/xxx.
- are there some other possibilities (netfilter/libiptc)?
- introduce some kind of connection STATE to the proxy table.
Timeout based discarding only is active for non-established.
An INVITE would set the STATE to CONNECTING, the following
ACK to CONNECTED. A CONNECTED entry can only be deleted by
a BYE or CANCEL.
- NETFILTER: during startup (RTP initialization) siproxd should
clean left over entries that are within the RTP proxy port range
- NETFILTER masquerading:
it looks like it is not possible to create an entry in the
ip_conntrack table from an userspace application. How do we proceed?
We just might insert/delete DNAT entries in the PREROUTE NAT table.
This the means that we must implement a connection state into the
proxy table.

View File

@ -9,19 +9,19 @@ Request Processing: implemented
Section 16.3: Request Validation Section 16.3: Request Validation
1. Reasonable Syntax yes 1. Reasonable Syntax yes
2. URI scheme no 2. URI scheme no
3. Max-Forwards no 3. Max-Forwards yes
4. (Optional) Loop Detection partially 4. (Optional) Loop Detection yes
5. Proxy-Require no 5. Proxy-Require no
6. Proxy-Authorization yes 6. Proxy-Authorization yes
Section 16.4 Route Information Preprocessing yes Section 16.4 Route Information Preprocessing partially
Section 16.5 Determining Request Targets no Section 16.5 Determining Request Targets no
Section 16.6 Request Forwarding Section 16.6 Request Forwarding
1. Make a copy of the received request yes 1. Make a copy of the received request yes
2. Update the Request-URI yes 2. Update the Request-URI yes
3. Update the Max-Forwards header field no 3. Update the Max-Forwards header field yes
4. Optionally add a Record-route header field value no 4. Optionally add a Record-route header field value no
5. Optionally add additional header fields no 5. Optionally add additional header fields no
6. Postprocess routing information no 6. Postprocess routing information no
@ -37,7 +37,7 @@ Response Processing: implemented
1. Reasonable Syntax yes 1. Reasonable Syntax yes
2. URI scheme no 2. URI scheme no
3. Max-Forwards no 3. Max-Forwards no
4. (Optional) Loop Detection partially 4. (Optional) Loop Detection yes
5. Proxy-Require no 5. Proxy-Require no
6. Proxy-Authorization yes 6. Proxy-Authorization yes

View File

@ -91,47 +91,26 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
DEBUGC(DBCLASS_PROXY,"proxy_request"); DEBUGC(DBCLASS_PROXY,"proxy_request");
/*
* RFC 3261, Section 16.6 step 1
* Proxy Behavior - Request Forwarding - Make a copy
*/
/* nothing to do here, copy is ready in 'request'*/
/* /*
* RFC 3261, Section 16.6 step 3 * RFC 3261, Section 16.4
* Proxy Behavior - Request Forwarding - Max-Forwards
* (if Max-Forward header exists, decrement by one, if it does not
* exist, add a new one with value SHOULD be 70)
*/
/* NOT IMPLEMENTED */
/*
* RFC 3261, Section 16.6 step 4
* Proxy Behavior - Request Forwarding - Add a Record-route header
*/
/* NOT IMPLEMENTED (optional) */
/*
* RFC 3261, Section 16.6 step 5
* Proxy Behavior - Request Forwarding - Add Additional Header Fields
*/
/* NOT IMPLEMENTED (optional) */
/*
* RFC 3261, Section 16.6 step 6
* Proxy Behavior - Request Forwarding - Postprocess routing information
*/
/* NOT IMPLEMENTED */
/*
* RFC 3261, Section 16.4
* Proxy Behavior - Route Information Preprocessing * Proxy Behavior - Route Information Preprocessing
* (process Record-Route header) * (process Route header)
*/ */
/*
The proxy MUST inspect the Request-URI of the request. If the
Request-URI of the request contains a value this proxy previously
placed into a Record-Route header field (see Section 16.6 item 4),
the proxy MUST replace the Request-URI in the request with the last
value from the Route header field, and remove that value from the
Route header field. The proxy MUST then proceed as if it received
this modified request.
NOT IMPLEMENTED*/
/* /*
* Check if I am listed at the topmost Route header (if any Route * Check if I am listed at the topmost Route header (if any Route
* header is existing at all). If so, remove it from the list. * header is existing at all). If so, remove it from the list and
* rewrite the request URI to point to the now topmost Route.
*/ */
if (request->routes && !osip_list_eol(request->routes, 0)) { if (request->routes && !osip_list_eol(request->routes, 0)) {
struct in_addr addr1, addr2, addr3; struct in_addr addr1, addr2, addr3;
@ -151,7 +130,8 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
configuration.sip_listen_port == SIP_PORT)) { configuration.sip_listen_port == SIP_PORT)) {
osip_list_remove(request->routes, 0); osip_list_remove(request->routes, 0);
osip_route_free(route); osip_route_free(route);
/* possibly request->routes will be freed by osip_message_free() */ /* request->routes will be freed by osip_message_free() */
DEBUGC(DBCLASS_PROXY,"removed Route header pointing to myself");
} }
} }
@ -298,6 +278,11 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
} /* log_calls */ } /* log_calls */
/*
* RFC 3261, Section 16.6 step 1
* Proxy Behavior - Request Forwarding - Make a copy
*/
/* nothing to do here, copy is ready in 'request'*/
/* get destination address */ /* get destination address */
url=osip_message_get_uri(request); url=osip_message_get_uri(request);
@ -321,17 +306,6 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
proxy_rewrite_request_uri(request, i); proxy_rewrite_request_uri(request, i);
} }
/*
* RFC 3261, Section 16.6 step 8
* Proxy Behavior - Add a Via header field value
*/
/* add my Via header line (inbound interface)*/
sts = sip_add_myvia(request, IF_INBOUND);
if (sts == STS_FAILURE) {
ERROR("adding my inbound via failed!");
return STS_FAILURE;
}
/* if this is CANCEL/BYE request, stop RTP proxying */ /* if this is CANCEL/BYE request, stop RTP proxying */
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
/* stop the RTP proxying stream(s) */ /* stop the RTP proxying stream(s) */
@ -356,7 +330,7 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
/* /*
* from the internal masqueraded host to an external host * from the internal masqueraded host to an external host
*/ */
case REQTYP_OUTGOING: case REQTYP_OUTGOING:
DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound", DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound",
request->from->url->username? request->from->url->username:"*NULL*", request->from->url->username? request->from->url->username:"*NULL*",
request->from->url->host? request->from->url->host: "*NULL*"); request->from->url->host? request->from->url->host: "*NULL*");
@ -371,6 +345,9 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
/* if it is addressed to myself, then it must be some request /* if it is addressed to myself, then it must be some request
* method that I as a proxy do not support. Reject */ * method that I as a proxy do not support. Reject */
#if 0 #if 0
/* careful - an internal UA might send an request to another internal UA.
This would be caught here, so don't do this. This situation should be
caught in the default part of the CASE statement below */
if (is_sipuri_local(request) == STS_TRUE) { if (is_sipuri_local(request) == STS_TRUE) {
WARN("unsupported request [%s] directed to proxy from %s@%s -> %s@%s", WARN("unsupported request [%s] directed to proxy from %s@%s -> %s@%s",
request->sip_method? request->sip_method:"*NULL*", request->sip_method? request->sip_method:"*NULL*",
@ -393,16 +370,6 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
/* rewrite Contact header to represent the masqued address */ /* rewrite Contact header to represent the masqued address */
sip_rewrite_contact(request, DIR_OUTGOING); sip_rewrite_contact(request, DIR_OUTGOING);
/*
* RFC 3261, Section 16.8
* Proxy Behavior - Add a Via header field value
*/
/* add my Via header line (outbound interface)*/
sts = sip_add_myvia(request, IF_OUTBOUND);
if (sts == STS_FAILURE) {
ERROR("adding my outbound via failed!");
}
/* if this is CANCEL/BYE request, stop RTP proxying */ /* if this is CANCEL/BYE request, stop RTP proxying */
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) { if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
/* stop the RTP proxying stream(s) */ /* stop the RTP proxying stream(s) */
@ -438,10 +405,119 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
return STS_FAILURE; return STS_FAILURE;
} }
/*
* RFC 3261, Section 16.6 step 7 /*
* Proxy Behavior - Determine Next-Hop Address * RFC 3261, Section 16.6 step 3
*/ * Proxy Behavior - Request Forwarding - Max-Forwards
* (if Max-Forwards header exists, decrement by one, if it does not
* exist, add a new one with value SHOULD be 70)
*/
{
osip_header_t *max_forwards;
int forwards_count = DEFAULT_MAXFWD;
char mfwd[8];
osip_message_get_max_forwards(request, 0, &max_forwards);
if (max_forwards == NULL) {
sprintf(mfwd, "%i", forwards_count);
osip_message_set_max_forwards(request, mfwd);
} else {
if (max_forwards->hvalue) {
forwards_count = atoi(max_forwards->hvalue);
forwards_count -=1;
osip_free (max_forwards->hvalue);
}
sprintf(mfwd, "%i", forwards_count);
max_forwards->hvalue = osip_strdup(mfwd);
}
DEBUGC(DBCLASS_PROXY,"setting Max-Forwards=%s",mfwd);
}
/*
* RFC 3261, Section 16.6 step 4
* Proxy Behavior - Request Forwarding - Add a Record-route header
*/
#if 0
/* NOT IMPLEMENTED - this requires proper implementation of
the Route headers first. */
{
struct in_addr addr;
osip_record_route_t *r_route;
osip_uri_t *uri_of_proxy;
/*
* get the IP address of the interface where I'm going to
* send out this request
*/
switch (type) {
case REQTYP_INCOMING:
sts = get_ip_by_ifname(configuration.inbound_if, &addr);
if (sts == STS_FAILURE) {
ERROR("can't find inbound interface %s - configuration error?",
configuration.outbound_if);
return STS_FAILURE;
}
break;
case REQTYP_OUTGOING:
sts = get_ip_by_ifname(configuration.outbound_if, &addr);
if (sts == STS_FAILURE) {
ERROR("can't find outbound interface %s - configuration error?",
configuration.outbound_if);
return STS_FAILURE;
}
break;
default:
ERROR("Oops, never should end up here (type=%i)", type);
return STS_FAILURE;
}
sts = osip_record_route_init(&r_route);
if (sts == 0) {
sts = osip_uri_init(&uri_of_proxy);
if (sts == 0) {
char tmp[8];
/* host name / IP */
osip_uri_set_host(uri_of_proxy, osip_strdup(utils_inet_ntoa(addr)));
/* port number */
sprintf(tmp, "%i", configuration.sip_listen_port);
osip_uri_set_port(uri_of_proxy, osip_strdup(tmp));
/* 'lr' parameter */
osip_uri_uparam_add(uri_of_proxy, "lr", NULL);
osip_record_route_set_url(r_route, uri_of_proxy);
/* insert before all other record-route */
osip_list_add (request->record_routes, r_route, 0);
} else {
osip_record_route_free (r_route);
osip_free (r_route);
} /* if url_init */
} /* if record route init */
}
#endif
/*
* RFC 3261, Section 16.6 step 5
* Proxy Behavior - Request Forwarding - Add Additional Header Fields
*/
/* NOT IMPLEMENTED (optional) */
/*
* RFC 3261, Section 16.6 step 6
* Proxy Behavior - Request Forwarding - Postprocess routing information
*/
/*
* RFC 3261, Section 16.6 step 7
* Proxy Behavior - Determine Next-Hop Address
*/
if ((type == REQTYP_OUTGOING) && (configuration.outbound_proxy_host)) { if ((type == REQTYP_OUTGOING) && (configuration.outbound_proxy_host)) {
/* I have an outbound proxy configured */ /* I have an outbound proxy configured */
sts = get_ip_by_host(configuration.outbound_proxy_host, &sendto_addr); sts = get_ip_by_host(configuration.outbound_proxy_host, &sendto_addr);
@ -472,6 +548,23 @@ int proxy_request (osip_message_t *request, struct sockaddr_in *from) {
} }
} }
/*
* RFC 3261, Section 16.6 step 8
* Proxy Behavior - Add a Via header field value
*/
/* add my Via header line (outbound interface)*/
if (type == REQTYP_INCOMING) {
sts = sip_add_myvia(request, IF_INBOUND);
if (sts == STS_FAILURE) {
ERROR("adding my inbound via failed!");
}
} else {
sts = sip_add_myvia(request, IF_OUTBOUND);
if (sts == STS_FAILURE) {
ERROR("adding my outbound via failed!");
return STS_FAILURE;
}
}
/* /*
* RFC 3261, Section 16.6 step 9 * RFC 3261, Section 16.6 step 9
* Proxy Behavior - Add a Content-Length header field if necessary * Proxy Behavior - Add a Content-Length header field if necessary

View File

@ -215,10 +215,9 @@ int register_client(osip_message_t *my_msg, int force_lcl_masq) {
* look for an Contact expires parameter - in case of REGISTER * look for an Contact expires parameter - in case of REGISTER
* these two are equal. The Contact expires has higher priority! * these two are equal. The Contact expires has higher priority!
*/ */
osip_contact_param_get_byname( osip_contact_param_get_byname(
(osip_contact_t*) my_msg->contacts->node->element, (osip_contact_t*) my_msg->contacts->node->element,
"expires", &expires_param); EXPIRES, &expires_param);
if (expires_param && expires_param->gvalue) { if (expires_param && expires_param->gvalue) {
/* get expires from contact Header */ /* get expires from contact Header */

View File

@ -294,9 +294,25 @@ int main (int argc, char *argv[])
/* /*
* RFC 3261, Section 16.3 step 3 * RFC 3261, Section 16.3 step 3
* Proxy Behavior - Request Validation - Max-Forwards check * Proxy Behavior - Request Validation - Max-Forwards check
* (check Max-Forward header and refuse with 483 if too many hops) * (check Max-Forwards header and refuse with 483 if too many hops)
*/ */
/* NOT IMPLEMENTED */ {
osip_header_t *max_forwards;
int forwards_count = DEFAULT_MAXFWD;
osip_message_get_max_forwards(my_msg, 0, &max_forwards);
if (max_forwards && max_forwards->hvalue) {
forwards_count = atoi(max_forwards->hvalue);
}
DEBUGC(DBCLASS_PROXY,"checking Max-Forwards (=%i)",forwards_count);
if (forwards_count <= 0) {
DEBUGC(DBCLASS_SIP, "Forward count reached 0 -> 483 response");
sip_gen_response(my_msg, 483 /*Too many hops*/);
goto end_loop; /* skip and free resources */
}
}
/* /*
* RFC 3261, Section 16.3 step 4 * RFC 3261, Section 16.3 step 4
@ -304,8 +320,8 @@ int main (int argc, char *argv[])
* (check for loop and return 482 if a loop is detected) * (check for loop and return 482 if a loop is detected)
*/ */
if (check_vialoop(my_msg) == STS_TRUE) { if (check_vialoop(my_msg) == STS_TRUE) {
DEBUGC(DBCLASS_PROXY,"via loop detected, ignoring request"); DEBUGC(DBCLASS_SIP,"via loop detected, ignoring request");
/* we should return 482, NOT IMPLEMENTED */ sip_gen_response(my_msg, 482 /*Loop detected*/);
goto end_loop; /* skip and free resources */ goto end_loop; /* skip and free resources */
} }

View File

@ -156,7 +156,8 @@ struct siproxd_config {
/* /*
* some constant definitions * some constant definitions
*/ */
#define SIP_PORT 5060 #define SIP_PORT 5060 /* default port to listen */
#define DEFAULT_MAXFWD 70 /* default Max-Forward count */
#define URLMAP_SIZE 32 /* number of URL mapping table entries */ #define URLMAP_SIZE 32 /* number of URL mapping table entries */
#define RTPPROXY_SIZE 64 /* number of rtp proxy entries */ #define RTPPROXY_SIZE 64 /* number of rtp proxy entries */