📄 sip_utils.c
字号:
/* -*- Mode: C; c-basic-offset: 3 -*- Copyright (C) 2002 Thomas Ries <tries@gmx.net> This file is part of Siproxd. Siproxd 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. Siproxd 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 Siproxd; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "config.h"#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <time.h>#include <signal.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <net/if.h>#include <sys/ioctl.h>#include <sys/types.h>#include <pwd.h>#include <osipparser2/osip_parser.h>#include <osipparser2/osip_port.h>#include <osipparser2/osip_md5.h>#include "siproxd.h"#include "digcalc.h"#include "rewrite_rules.h"#include "log.h"static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-" BUILDSTR " $";/* configuration storage */extern struct siproxd_config configuration;extern int h_errno;extern int sip_socket; /* sending SIP datagrams */extern struct urlmap_s urlmap[]; /* URL mapping table *//* * create a reply template from an given SIP request * * RETURNS a pointer to osip_message_t */osip_message_t *msg_make_template_reply (osip_message_t * request, int code) { osip_message_t *response; int pos; osip_message_init (&response); response->message=NULL; osip_message_set_version (response, osip_strdup ("SIP/2.0")); osip_message_set_status_code (response, code); osip_message_set_reason_phrase (response, osip_strdup(osip_message_get_reason (code))); if (request->to==NULL) { ERROR("msg_make_template_reply: empty To in request header"); } if (request->from==NULL) { ERROR("msg_make_template_reply: empty From in request header"); } osip_to_clone (request->to, &response->to); osip_from_clone (request->from, &response->from); /* via headers */ pos = 0; while (!osip_list_eol (request->vias, pos)) { char *tmp; osip_via_t *via; via = (osip_via_t *) osip_list_get (request->vias, pos); osip_via_to_str (via, &tmp); osip_message_set_via (response, tmp); osip_free (tmp); pos++; } osip_call_id_clone(request->call_id,&response->call_id); osip_cseq_clone(request->cseq,&response->cseq); return response;}/* * check for a via loop. * It checks for the presense of a via entry that holds one of * my IP addresses and is *not* the topmost via. * * RETURNS * STS_TRUE if loop detected * STS_FALSE if no loop */int check_vialoop (osip_message_t *my_msg) {/*!!! actually this is a problematic one.1) for requests, I must search the whole VIA list (topmost via is the previos station in the path)2) for responses I must skip the topmost via, as this is mine (and will be removed later on)3) What happens if we have 'clashes' with private addresses?? From that point of view, siproxd *should* not try to check against it's local IF addresses if they are private. this then of course again can lead to a endless loop... -> Use a fixed unique part of branch parameter to identify that it is MY via can we use something like a Tag in via headers?? (a veriy likely to-be-unique ID)*/ int sts; int pos; int found_own_via; found_own_via=0; pos = 1; /* for detecting a loop, don't check the first entry as this is my own VIA! */ while (!osip_list_eol (my_msg->vias, pos)) { osip_via_t *via; via = (osip_via_t *) osip_list_get (my_msg->vias, pos); sts = is_via_local (via); if (sts == STS_TRUE) found_own_via+=1; pos++; } /* * what happens if a message is coming back to me legally? * UA1 -->--\ /-->--\ * siproxd Registrar * UA2 --<--/ \--<--/ * * This may also lead to a VIA loop - so I probably must take the branch * parameter into count (or a unique part of it) OR just allow at least 2 * vias of my own. */ return (found_own_via>2)? STS_TRUE : STS_FALSE;}/* * check if a given osip_via_t is local. I.e. its address is owned * by my inbound or outbound interface * * RETURNS * STS_TRUE if the given VIA is one of my interfaces * STS_FALSE otherwise */int is_via_local (osip_via_t *via) { int sts, found; struct in_addr addr_via, addr_myself; char *my_interfaces[]= { configuration.inbound_if, configuration.outbound_if, (char*)-1 }; int port; int i; char *ptr; if (via==NULL) { ERROR("called is_via_local with NULL via"); return STS_FALSE; } DEBUGC(DBCLASS_BABBLE,"via name %s",via->host); if (utils_inet_aton(via->host,&addr_via) == 0) { /* need name resolution */ sts=get_ip_by_host(via->host, &addr_via); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_DNS, "is_via_local: cannot resolve VIA [%s]", via->host); return STS_FAILURE; } } found=0; for (i=0; ; i++) { /* * try to search by interface name first */ ptr=my_interfaces[i]; if (ptr==(char*)-1) break; /* end of list mark */ if (ptr) { DEBUGC(DBCLASS_BABBLE,"resolving IP of interface %s",ptr); sts = get_ip_by_ifname(ptr, &addr_myself); } /* check the extracted VIA against my own host addresses */ if (via->port) port=atoi(via->port); else port=SIP_PORT; if ( (memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) && (port == configuration.sip_listen_port) ) { DEBUG("got address match [%s]", utils_inet_ntoa(addr_via)); found=1; break; } } return (found)? STS_TRUE : STS_FALSE;}/* * compares two URLs * (by now, only scheme, hostname and username are compared) * * RETURNS * STS_SUCCESS if equal * STS_FAILURE if non equal or error */int compare_url(osip_uri_t *url1, osip_uri_t *url2) { int sts1, sts2; struct in_addr addr1, addr2; /* sanity checks */ if ((url1 == NULL) || (url2 == NULL)) { ERROR("compare_url: NULL ptr: url1=0x%p, url2=0x%p",url1, url2); return STS_FAILURE; } /* sanity checks: host part is a MUST */ if ((url1->host == NULL) || (url2->host == NULL)) { ERROR("compare_url: NULL ptr: url1->host=0x%p, url2->host=0x%p", url1->host, url2->host); return STS_FAILURE; } DEBUGC(DBCLASS_PROXY, "comparing urls: %s:%s@%s -> %s:%s@%s", (url1->scheme) ? url1->scheme : "(null)", (url1->username) ? url1->username : "(null)", (url1->host) ? url1->host : "(null)", (url2->scheme) ? url2->scheme : "(null)", (url2->username) ? url2->username : "(null)", (url2->host) ? url2->host : "(null)"); /* compare SCHEME (if present) case INsensitive */ if (url1->scheme && url2->scheme) { if (strcasecmp(url1->scheme, url2->scheme) != 0) { DEBUGC(DBCLASS_PROXY, "compare_url: scheme mismatch"); return STS_FAILURE; } } else { WARN("compare_url: NULL scheme - ignoring"); } /* compare username (if present) case sensitive */ if (url1->username && url2->username) { if (strcmp(url1->username, url2->username) != 0) { DEBUGC(DBCLASS_PROXY, "compare_url: username mismatch"); return STS_FAILURE; } } else { WARN("compare_url: NULL username - ignoring"); } /* * now, try to resolve the host. If resolveable, compare * IP addresses - if not resolveable, compare the host names * itselfes */ /* get the IP addresses from the (possible) hostnames */ sts1=get_ip_by_host(url1->host, &addr1); if (sts1 == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "compare_url: cannot resolve host [%s]", url1->host); } sts2=get_ip_by_host(url2->host, &addr2); if (sts2 == STS_FAILURE) { DEBUGC(DBCLASS_PROXY, "compare_url: cannot resolve host [%s]", url2->host); } if ((sts1 == STS_SUCCESS) && (sts2 == STS_SUCCESS)) { /* compare IP addresses */ if (memcmp(&addr1, &addr2, sizeof(addr1))!=0) { DEBUGC(DBCLASS_PROXY, "compare_url: IP mismatch"); return STS_FAILURE; } } else { /* compare hostname strings case INsensitive */ if (strcasecmp(url1->host, url2->host) != 0) { DEBUGC(DBCLASS_PROXY, "compare_url: host name mismatch"); return STS_FAILURE; } } /* the two URLs did pass all tests successfully - MATCH */ return STS_SUCCESS;}/* * 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_SUCCESS;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) * * RETURNS * STS_TRUE if the request is addressed local * STS_FALSE otherwise */int is_sipuri_local (osip_message_t *sip) { int sts, found; struct in_addr addr_uri, addr_myself; char *my_interfaces[]= { configuration.inbound_if, configuration.outbound_if, (char*)-1 }; int port; int i; char *ptr; if (sip==NULL) { ERROR("called is_sipuri_local with NULL sip"); return STS_FALSE; } if (!sip || !sip->req_uri) { ERROR("is_sipuri_local: no request URI present"); return STS_FALSE; } DEBUGC(DBCLASS_DNS,"check for local SIP URI %s:%s", sip->req_uri->host? sip->req_uri->host : "*NULL*", sip->req_uri->port? sip->req_uri->port : "*NULL*"); if (utils_inet_aton(sip->req_uri->host, &addr_uri) == 0) { /* need name resolution */ get_ip_by_host(sip->req_uri->host, &addr_uri); } found=0; for (i=0; ; i++) { /* * try to search by interface name first */ ptr=my_interfaces[i]; if (ptr==(char*)-1) break; /* end of list mark */ if (ptr) { DEBUGC(DBCLASS_BABBLE,"resolving IP of interface %s",ptr); sts = get_ip_by_ifname(ptr, &addr_myself); } /* check the extracted HOST against my own host addresses */ if (sip->req_uri->port) { port=atoi(sip->req_uri->port); } else { port=SIP_PORT; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -