Example #1
0
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);
		}
	}
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
/* 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;
}
Example #9
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;
}
Example #10
0
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;
}
Example #11
0
/*
 * 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;
}