/* Get SIP message of the call leg */ osip_message_t *eXosipua_extract_message(eXosipua_t *jua, eXosip_event_t *je) { osip_message_t *message; if(osip_message_init(&message) != 0) { jua_debug(("eXosipua_extract_message: init sip body error\n")); return NULL; } if(osip_message_parse(message, je->sdp_body, strlen(je->sdp_body)) != 0) { osip_message_free(message); return NULL; } return message; }
static struct session *sip_callback(struct session *sip, u_char *data, uint32_t len) { osip_message_t *msg; struct tuple4 addr; struct session *start; struct session *rtp; osip_call_id_t *call_id; osip_message_init(&msg); if (!osip_message_parse(msg, (char *)data, len)) { if (NULL == sip->u.sip_params.call_id) { /* * If the session object was created by udp_callback * we need to fill in the call_id field here because * udp_callback doesn't know anything about SIP */ if (NULL != (call_id = osip_message_get_call_id(msg))) osip_call_id_clone(call_id, &sip->u.sip_params.call_id); } else { /* * Otherwise check if the session object passed to this * function call was really the one corresponding to the * call ID in the SIP packet, in case several SIP calls * are passed upon the same transport layer protocol, * source and destination IPv4 address & port combination. * udp_callback has no way of knowing how to distinguish * SIP session objects based on call ID, so we have to do * it here. We just continue searching in the list of all * tracked sessions for similar SIP objects until we find * one that has the same call ID, or else we create a new * SIP session object that corresponds to the new call. */ start = sip; do { if (NULL == (call_id = osip_message_get_call_id(msg))) continue; if (!osip_call_id_match(sip->u.sip_params.call_id, call_id)) break; } while ((sip = sessions_find(sip->next, TYPE_SIP, 0, &sip->addr))); if (NULL == sip) { if (bonus_time) { osip_message_free(msg); return start; } sip = sessions_add(start->type, &start->addr, NULL); if (NULL != (call_id = osip_message_get_call_id(msg))) osip_call_id_clone(call_id, &sip->u.sip_params.call_id); } } /* * If the current SIP packet is an INVITE message, store the * advertised source port and IPv4 address. It is not very * important, since we can do only with the destination part * (useful in case the capture missed the INVITE packet), but * it helps discriminating from unrelated packets. * * Unfortunately, some SIP implementations such as the one in * Audiocodes Mediant 1000 SIP gateways actually use a source * port different from the one they advertised in the INVITE * message parameters - how outrageous! - so we have to make * our sessions search engine ignore the source port part by * zeroing it :-/ */ if (MSG_IS_INVITE(msg)) { if (!bonus_time) { sip_get_address(msg, &sip->u.sip_params.rtp_addr.saddr, &sip->u.sip_params.rtp_addr.source); #ifndef USING_NON_STUPID_SIP_IMPLEMENTATIONS sip->u.sip_params.rtp_addr.source = 0; #endif } } else if (MSG_TEST_CODE(msg, 200)) { if (MSG_IS_RESPONSE_FOR(msg, "INVITE")) { if (!bonus_time && sip_get_address(msg, &sip->u.sip_params.rtp_addr.daddr, &sip->u.sip_params.rtp_addr.dest)) { sessions_add(TYPE_UDP | TYPE_RTP, &sip->u.sip_params.rtp_addr, sip); sip->u.sip_params.picked_up = 1; } } else if (MSG_IS_RESPONSE_FOR(msg, "BYE") || MSG_IS_RESPONSE_FOR(msg, "CANCEL")) { start = first_session; while (NULL != (rtp = sessions_find(start, TYPE_RTP, sip->id, NULL))) { sessions_del(rtp); start = rtp->next; } /* * Mark for deletion in 2 seconds, in order to give some * time to the extra ACK packets that might be exchanged */ if (sip->type & TYPE_UDP) sip->timeout = nids_last_pcap_header->ts.tv_sec + 2; } } } osip_message_free(msg); return sip; }
int main (int argc, char *argv[]) #endif { int sts; int i; 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); /* * 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; } /* * 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; } /* 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"); i=sipsock_read(&buff, sizeof(buff)-1, &ticket.from, &ticket.protocol); buff[i]='\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, i); 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=osip_message_parse(ticket.sipmsg, buff); if (sts != 0) { ERROR("osip_message_parse() failed... this is not good"); DUMP_BUFFER(-1, buff, i); 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, i); 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"))); /* * if an 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_ip_by_ifname(configuration.inbound_if,&addr2) == STS_SUCCESS) && (get_ip_by_ifname(configuration.outbound_if,&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); sts = proxy_request(&ticket); } } else { if (MSG_IS_REQUEST(ticket.sipmsg)) { 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_ip_by_ifname(configuration.outbound_if,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); } /* * free the SIP message buffers */ end_loop: osip_message_free(ticket.sipmsg); } /* while TRUE */ exit_prg: /* dump current known SIP registrations */ register_shut(); 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; }
int test_message (char *msg, size_t len, int verbose, int clone) { osip_message_t *sip; { char *result; /* int j=10000; */ int j = 1; if (verbose) fprintf (stdout, "Trying %i sequentials calls to osip_message_init(), osip_message_parse() and osip_message_free()\n", j); while (j != 0) { j--; osip_message_init (&sip); if (osip_message_parse (sip, msg, len) != 0) { fprintf (stdout, "ERROR: failed while parsing!\n"); osip_message_free (sip); return -1; } osip_message_free (sip); } osip_message_init (&sip); if (osip_message_parse (sip, msg, len) != 0) { fprintf (stdout, "ERROR: failed while parsing!\n"); osip_message_free (sip); return -1; } else { int i; size_t length; #if 0 sdp_message_t *sdp; osip_body_t *oldbody; int pos; pos = 0; while (!osip_list_eol (&sip->bodies, pos)) { oldbody = (osip_body_t *) osip_list_get (&sip->bodies, pos); pos++; sdp_message_init (&sdp); i = sdp_message_parse (sdp, oldbody->body); if (i != 0) { fprintf (stdout, "ERROR: Bad SDP!\n"); } else fprintf (stdout, "SUCCESS: Correct SDP!\n"); sdp_message_free (sdp); sdp = NULL; } #endif osip_message_force_update (sip); i = osip_message_to_str (sip, &result, &length); if (i == -1) { fprintf (stdout, "ERROR: failed while printing message!\n"); osip_message_free (sip); return -1; } else { if (verbose) fwrite (result, 1, length, stdout); if (clone) { /* create a clone of message */ /* int j = 10000; */ int j = 1; if (verbose) fprintf (stdout, "Trying %i sequentials calls to osip_message_clone() and osip_message_free()\n", j); while (j != 0) { osip_message_t *copy; j--; i = osip_message_clone (sip, ©); if (i != 0) { fprintf (stdout, "ERROR: failed while creating copy of message!\n"); } else { char *tmp; size_t length; osip_message_force_update (copy); i = osip_message_to_str (copy, &tmp, &length); if (i != 0) { fprintf (stdout, "ERROR: failed while printing message!\n"); } else { if (0 == strcmp (result, tmp)) { if (verbose) printf ("The osip_message_clone method works perfectly\n"); } else printf ("ERROR: The osip_message_clone method DOES NOT works\n"); if (verbose) { printf ("Here is the copy: \n"); fwrite (tmp, 1, length, stdout); printf ("\n"); } osip_free (tmp); } osip_message_free (copy); } } if (verbose) fprintf (stdout, "sequentials calls: done\n"); } osip_free (result); } osip_message_free (sip); } } return 0; }
/* return NULL if message cannot be parsed */ osip_event_t * osip_parse (char *buf) { osip_event_t *se = __osip_event_new (UNKNOWN_EVT, 0); int i; #ifdef TEST_PARSER_SPEED { int kk; int pstime1, pstime; struct timespec tv1; clock_get_time (CLOCK_REALTIME, &tv1); pstime = ((tv1.tv_sec * 1000) + (tv1.tv_nsec / 1000000)); for (kk = 0; kk < 10000; kk++) { i = osip_message_init (&(se->sip)); if (osip_message_parse (se->sip, buf) == -1) { fprintf (stdout, "osip_message_parse retrun -1\n"); osip_message_free (se->sip); } else { /* msg is parsed */ osip_message_free (se->sip); } } clock_get_time (CLOCK_REALTIME, &tv1); pstime1 = ((tv1.tv_sec * 1000) + (tv1.tv_nsec / 1000000)); fprintf (stdout, "CPU clock ticks for 10000 messages - T1: %i - T2: %i\n", pstime1, pstime); fprintf (stdout, "CPU time for 10000 messages - %d\n", (pstime1 - pstime)); } osip_free (se); return NULL; #endif /* parse message and set up an event */ i = osip_message_init (&(se->sip)); if (osip_message_parse (se->sip, buf) == -1) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "could not parse message\n")); osip_message_free (se->sip); osip_free (se); return NULL; } else { if (se->sip->call_id!=NULL && se->sip->call_id->number!=NULL) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO3, NULL, "MESSAGE REC. CALLID:%s\n", se->sip->call_id->number)); } if (MSG_IS_REQUEST(se->sip)) { if (se->sip->sip_method==NULL || se->sip->req_uri==NULL) { osip_message_free (se->sip); osip_free (se); return NULL; } } se->type = evt_set_type_incoming_sipmessage (se->sip); return se; } }