void processSipMsg() { int port; char host[256]; char msg[MESSAGE_MAX_LENGTH]; int msgLen; osip_event_t *sipevent; osip_transaction_t *transaction = NULL; struct sockaddr_in sa; int status; if((msgLen = networkMsgRecv(sipSock,msg,MESSAGE_MAX_LENGTH,&sa)) > 0){ printf("processSipMsg: RECEIVED MSG\n"); printf("%s\n",msg); sipevent = osip_parse(msg,msgLen); if((sipevent==NULL)||(sipevent->sip==NULL)){ printf("Could not parse SIP message\n"); osip_event_free(sipevent); return; } } osip_message_fix_last_via_header(sipevent->sip,(char *)inet_ntoa(sa.sin_addr),ntohs(sa.sin_port)); if((status = osip_find_transaction_and_add_event(osip,sipevent)) != 0){ printf("New transaction!\n"); if(MSG_IS_REQUEST(sipevent->sip)){ printf("Got New Request\n");; }else if(MSG_IS_RESPONSE(sipevent->sip)){ printf("Bad Message:%s\n",msg); osip_event_free(sipevent); }else{ printf("Unsupported message:%s\n",msg); osip_event_free(sipevent); } } }
static int ac_packetfilter_trust(ac_sip_t *asip, void *data) { osip_message_t* sip = asip->req->evt->sip; LOG_DEBUG("Performing trust ac on %s->%s\n", asip->from, asip->to); /* filter only inbound, non-response sessions */ if (asip->req->remote_msg && !MSG_IS_RESPONSE(sip) && (MSG_IS_INVITE(sip) || MSG_IS_MESSAGE(sip)) && asip->verdict == AC_VERDICT_NONE) { /* check max path */ if (max_path > 0) { int pathlen = -1; /* the default unless proven otherwise.. */ asip->verdict = AC_VERDICT_REJECT; pathlen = trustman_get_pathlen(asip->from, asip->to); LOG_DEBUG("Will check params, trust path data: %d, limit: %d\n", pathlen, max_path); if ((pathlen > -1) && (pathlen <= max_path)) { asip->verdict = AC_VERDICT_NONE; } else { LOG_DEBUG("No trust parameters got, skipping as we require max %d\n", max_path); } } } return 1; }
static int ac_packetfilter_simple(ac_sip_t *asip, void *data) { osip_message_t* sip = asip->req->evt->sip; int code = osip_message_get_status_code(sip); LOG_DEBUG("Performing simple ac on %s->%s, remote: %d\n", asip->from, asip->to, asip->req->remote_msg); /* filter only inbound */ if (asip->req->remote_msg && !asip->req->internally_generated) { /* todo: we should check that the sip from == the aor associated with the connection (on remote calls) */ /* except that that would mess up the gateway things. */ //ASSERT_ZERO(sipp_get_sip_aors_simple(sip, &local_aor, &remote_aor, 1), end); /* if ((!MSG_IS_RESPONSE(asip->evt->sip) && (strcmp(asip->from, asip->remote) || strcmp(asip->to, asip->local))) || (MSG_IS_RESPONSE(asip->evt->sip) && (strcmp(asip->to, asip->remote) || strcmp(asip->from, asip->local)))) asip->verdict = AC_VERDICT_REJECT; else */ if (MSG_IS_RESPONSE(sip)) { /* reject 482 merges, as server loops aren't of any interest to us */ if (code == 482) { LOG_WARN("Skipping %d response\n", code); asip->verdict = AC_VERDICT_REJECT; } } else if (MSG_IS_ACK(sip) || MSG_IS_BYE(sip) || MSG_IS_CANCEL(sip) || MSG_IS_UPDATE(sip)) { /* this we should let through pretty much undisturbed */ } else if (MSG_IS_SUBSCRIBE(sip) || MSG_IS_PUBLISH(sip)) { /* if this is remotely got, just reject */ asip->verdict = AC_VERDICT_REJECT; } else if (MSG_IS_INVITE(sip) || MSG_IS_MESSAGE(sip)) { /* hm, nothing.. */ // } else if (MSG_IS_NOTIFY(sip)) { } else { /* todo: what about OPTIONS? */ LOG_WARN("Got unsupported request\n"); asip->verdict = AC_VERDICT_UNSUPP; } } else { /* allow *all* outgoing! */ asip->verdict = AC_VERDICT_ALLOW; } return 1; }
static int ac_packetfilter_op(ac_sip_t *asip, void *data) { osip_message_t* sip = asip->evt->sip; LOG_DEBUG("Performing op ac on %s->%s\n", asip->from, asip->to); /* filter only inbound, non-response sessions */ if (asip->remotely_got && !MSG_IS_RESPONSE(sip) && (MSG_IS_INVITE(sip) || MSG_IS_MESSAGE(sip)) && asip->verdict == AC_VERDICT_NONE) { int is_known = 0; char* key = 0; reg_package_t *reg = 0; /* check identity key */ if ((reg = ident_find_foreign_reg(asip->from))) { key = ident_data_get_pkey_base64(reg->cert); if (key) opconn_known(key, &is_known); if (is_known) LOG_DEBUG("we know the user's key\n"); freez(key); ship_unlock(reg); } /* check trustman info */ if (!is_known) { key = trustman_op_get_verification_key(asip->from, asip->to); if (key) opconn_known(key, &is_known); if (is_known) LOG_DEBUG("we know the verificator of the user's key\n"); freez(key); } switch (op_filtering) { case 0: /* block unknown */ if (!is_known) //is_unknown) asip->verdict = AC_VERDICT_REJECT; break; case 2: /* allow known */ if (is_known) asip->verdict = AC_VERDICT_ALLOW; break; default: /* nothing / unknkown */ break; } } return 1; }
static int ac_packetfilter_debug(ac_sip_t *asip, void *data) { if (MSG_IS_RESPONSE(asip->req->evt->sip)) { LOG_INFO("PACKETFILTERING: Got a %d response from %s to %s (channel %s:%s, remotely got: %d, internal: %d, filter: %d)\n", osip_message_get_status_code(asip->req->evt->sip), asip->from, asip->to, asip->req->local_aor, asip->req->remote_aor, asip->req->remote_msg, asip->req->internally_generated, asip->filter); } else { LOG_INFO("PACKETFILTERING: Got a %s request from %s to %s (channel %s:%s, remotely got: %d, internal: %d, filter: %d)\n", asip->req->evt->sip->sip_method, asip->from, asip->to, asip->req->local_aor, asip->req->remote_aor, asip->req->remote_msg, asip->req->internally_generated, asip->filter); } return 1; }
/* currently not used, unstatified to supress compiler warning .. */ static int ac_packetfilter_http(ac_sip_t *asip) { char *data = 0, *tmp = 0; int pathlen = -1; int len = 0, size = 0; char buf[32]; if (!http_ac || !strlen(http_ac)) goto err; LOG_DEBUG("Performing http ac on %s->%s\n", asip->from, asip->to); pathlen = trustman_get_pathlen(asip->from, asip->to); sprintf(buf, "%d", pathlen); /* create a nice post param packet from this */ ASSERT_TRUE((tmp = ship_addparam_urlencode("p2pship_ver", "1", data, &size, &len)) && (data = tmp), err); ASSERT_TRUE((tmp = ship_addparam_urlencode("from", asip->from, data, &size, &len)) && (data = tmp), err); ASSERT_TRUE((tmp = ship_addparam_urlencode("to", asip->to, data, &size, &len)) && (data = tmp), err); ASSERT_TRUE((tmp = ship_addparam_urlencode("type", (asip->evt->sip->sip_method?asip->evt->sip->sip_method:""), data, &size, &len)) && (data = tmp), err); ASSERT_TRUE((tmp = ship_addparam_urlencode("response", (MSG_IS_RESPONSE(asip->evt->sip)? "yes":"no"), data, &size, &len)) && (data = tmp), err); ASSERT_TRUE((tmp = ship_addparam_urlencode("local", (asip->local?asip->local:""), data, &size, &len)) && (data = tmp), err); ASSERT_TRUE((tmp = ship_addparam_urlencode("remote", (asip->remote?asip->remote:""), data, &size, &len)) && (data = tmp), err); ASSERT_TRUE((tmp = ship_addparam_urlencode("pathlen", buf, data, &size, &len)) && (data = tmp), err); if (!netio_http_post_host(http_ac, "/validate", "", "application/x-www-form-urlencoded", data, len, ac_packetfilter_http_cb, asip)) { asip = 0; } err: freez(data); if (asip) return 1; else return 0; }
/* This method just add a received parameter in the Via as requested by rfc3261 */ int osip_message_fix_last_via_header(osip_message_t * request, const char *ip_addr, int port) { osip_generic_param_t *rport; osip_via_t *via; /* get Top most Via header: */ if (request == NULL) return OSIP_BADPARAMETER; if (MSG_IS_RESPONSE(request)) return OSIP_SUCCESS; /* Don't fix Via header */ via = osip_list_get(&request->vias, 0); if (via == NULL || via->host == NULL) /* Hey, we could build it? */ return OSIP_BADPARAMETER; osip_via_param_get_byname(via, "rport", &rport); if (rport != NULL) { if (rport->gvalue == NULL) { rport->gvalue = (char *) osip_malloc(9); if (rport->gvalue == NULL) return OSIP_NOMEM; #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf(rport->gvalue, 8, "%i", port); #else snprintf(rport->gvalue, 8, "%i", port); #endif } /* else bug? */ } /* only add the received parameter if the 'sent-by' value does not contains this ip address */ if (0 == strcmp(via->host, ip_addr)) /* don't need the received parameter */ return OSIP_SUCCESS; osip_via_set_received(via, osip_strdup(ip_addr)); return OSIP_SUCCESS; }
/* This method just add a received parameter in the Via as requested by rfc3261 */ int msg_fix_last_via_header (sip_t * request, char *ip_addr, int port) { generic_param_t *rport; via_t *via; /* get Top most Via header: */ if (request == NULL || request->strtline == NULL) return -1; if (MSG_IS_RESPONSE (request)) return 0; /* Don't fix Via header */ via = list_get (request->vias, 0); if (via == NULL || via->host == NULL) /* Hey, we could build it? */ return -1; via_param_getbyname (via, "rport", &rport); if (rport != NULL) { if (rport->gvalue == NULL) { rport->gvalue = (char *) smalloc (9); #if (defined WIN32 || defined _WIN32_WCE) _snprintf (rport->gvalue, 8, "%i", port); #else snprintf (rport->gvalue, 8, "%i", port); #endif } /* else bug? */ } /* only add the received parameter if the 'sent-by' value does not contains this ip address */ if (0 == strcmp (via->host, ip_addr)) /* don't need the received parameter */ return 0; via_set_received (via, sgetcopy (ip_addr)); return 0; }
static int ac_packetfilter_stats(ac_sip_t *asip, void *data) { osip_message_t* sip = asip->evt->sip; char *callid = 0; unsigned long now = ship_systemtimemillis(); if (asip->remotely_got) { /* .. meaning remotely got */ if (MSG_IS_RESPONSE(sip)) { pdd_stat_t *stat = 0; int code = osip_message_get_status_code(sip); /* check for ACK with code != 100 */ callid = sipp_get_call_id(sip); ship_lock(stats) ; if (code != 100 && (stat = ship_ht_get_string(stats, callid)) && !stat->end) { stat->end = ship_systemtimemillis(); LOG_INFO("Got PDD for %s %s -> %s (status %d) in %u.%03u seconds..\n", stat->msg_type, stat->from, stat->to, code, (stat->end - stat->start) / 1000, ((stat->end - stat->start) % 1000)); /* ... if we are recording special, then do that! */ if (pdd_log) { pdd_record_pdd(stat); } /* remove.. ? */ ship_ht_remove_string(stats, callid); ship_lock(done_stats); while (ship_list_length(done_stats) > 20) { pdd_stat_t *s2 = ship_list_pop(done_stats); ship_ht_remove(done_stats_ht, s2); pdd_free_stat(s2); } ship_list_add(done_stats, stat); ship_ht_put_string(done_stats_ht, callid, stat); ship_unlock(done_stats); } ship_unlock(stats); } else if (MSG_IS_INVITE(sip) || MSG_IS_MESSAGE(sip)) { /* record the pdd for the other fellow .. */ callid = sipp_get_call_id(sip); /* send 'stats' packet back, event remote_req */ ac_send_stats(asip->remote, asip->local, now, callid, "remote_start"); } } else { /* if we get an invite or something like that, record the time .. and so on */ if (MSG_IS_INVITE(sip) || MSG_IS_MESSAGE(sip)) { /* if not seen already & pdd mode, do some funky stuff.. */ if (pdd_reset_mode) { LOG_INFO("pdd measurement mode: clearing SAs and peer DB!\n"); #ifdef CONFIG_HIP_ENABLED hipapi_clear_sas(); #endif ident_reset_foreign_regs(); conn_close_all(); } callid = sipp_get_call_id(sip); ship_lock(stats); if (!ship_ht_get_string(stats, callid)) { pdd_stat_t *stat = pdd_new_stat(sip, asip->from, asip->to); if (stat) { stat->start = ship_systemtimemillis(); ship_ht_put_string(stats, callid, stat); } } ship_unlock(stats); } else if (MSG_IS_RESPONSE(sip)) { int code = osip_message_get_status_code(sip); if (code != 100) { callid = sipp_get_call_id(sip); /* send 'stats' packet back, event remote_resp */ ac_send_stats(asip->remote, asip->local, now, callid, "remote_end"); } } } freez(callid); return 1; }
int main (int argc, char *argv[]) { int sts; int i; int buflen; int access; char buff [BUFFER_SIZE]; sip_ticket_t ticket; extern char *optarg; /* Defined in libc getopt and unistd.h */ int ch1; char configfile[64]="siproxd"; /* basename of configfile */ int config_search=1; /* search the config file */ int cmdline_debuglevel=0; char *pidfilename=NULL; struct sigaction act; log_set_stderr(1); /* * setup signal handlers */ act.sa_handler=sighandler; sigemptyset(&act.sa_mask); act.sa_flags=SA_RESTART; if (sigaction(SIGTERM, &act, NULL)) { ERROR("Failed to install SIGTERM handler"); } if (sigaction(SIGINT, &act, NULL)) { ERROR("Failed to install SIGINT handler"); } if (sigaction(SIGUSR2, &act, NULL)) { ERROR("Failed to install SIGUSR2 handler"); } /* * prepare default configuration */ make_default_config(); log_set_pattern(configuration.debuglevel); /* * parse command line */ { #ifdef HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"config", required_argument, NULL, 'c'}, {"debug", required_argument, NULL, 'd'}, {"pid-file", required_argument, NULL,'p'}, {0,0,0,0} }; while ((ch1 = getopt_long(argc, argv, "hc:d:p:", long_options, &option_index)) != -1) { #else /* ! HAVE_GETOPT_LONG */ while ((ch1 = getopt(argc, argv, "hc:d:p:")) != -1) { #endif switch (ch1) { case 'h': /* help */ DEBUGC(DBCLASS_CONFIG,"option: help"); fprintf(stderr,str_helpmsg); exit(0); break; case 'c': /* load config file */ DEBUGC(DBCLASS_CONFIG,"option: config file=%s",optarg); i=sizeof(configfile)-1; strncpy(configfile,optarg,i-1); configfile[i]='\0'; config_search=0; break; case 'd': /* set debug level */ DEBUGC(DBCLASS_CONFIG,"option: set debug level: %s",optarg); cmdline_debuglevel=atoi(optarg); log_set_pattern(cmdline_debuglevel); break; case 'p': pidfilename = optarg; break; default: DEBUGC(DBCLASS_CONFIG,"no command line options"); break; } } } /* * Init stuff */ INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" starting up"); /* read the config file */ if (read_config(configfile, config_search) == STS_FAILURE) exit(1); /* if a debug level > 0 has been given on the commandline use its value and not what is in the config file */ if (cmdline_debuglevel != 0) { configuration.debuglevel=cmdline_debuglevel; } /* * open a the pwfile instance, so we still have access after * we possibly have chroot()ed to somewhere. */ if (configuration.proxy_auth_pwfile) { siproxd_passwordfile = fopen(configuration.proxy_auth_pwfile, "r"); } else { siproxd_passwordfile = NULL; } /* set debug level as desired */ log_set_pattern(configuration.debuglevel); log_set_listen_port(configuration.debugport); /* change user and group IDs */ secure_enviroment(); /* daemonize if requested to */ if (configuration.daemonize) { DEBUGC(DBCLASS_CONFIG,"daemonizing"); if (fork()!=0) exit(0); setsid(); if (fork()!=0) exit(0); log_set_stderr(0); INFO("daemonized, pid=%i", getpid()); } /* write PID file of main thread */ if (pidfilename == NULL) pidfilename = configuration.pid_file; if (pidfilename) { FILE *pidfile; DEBUGC(DBCLASS_CONFIG,"creating PID file [%s]", pidfilename); sts=unlink(configuration.pid_file); if ((sts==0) ||(errno == ENOENT)) { if ((pidfile=fopen(pidfilename, "w"))) { fprintf(pidfile,"%i\n",(int)getpid()); fclose(pidfile); } else { WARN("couldn't create new PID file: %s", strerror(errno)); } } else { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* initialize the RTP proxy */ sts=rtpproxy_init(); if (sts != STS_SUCCESS) { ERROR("unable to initialize RTP proxy - aborting"); exit(1); } /* init the oSIP parser */ parser_init(); /* listen for incoming messages */ sts=sipsock_listen(); if (sts == STS_FAILURE) { /* failure to allocate SIP socket... */ ERROR("unable to bind to SIP listening socket - aborting"); exit(1); } /* initialize the registration facility */ register_init(); /* * silence the log - if so required... */ log_set_silence(configuration.silence_log); INFO(PACKAGE"-"VERSION"-"BUILDSTR" "UNAME" started"); /***************************** * Main loop *****************************/ while (!exit_program) { DEBUGC(DBCLASS_BABBLE,"going into sipsock_wait\n"); while (sipsock_wait()<=0) { /* got no input, here by timeout. do aging */ register_agemap(); /* TCP log: check for a connection */ log_tcp_connect(); /* dump memory stats if requested to do so */ if (dmalloc_dump) { dmalloc_dump=0; #ifdef DMALLOC INFO("SIGUSR2 - DMALLOC statistics is dumped"); dmalloc_log_stats(); dmalloc_log_unfreed(); #else INFO("SIGUSR2 - DMALLOC support is not compiled in"); #endif } if (exit_program) goto exit_prg; } /* * got input, process */ DEBUGC(DBCLASS_BABBLE,"back from sipsock_wait"); ticket.direction=0; buflen=sipsock_read(&buff, sizeof(buff)-1, &ticket.from, &ticket.protocol); buff[buflen]='\0'; /* * evaluate the access lists (IP based filter) */ access=accesslist_check(ticket.from); if (access == 0) { DEBUGC(DBCLASS_ACCESS,"access for this packet was denied"); continue; /* there are no resources to free */ } /* * integrity checks */ sts=security_check_raw(buff, buflen); if (sts != STS_SUCCESS) { DEBUGC(DBCLASS_SIP,"security check (raw) failed"); continue; /* there are no resources to free */ } /* * init sip_msg */ sts=osip_message_init(&ticket.sipmsg); ticket.sipmsg->message=NULL; if (sts != 0) { ERROR("osip_message_init() failed... this is not good"); continue; /* skip, there are no resources to free */ } /* * RFC 3261, Section 16.3 step 1 * Proxy Behavior - Request Validation - Reasonable Syntax * (parse the received message) */ sts=sip_message_parse(ticket.sipmsg, buff, buflen); if (sts != 0) { ERROR("sip_message_parse() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * integrity checks - parsed buffer */ sts=security_check_sip(&ticket); if (sts != STS_SUCCESS) { ERROR("security_check_sip() failed... this is not good"); DUMP_BUFFER(-1, buff, buflen); goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 2 * Proxy Behavior - Request Validation - URI scheme * (check request URI and refuse with 416 if not understood) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.3 step 3 * Proxy Behavior - Request Validation - Max-Forwards check * (check Max-Forwards header and refuse with 483 if too many hops) */ { osip_header_t *max_forwards; int forwards_count = DEFAULT_MAXFWD; osip_message_get_max_forwards(ticket.sipmsg, 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(&ticket, 483 /*Too many hops*/); goto end_loop; /* skip and free resources */ } } /* * RFC 3261, Section 16.3 step 4 * Proxy Behavior - Request Validation - Loop Detection check * (check for loop and return 482 if a loop is detected) */ if (check_vialoop(&ticket) == STS_TRUE) { /* make sure we don't end up in endless loop when detecting * an loop in an "loop detected" message - brrr */ if (MSG_IS_RESPONSE(ticket.sipmsg) && MSG_TEST_CODE(ticket.sipmsg, 482)) { DEBUGC(DBCLASS_SIP,"loop in loop-response detected, ignoring"); } else { DEBUGC(DBCLASS_SIP,"via loop detected, ignoring request"); sip_gen_response(&ticket, 482 /*Loop detected*/); } goto end_loop; /* skip and free resources */ } /* * RFC 3261, Section 16.3 step 5 * Proxy Behavior - Request Validation - Proxy-Require check * (check Proxy-Require header and return 420 if unsupported option) */ /* NOT IMPLEMENTED */ /* * RFC 3261, Section 16.5 * Proxy Behavior - Determining Request Targets */ /* NOT IMPLEMENTED */ DEBUGC(DBCLASS_SIP,"received SIP type %s:%s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", (MSG_IS_REQUEST(ticket.sipmsg) ? ((ticket.sipmsg->sip_method)? ticket.sipmsg->sip_method : "NULL") : ((ticket.sipmsg->reason_phrase) ? ticket.sipmsg->reason_phrase : "NULL"))); /********************************* * The message did pass all the * tests above and is now ready * to be proxied. * Before we do so, we apply some * additional preprocessing *********************************/ /* Dial shortcuts */ if (configuration.pi_shortdial) { sts = plugin_shortdial(&ticket); if (sts == STS_SIP_SENT) goto end_loop; } /********************************* * finally proxy the message. * This includes the masquerading * of the local UA and starting/ * stopping the RTP proxy for this * call *********************************/ /* * if a REQ 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(ticket.sipmsg) && MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_REG) { osip_uri_t *url; struct in_addr addr1, addr2, addr3; int dest_port; url = osip_message_get_uri(ticket.sipmsg); dest_port= (url->port)?atoi(url->port):SIP_PORT; if ( (get_ip_by_host(url->host, &addr1) == STS_SUCCESS) && (get_interface_ip(IF_INBOUND,&addr2) == STS_SUCCESS) && (get_interface_ip(IF_OUTBOUND,&addr3) == STS_SUCCESS)) { if ((configuration.sip_listen_port == dest_port) && ((memcmp(&addr1, &addr2, sizeof(addr1)) == 0) || (memcmp(&addr1, &addr3, sizeof(addr1)) == 0))) { /* I'm the registrar, send response myself */ sts = register_client(&ticket, 0); sts = register_response(&ticket, sts); } else { /* I'm just the outbound proxy */ DEBUGC(DBCLASS_SIP,"proxying REGISTER request to:%s", url->host); sts = register_client(&ticket, 1); if (sts == STS_SUCCESS) { sts = proxy_request(&ticket); } } } else { sip_gen_response(&ticket, 408 /*request timeout*/); } } else { WARN("non-authorized registration attempt from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * check if outbound interface is UP. * If not, send back error to UA and * skip any proxying attempt */ } else if (get_interface_ip(IF_OUTBOUND,NULL) != STS_SUCCESS) { DEBUGC(DBCLASS_SIP, "got a %s to proxy, but outbound interface " "is down", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES"); if (MSG_IS_REQUEST(ticket.sipmsg)) sip_gen_response(&ticket, 408 /*request timeout*/); /* * MSG is a request, add current via entry, * do a lookup in the URLMAP table and * send to the final destination */ } else if (MSG_IS_REQUEST(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_request(&ticket); } else { INFO("non-authorized request received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * MSG is a response, remove current via and * send to the next VIA in chain */ } else if (MSG_IS_RESPONSE(ticket.sipmsg)) { if (access & ACCESSCTL_SIP) { sts = proxy_response(&ticket); } else { INFO("non-authorized response received from %s", utils_inet_ntoa(ticket.from.sin_addr)); } /* * unsupported message */ } else { ERROR("received unsupported SIP type %s %s", (MSG_IS_REQUEST(ticket.sipmsg))? "REQ" : "RES", ticket.sipmsg->sip_method); } /********************************* * Done with proxying. Message * has been sent to its destination. *********************************/ /* * free the SIP message buffers */ end_loop: osip_message_free(ticket.sipmsg); } /* while TRUE */ exit_prg: /* save current known SIP registrations */ register_save(); INFO("properly terminating siproxd"); /* remove PID file */ if (pidfilename) { DEBUGC(DBCLASS_CONFIG,"deleting PID file [%s]", pidfilename); sts=unlink(pidfilename); if (sts != 0) { WARN("couldn't delete old PID file: %s", strerror(errno)); } } /* END */ return 0; } /* main */ /* * Signal handler * * this one is called asynchronously whevener a registered * signal is applied. Just set a flag and don't do any funny * things here. */ static void sighandler(int sig) { if (sig==SIGTERM) exit_program=1; if (sig==SIGINT) exit_program=1; if (sig==SIGUSR2) dmalloc_dump=1; return; }
/* * SIP_IS_OUTGOING * * Figures out if this is an outgoing or incoming request/response. * The direction is stored in the ticket->direction property. * * RETURNS * STS_SUCCESS on success * STS_FAILURE if unable to determine */ int sip_find_direction(sip_ticket_t *ticket, int *urlidx) { int type; int i, sts; struct sockaddr_in *from; osip_message_t *request; osip_message_t *response; from=&ticket->from; request=ticket->sipmsg; response=ticket->sipmsg; type = 0; ticket->direction = 0; /* * did I receive the telegram from a REGISTERED host? * -> it must be an OUTGOING request */ for (i=0; i<URLMAP_SIZE; i++) { struct in_addr tmp_addr; if (urlmap[i].active == 0) continue; if (get_ip_by_host(urlmap[i].true_url->host, &tmp_addr) == STS_FAILURE) { DEBUGC(DBCLASS_SIP, "sip_find_direction: cannot resolve host [%s]", urlmap[i].true_url->host); } else { DEBUGC(DBCLASS_SIP, "sip_find_direction: reghost:%s ip:%s", urlmap[i].true_url->host, utils_inet_ntoa(from->sin_addr)); if (memcmp(&tmp_addr, &from->sin_addr, sizeof(tmp_addr)) == 0) { if (MSG_IS_REQUEST(ticket->sipmsg)) { type=REQTYP_OUTGOING; } else { type=RESTYP_OUTGOING; } break; } } } /* * is the telegram directed to an internally registered host? * -> it must be an INCOMING request */ if (type == 0) { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* RFC3261: * 'To' contains a display name (Bob) and a SIP or SIPS URI * (sip:[email protected]) towards which the request was originally * directed. Display names are described in RFC 2822 [3]. */ /* So this means, that we must check the SIP URI supplied with the * INVITE method, as this points to the real wanted target. * Q: does there exist a situation where the SIP URI itself does * point to "somewhere" but the To: points to the correct UA? * So for now, we just look at both of them (SIP URI and To: header) */ if (MSG_IS_REQUEST(ticket->sipmsg)) { /* REQUEST */ /* incoming request (SIP URI == 'masq') || ((SIP URI == 'reg') && !REGISTER)*/ if ((compare_url(request->req_uri, urlmap[i].masq_url)==STS_SUCCESS) || (!MSG_IS_REGISTER(request) && (compare_url(request->req_uri, urlmap[i].reg_url)==STS_SUCCESS))) { type=REQTYP_INCOMING; break; } /* 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; break; } } else { /* RESPONSE */ /* 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; break; } } /* is request */ } /* for i */ } /* if type == 0 */ if (MSG_IS_RESPONSE(ticket->sipmsg)) { /* &&&& Open Issue &&&& it has been seen with cross-provider calls that the FROM may be 'garbled' (e.g [email protected] for calls made sipphone -> FWD) How can we deal with this? Should I take into consideration the 'Via' headers? This is the only clue I have, pointing to the *real* UA. Maybe I should put in a 'siproxd' ftag value to recognize it as a header inserted by myself */ if ((type == 0) && (!osip_list_eol(response->vias, 0))) { osip_via_t *via; struct in_addr addr_via, addr_myself; int port_via, port_ua; /* get the via address */ via = (osip_via_t *) osip_list_get (response->vias, 0); DEBUGC(DBCLASS_SIP, "sip_find_direction: check via [%s] for " "registered UA",via->host); sts=get_ip_by_host(via->host, &addr_via); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_SIP, "sip_find_direction: cannot resolve VIA [%s]", via->host); } else { for (i=0; i<URLMAP_SIZE; i++) { if (urlmap[i].active == 0) continue; /* incoming response (1st via in list points to a registered UA) */ sts=get_ip_by_host(urlmap[i].true_url->host, &addr_myself); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_SIP, "sip_find_direction: cannot resolve " "true_url [%s]", via->host); continue; } port_via=0; if (via->port) port_via=atoi(via->port); if (port_via <= 0) port_via=SIP_PORT; port_ua=0; if (urlmap[i].true_url->port) port_ua=atoi(urlmap[i].true_url->port); if (port_ua <= 0) port_ua=SIP_PORT; DEBUGC(DBCLASS_SIP, "sip_find_direction: checking for registered " "host [%s:%i] <-> [%s:%i]", urlmap[i].true_url->host, port_ua, via->host, port_via); if ((memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) && (port_via == port_ua)) { type=RESTYP_INCOMING; break; } } /* for i */ } } /* if type == 0 */ } /* is response */ if (type == 0) { DEBUGC(DBCLASS_SIP, "sip_find_direction: unable to determine " "direction of SIP packet"); return STS_FAILURE; } ticket->direction=type; if (urlidx) *urlidx=i; return STS_SUCCESS; }