diff --git a/ChangeLog b/ChangeLog index 1b18549..e8aaa21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 0.3.7 ===== + 04-Oct-2003: - Siproxd now also works as outbound proxy 'only', + means that local UAs may register themselfes to a + 3rd party registrar and use siproxd only as oubound + proxy for masquerading purpose. + - fixed some errors with callid handling (NULL pointers) 24-Sep-2003: - corrected the calling arguments of rtp_masq dummy routines (non IPCHAINS capable kernels) 22-Sep-2003: - \0 termination of read() SIP telegram from line diff --git a/RELNOTES b/RELNOTES index 4c09956..f044bd5 100644 --- a/RELNOTES +++ b/RELNOTES @@ -1,4 +1,4 @@ -Release Notes for siproxd-0.3.6a +Release Notes for siproxd-0.3.6b ================================ - Fli4l OPT_SIP (still experimental) available, check @@ -60,15 +60,15 @@ Known bugs: ----- -md5sum for siproxd-0.3.6a.tar.gz: e47e8cae6b494e79f72367b76d8e2706 +md5sum for siproxd-0.3.6b.tar.gz: 5ded692aa606aac714f9c9278b4adee7 GnuPG signature for siproxd-0.3.6a.tar.gz archive: -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (GNU/Linux) -iD8DBQA/cdADCfzBioe83JQRAol5AKC/ugXDRvwMCCmUeDkVgfxZmWKJSACfUi8Z -hUdAYUxhye4JSHfql1EcBg4= -=AXu4 +iD8DBQA/cztqCfzBioe83JQRAs8OAJ9DZn4qJceNYkkhuF3EqMiV+w+kKQCcDFPL +h7SwZyAdz+7Qzri/xFcdrjE= +=SEXX -----END PGP SIGNATURE----- diff --git a/doc/siproxd.conf.example b/doc/siproxd.conf.example index 87174cb..310d3a6 100644 --- a/doc/siproxd.conf.example +++ b/doc/siproxd.conf.example @@ -7,7 +7,7 @@ # ###################################################################### -# The interafce names of INBOUND and OUTBOUND interface. +# The interface names of INBOUND and OUTBOUND interface. # if_inbound = eth0 if_outbound = ppp0 diff --git a/src/proxy.c b/src/proxy.c index 597e013..6edc417 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -82,8 +82,10 @@ int proxy_request (osip_message_t *request) { for (i=0; ito->url, urlmap[i].masq_url)==STS_SUCCESS) { + /* incoming request ('to' == 'masq') || (('to' == 'reg') && !REGISTER)*/ + if ((compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) || + (!MSG_IS_REGISTER(request) && + (compare_url(request->to->url, urlmap[i].reg_url)==STS_SUCCESS))) { type=REQTYP_INCOMING; DEBUGC(DBCLASS_PROXY,"incoming request from %s@%s from outbound", request->from->url->username? request->from->url->username:"*NULL*", @@ -336,7 +338,7 @@ int proxy_response (osip_message_t *response) { */ - /* Ahhrghh...... an response seems to have NO contact information... + /* Ahhrghh...... a response seems to have NO contact information... * so let's take FROM instead... * the TO and FROM headers are EQUAL to the request - that means * they are swapped in their meaning for a response... @@ -346,9 +348,9 @@ int proxy_response (osip_message_t *response) { for (i=0; ifrom->url, urlmap[i].masq_url)==STS_SUCCESS) { + /* incoming response ('from' == 'masq') || ('from' == 'reg') */ + if ((compare_url(response->from->url, urlmap[i].reg_url)==STS_SUCCESS) || + (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS)) { type=RESTYP_INCOMING; DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound", response->from->url->username? response->from->url->username:"*NULL*", @@ -356,8 +358,9 @@ int proxy_response (osip_message_t *response) { break; } - /* outgoing response ('to' == 'reg') */ - if (compare_url(response->to->url, urlmap[i].masq_url)==STS_SUCCESS) { + /* outgoing response ('to' == 'reg') || ('to' == 'masq' ) */ + if ((compare_url(response->to->url, urlmap[i].masq_url)==STS_SUCCESS) || + (compare_url(response->to->url, urlmap[i].reg_url)==STS_SUCCESS)){ type=RESTYP_OUTGOING; DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound", response->from->url->username? response->from->url->username:"*NULL*", diff --git a/src/register.c b/src/register.c index af412c0..ac75fd7 100644 --- a/src/register.c +++ b/src/register.c @@ -59,7 +59,7 @@ void register_init(void) { * STS_FAILURE : registration failed * STS_NEED_AUTH : authentication needed */ -int register_client(osip_message_t *my_msg) { +int register_client(osip_message_t *my_msg, int force_lcl_masq) { int i, j, n, sts; int expires; time_t time_now; @@ -201,8 +201,28 @@ int register_client(osip_message_t *my_msg) { strcpy(urlmap[i].masq_url->host, configuration.masked_host.string[j]); } + /* + * for transparent proxying: force device to be masqueraded + * as with the outbound IP + */ + if (force_lcl_masq) { + struct in_addr addr; + char *addrstr; + sts = get_ip_by_ifname(configuration.outbound_if,&addr); + addrstr = inet_ntoa(addr); + DEBUGC(DBCLASS_REG,"masquerading UA %s@%s local %s@%s", + (url1_contact->username) ? url1_contact->username : "*NULL*", + (url1_contact->host) ? url1_contact->host : "*NULL*", + (url1_contact->username) ? url1_contact->username : "*NULL*", + addrstr); + urlmap[i].masq_url->host=realloc(urlmap[i].masq_url->host, + strlen(addrstr)+1); + strcpy(urlmap[i].masq_url->host, addrstr); + } + + /* remember the VIA for later use */ osip_via_clone( ((osip_via_t*)(my_msg->vias->node->element)), - &urlmap[i].via); /* via field */ + &urlmap[i].via); } /* if new entry */ /* give some safety margin for the next update */ diff --git a/src/rewrite_rules.h b/src/rewrite_rules.h index 6abca94..6ee0087 100644 --- a/src/rewrite_rules.h +++ b/src/rewrite_rules.h @@ -43,7 +43,7 @@ static struct { {"Windows RTC", {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, {"KPhone", {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, /* the following line holds the default entries */ -{NULL, { 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1}} +{NULL, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}} }; static struct { diff --git a/src/rtpproxy_masq.c b/src/rtpproxy_masq.c index d29f926..e2aa4f1 100644 --- a/src/rtpproxy_masq.c +++ b/src/rtpproxy_masq.c @@ -104,6 +104,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, int sts, i; int freeidx; time_t t; + osip_call_id_t cid; if (callid == NULL) { ERROR("rtp_relay_start_fwd: callid is NULL!"); @@ -117,13 +118,13 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, * so if this test fails maybe it's just necessary to increase * the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE. */ - if (strlen(callid->number) > CALLIDNUM_SIZE) { + if (callid->number && strlen(callid->number) > CALLIDNUM_SIZE) { ERROR("rtp_relay_start_fwd: received callid number " "has too many characters (%i, max=%i)", strlen(callid->number),CALLIDNUM_SIZE); return STS_FAILURE; } - if (strlen(callid->host) > CALLIDHOST_SIZE) { + if (callid->host && strlen(callid->host) > CALLIDHOST_SIZE) { ERROR("rtp_relay_start_fwd: received callid host " "has too many characters (%i, max=%i)", strlen(callid->host),CALLIDHOST_SIZE); @@ -139,8 +140,8 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, */ time(&t); for (i=0; inumber)==0) && - (strcmp(rtp_proxytable[i].callid_host, callid->host)==0) && - (rtp_proxytable[i].media_stream_no == media_stream_no) ) { + cid.number = rtp_proxytable[i].callid_number; + cid.host = rtp_proxytable[i].callid_host; + if (rtp_proxytable[i].sock && + (compare_callid(callid, &cid) == STS_SUCCESS) && + (rtp_proxytable[i].media_stream_no == media_stream_no)) { /* return the already known port number */ DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i, " "id=%s, #=%i)", rtp_proxytable[i].outboundport, @@ -210,8 +213,19 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, /* write entry into rtp_proxytable slot (freeidx) */ DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: using proxy slot %i",freeidx); rtp_proxytable[freeidx].sock=1; - strcpy(rtp_proxytable[freeidx].callid_number, callid->number); - strcpy(rtp_proxytable[freeidx].callid_host, callid->host); + + if (callid->number) { + strcpy(rtp_proxytable[freeidx].callid_number, callid->number); + } else { + rtp_proxytable[freeidx].callid_number[0]='\0'; + } + + if (callid->host) { + strcpy(rtp_proxytable[freeidx].callid_host, callid->host); + } else { + rtp_proxytable[freeidx].callid_host[0]='\0'; + } + rtp_proxytable[freeidx].media_stream_no = media_stream_no; memcpy(&rtp_proxytable[freeidx].outbound_ipaddr, &outbound_ipaddr, sizeof(struct in_addr)); @@ -223,7 +237,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, } DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: masq address & port:%s:%i", - inet_ntoa(outbound_ipaddr),outbound_lcl_port); + inet_ntoa(outbound_ipaddr),*outbound_lcl_port); return (*outbound_lcl_port)?STS_SUCCESS:STS_FAILURE; } @@ -231,6 +245,7 @@ int rtp_masq_start_fwd(osip_call_id_t *callid, int media_stream_no, int rtp_masq_stop_fwd(osip_call_id_t *callid) { int i; int got_match=0; + osip_call_id_t cid; /* let the UDP tunnel time-out */ @@ -240,10 +255,10 @@ int rtp_masq_stop_fwd(osip_call_id_t *callid) { } for (i=0; inumber==NULL) || (callid->host==NULL)) break; - if( rtp_proxytable[i].sock && - (strcmp(rtp_proxytable[i].callid_number, callid->number)==0) && - (strcmp(rtp_proxytable[i].callid_host, callid->host)==0) ) { + cid.number = rtp_proxytable[i].callid_number; + cid.host = rtp_proxytable[i].callid_host; + if (rtp_proxytable[i].sock && + (compare_callid(callid, &cid) == STS_SUCCESS)) { DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: cleaning proxy slot %i",i); memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0])); got_match=1; @@ -305,7 +320,7 @@ static int _create_listening_masq(struct ip_masq_ctl *masq, if (setsockopt(masq_ctl_sock, IPPROTO_IP, IP_FW_MASQ_CTL, (char *)masq, sizeof(*masq))) { - ERROR("create_listening_masq: setsockopt() failed: %s", + DEBUGC(DBCLASS_RTP, "create_listening_masq: setsockopt() failed: %s", strerror(errno)); sts = STS_FAILURE; goto exit; diff --git a/src/rtpproxy_relay.c b/src/rtpproxy_relay.c index 0311f26..55e77e4 100644 --- a/src/rtpproxy_relay.c +++ b/src/rtpproxy_relay.c @@ -234,6 +234,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, int sock, port; int freeidx; int sts=STS_SUCCESS; + osip_call_id_t cid; if (callid == NULL) { ERROR("rtp_relay_start_fwd: callid is NULL!"); @@ -247,13 +248,13 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, * so if this test fails maybe it's just necessary to increase * the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE. */ - if (strlen(callid->number) > CALLIDNUM_SIZE) { + if (callid->number && strlen(callid->number) > CALLIDNUM_SIZE) { ERROR("rtp_relay_start_fwd: received callid number " "has too many characters (%i, max=%i)", strlen(callid->number),CALLIDNUM_SIZE); return STS_FAILURE; } - if (strlen(callid->host) > CALLIDHOST_SIZE) { + if (callid->host && strlen(callid->host) > CALLIDHOST_SIZE) { ERROR("rtp_relay_start_fwd: received callid host " "has too many characters (%i, max=%i)", strlen(callid->host),CALLIDHOST_SIZE); @@ -281,16 +282,18 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int media_stream_no, * media_stream_no). This can be due to UDP repetitions of the * INVITE request... */ - for (j=0; jnumber)==0) && - (strcmp(rtp_proxytable[j].callid_host, callid->host)==0) && - (rtp_proxytable[j].media_stream_no == media_stream_no) ) { + for (i=0; inumber); - strcpy(rtp_proxytable[freeidx].callid_host, callid->host); + + if (callid->number) { + strcpy(rtp_proxytable[freeidx].callid_number, callid->number); + } else { + rtp_proxytable[freeidx].callid_number[0]='\0'; + } + + if (callid->host) { + strcpy(rtp_proxytable[freeidx].callid_host, callid->host); + } else { + rtp_proxytable[freeidx].callid_host[0]='\0'; + } + rtp_proxytable[freeidx].media_stream_no = media_stream_no; memcpy(&rtp_proxytable[freeidx].outbound_ipaddr, &outbound_ipaddr, sizeof(struct in_addr)); @@ -392,6 +406,7 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock) { int i, sts; int retsts=STS_SUCCESS; int got_match=0; + osip_call_id_t cid; if (callid == NULL) { ERROR("rtp_relay_stop_fwd: callid is NULL!"); @@ -433,10 +448,10 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid, int nolock) { * media strema active for the same callid (audio + video stream) */ for (i=0; inumber==NULL) || (callid->host==NULL)) break; - if( rtp_proxytable[i].sock && - (strcmp(rtp_proxytable[i].callid_number, callid->number)==0) && - (strcmp(rtp_proxytable[i].callid_host, callid->host)==0) ) { + cid.number = rtp_proxytable[i].callid_number; + cid.host = rtp_proxytable[i].callid_host; + if (rtp_proxytable[i].sock && + (compare_callid(callid, &cid) == STS_SUCCESS)) { sts = close(rtp_proxytable[i].sock); DEBUGC(DBCLASS_RTP,"closed socket %i for RTP stream " "%s:%s == %s:%s (idx=%i) sts=%i", diff --git a/src/sip_utils.c b/src/sip_utils.c index 10a7af6..5499f37 100644 --- a/src/sip_utils.c +++ b/src/sip_utils.c @@ -254,7 +254,7 @@ int compare_url(osip_uri_t *url1, osip_uri_t *url2) { /* let's be nice to Billy boy and don't complain evey time ;-) // WARN("compare_url: NULL username pointer: MSN messenger is known to " // "trigger this one!"); */ - DEBUGC(DBCLASS_DNS, "comparing broken urls (no user): " + DEBUGC(DBCLASS_PROXY, "comparing broken urls (no user): " "%s[%s] -> %s[%s]", url1->host, inet_ntoa(addr1), url2->host, inet_ntoa(addr2)); if (memcmp(&addr1, &addr2, sizeof(addr1))==0) { @@ -267,7 +267,7 @@ int compare_url(osip_uri_t *url1, osip_uri_t *url2) { /* we have a proper URL */ /* comparison of hosts should be based on IP addresses, no? */ - DEBUGC(DBCLASS_DNS, "comparing urls: %s@%s[%s] -> %s@%s[%s]", + DEBUGC(DBCLASS_PROXY, "comparing urls: %s@%s[%s] -> %s@%s[%s]", url1->username, url1->host, inet_ntoa(addr1), url2->username, url2->host, inet_ntoa(addr2)); if ((strcmp(url1->username, url2->username)==0) && @@ -281,6 +281,64 @@ int compare_url(osip_uri_t *url1, osip_uri_t *url2) { } +/* + * compares two Call IDs + * (by now, only hostname and username are compared) + * + * RETURNS + * STS_SUCCESS if equal + * STS_FAILURE if non equal or error + */ +int compare_callid(osip_call_id_t *cid1, osip_call_id_t *cid2) { + + if ((cid1==0) || (cid2==0)) { + ERROR("compare_callid: NULL ptr: cid1=0x%p, cid2=0x%p",cid1, cid2); + return STS_FAILURE; + } + + /* + * Check number part: if present must be equal, + * if not present, must be not present in both cids + */ + if (cid1->number && cid2->number) { + /* have both numbers */ + if (strcmp(cid1->number, cid2->number) != 0) goto mismatch; + } else { + /* at least one number missing, make sure that both are empty */ + if ( (cid1->number && (cid1->number[0]!='\0')) || + (cid2->number && (cid2->number[0]!='\0'))) { + goto mismatch; + } + } + + /* + * Check host part: if present must be equal, + * if not present, must be not present in both cids + */ + if (cid1->host && cid2->host) { + /* have both hosts */ + if (strcmp(cid1->host, cid2->host) != 0) goto mismatch; + } else { + /* at least one host missing, make sure that both are empty */ + if ( (cid1->host && (cid1->host[0]!='\0')) || + (cid2->host && (cid2->host[0]!='\0'))) { + goto mismatch; + } + } + + DEBUGC(DBCLASS_BABBLE, "comparing callid - matched: " + "%s@%s <-> %s@%s", + cid1->number, cid1->host, cid2->number, cid2->host); + return STS_FAILURE; + +mismatch: + DEBUGC(DBCLASS_BABBLE, "comparing callid - mismatch: " + "%s@%s <-> %s@%s", + cid1->number, cid1->host, cid2->number, cid2->host); + return STS_FAILURE; +} + + /* * check if a given request is addressed to local. I.e. it is addressed * to the porxy itself (IP of my inbound or outbound interface, same port) diff --git a/src/siproxd.c b/src/siproxd.c index f2e724c..6e3491e 100644 --- a/src/siproxd.c +++ b/src/siproxd.c @@ -238,13 +238,30 @@ INFO("got packet [%i bytes]from %s [%s]", i, inet_ntoa(from.sin_addr), tmp);} my_msg->sip_method : "NULL") ; /* - * if RQ REGISTER, just register - * and send an answer + * if an RQ REGISTER, check if it is directed to myself, + * or am I just the outbound proxy but no registrar. + * - If I'm the registrar, register & generate answer + * - If I'm just the outbound proxy, register, rewrite & forward */ if (MSG_IS_REGISTER(my_msg) && MSG_IS_REQUEST(my_msg)) { if (access & ACCESSCTL_REG) { - sts = register_client(my_msg); - sts = register_response(my_msg, sts); + osip_uri_t *url; + struct in_addr addr1, addr2; + + url = osip_message_get_uri(my_msg); + sts = get_ip_by_host(url->host, &addr1); + sts = get_ip_by_ifname(configuration.inbound_if,&addr2); + + if (memcmp(&addr1, &addr2, sizeof(addr1)) == 0) { + /* I'm the registrar, send response myself */ + sts = register_client(my_msg, 0); + sts = register_response(my_msg, sts); + } else { + /* I'm just the outbound proxy */ + DEBUGC(DBCLASS_SIP,"proxying REGISTER request to:%s",url->host); + sts = register_client(my_msg, 1); + sts = proxy_request(my_msg); + } } else { WARN("non-authorized registration attempt from %s", inet_ntoa(from.sin_addr)); diff --git a/src/siproxd.h b/src/siproxd.h index 0d7364f..1d8a7b6 100644 --- a/src/siproxd.h +++ b/src/siproxd.h @@ -30,15 +30,15 @@ int sockbind(struct in_addr ipaddr, int localport, int errflg); /* register.c */ void register_init(void); -int register_client(osip_message_t *request); /*X*/ +int register_client(osip_message_t *request, int force_lcl_masq); /*X*/ void register_agemap(void); -int register_response(osip_message_t *request, int flag); /*X*/ +int register_response(osip_message_t *request, int flag); /*X*/ /* proxy.c */ -int proxy_request (osip_message_t *request); /*X*/ -int proxy_response (osip_message_t *response); /*X*/ -int proxy_rewrite_invitation_body(osip_message_t *mymsg); /*X*/ -int proxy_rewrite_request_uri(osip_message_t *mymsg, int idx); /*X*/ +int proxy_request (osip_message_t *request); /*X*/ +int proxy_response (osip_message_t *response); /*X*/ +int proxy_rewrite_invitation_body(osip_message_t *mymsg); /*X*/ +int proxy_rewrite_request_uri(osip_message_t *mymsg, int idx); /*X*/ /* utils.c */ int get_ip_by_host(char *hostname, struct in_addr *addr); /*X*/ @@ -47,23 +47,24 @@ int get_ip_by_ifname(char *ifname, struct in_addr *retaddr); /*X*/ /* sip_utils.c */ osip_message_t * msg_make_template_reply (osip_message_t * request, int code); -int check_vialoop (osip_message_t *my_msg); /*X*/ -int is_via_local (osip_via_t *via); /*X*/ -int compare_url(osip_uri_t *url1, osip_uri_t *url2); /*X*/ -int is_sipuri_local (osip_message_t *sip); /*X*/ -int check_rewrite_rq_uri (osip_message_t *sip); /*X*/ -int sip_gen_response(osip_message_t *request, int code); /*X*/ +int check_vialoop (osip_message_t *my_msg); /*X*/ +int is_via_local (osip_via_t *via); /*X*/ +int compare_url(osip_uri_t *url1, osip_uri_t *url2); /*X*/ +int compare_callid(osip_call_id_t *cid1, osip_call_id_t *cid2); /*X*/ +int is_sipuri_local (osip_message_t *sip); /*X*/ +int check_rewrite_rq_uri (osip_message_t *sip); /*X*/ +int sip_gen_response(osip_message_t *request, int code); /*X*/ #define IF_OUTBOUND 0 #define IF_INBOUND 1 -int sip_add_myvia (osip_message_t *request, int interface); /*X*/ -int sip_del_myvia (osip_message_t *response); /*X*/ +int sip_add_myvia (osip_message_t *request, int interface); /*X*/ +int sip_del_myvia (osip_message_t *response); /*X*/ /* readconf.c */ int read_config(char *name, int search); /*X*/ /* rtpproxy.c */ int rtpproxy_init( void ); /*X*/ -int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no, /*X*/ +int rtp_start_fwd (osip_call_id_t *callid, int media_stream_no, /*X*/ struct in_addr outbound_ipaddr, int *outboundport, struct in_addr lcl_client_ipaddr, int lcl_clientport); int rtp_stop_fwd (osip_call_id_t *callid); /*X*/ @@ -73,12 +74,12 @@ void rtpproxy_kill( void ); /*X*/ int accesslist_check(struct sockaddr_in from); /* security.c */ -int security_check_raw(char *sip_buffer, int size); /*X*/ -int security_check_sip(osip_message_t *sip); /*X*/ +int security_check_raw(char *sip_buffer, int size); /*X*/ +int security_check_sip(osip_message_t *sip); /*X*/ /* auth.c */ -int authenticate_proxy(osip_message_t *request); /*X*/ -int auth_include_authrq(osip_message_t *response); /*X*/ +int authenticate_proxy(osip_message_t *request); /*X*/ +int auth_include_authrq(osip_message_t *response); /*X*/