Exemplo n.º 1
0
/*
 * cyclically called to do the aging of the URL mapping table entries
 * and throw out expired entries.
 * Also we do the cyclic saving here - if required.
 */
void register_agemap(void) {
   int i;
   time_t t;
   
   /* expire old entries */
   time(&t);
   DEBUGC(DBCLASS_BABBLE,"sip_agemap, t=%i",(int)t);
   for (i=0; i<URLMAP_SIZE; i++) {
      if ((urlmap[i].active == 1) && (urlmap[i].expires < t)) {
         DEBUGC(DBCLASS_REG,"cleaned entry:%i %s@%s", i,
                urlmap[i].masq_url->username,  urlmap[i].masq_url->host);
         urlmap[i].active=0;
         osip_uri_free(urlmap[i].true_url);
         osip_uri_free(urlmap[i].masq_url);
         osip_uri_free(urlmap[i].reg_url);
      }
   }

   /* auto-save of registration table */
   if ((configuration.autosave_registrations > 0) &&
       ((last_save + configuration.autosave_registrations) < t)) {
      register_save();
      last_save = t;
   }
   return;
}
Exemplo n.º 2
0
/*
 * Processing.
 * 
 */
int  PLUGIN_PROCESS(int stage, sip_ticket_t *ticket){
   /* stage contains the PLUGIN_* value - the stage of SIP processing. */
   int type;
   osip_via_t *via;
   struct sockaddr_in from;

   type = ticket->direction;

   /* Incoming SIP message? */
DEBUGC(DBCLASS_PLUGIN, "plugin_fix_bogus_via: type=%i", type);
   if (type == REQTYP_INCOMING) {

      if((via = osip_list_get(&(ticket->sipmsg->vias), 0)) == NULL) {
         WARN("no Via header found in incoming SIP message");
         return STS_SUCCESS;
      }

      get_ip_by_host(via->host, &(from.sin_addr));

      /* check for Via IP in configured range */
      if ((plugin_cfg.networks != NULL) &&
          (strcmp(plugin_cfg.networks, "") !=0) &&
          (process_aclist(plugin_cfg.networks, from) == STS_SUCCESS)) {
         /* is in list, patch Via header with received from IP */
         DEBUGC(DBCLASS_PLUGIN, "plugin_fix_bogus_via: replacing a bogus via");
         if (sip_patch_topvia(ticket) == STS_FAILURE) {
            ERROR("patching inbound Via failed!");
         }
      }
   }
   return STS_SUCCESS;
}
Exemplo n.º 3
0
/*
 * check if a given request (outbound -> inbound) shall its
 * request URI get rewritten based upon our UA knowledge
 *
 * RETURNS
 *	STS_TRUE if to be rewritten
 *	STS_FALSE otherwise
 */
int check_rewrite_rq_uri (osip_message_t *sip) {
   int i, j, sts;
   int dflidx;
   osip_header_t *ua_hdr;

   /* get index of default entry */
   dflidx=(sizeof(RQ_rewrite)/sizeof(RQ_rewrite[0])) - 1;

   /* check fort existence of method */
   if ((sip==NULL) ||
       (sip->sip_method==NULL)) {
      ERROR("check_rewrite_rq_uri: got NULL method");
      return STS_FALSE;
   }

   /* extract UA string */
   osip_message_get_user_agent (sip, 0, &ua_hdr);
   if ((ua_hdr==NULL) || (ua_hdr->hvalue==NULL)) {
      DEBUGC(DBCLASS_SIP, "check_rewrite_rq_uri: NULL UA in Header, "
             "using default");
      i=dflidx;
   } else {
      /* loop through the knowledge base */
      for (i=0; RQ_rewrite[i].UAstring; i++) {
         if (strncmp(RQ_rewrite[i].UAstring, ua_hdr->hvalue,
                    sizeof(RQ_rewrite[i].UAstring))==0) {
            DEBUGC(DBCLASS_SIP, "got knowledge entry for [%s]",
                   ua_hdr->hvalue);
            break;
         }
      } /* for i */
   } /* if ua_hdr */

   for (j=0; RQ_method[j].name; j++) 
   {
      if (strncmp(RQ_method[j].name,
                 sip->sip_method, RQ_method[j].size)==0) 
      {
         if (RQ_rewrite[i].action[j] >= 0) 
         {
            sts = (RQ_rewrite[i].action[j])? STS_TRUE: STS_FALSE;
         } 
         else
         {
	    sts = (RQ_rewrite[dflidx].action[j])? STS_TRUE: STS_FALSE;
         }
         DEBUGC(DBCLASS_SIP, "check_rewrite_rq_uri: [%s:%s, i=%i, j=%i] "
                "got action %s",
                (sip && sip->sip_method) ?
                  sip->sip_method : "*NULL*",
                (ua_hdr && ua_hdr->hvalue)? ua_hdr->hvalue:"*NULL*",
                 i, j, (sts==STS_TRUE)? "rewrite":"norewrite");
         return sts;
      }
   } /* for j */

   WARN("check_rewrite_rq_uri: didn't get a hit of the method [%s]",
        sip->sip_method);
   return STS_FALSE;
}
Exemplo n.º 4
0
/*
 * SIP_GEN_RESPONSE
 *
 * send an proxy generated response back to the client.
 * Only errors are reported from the proxy itself.
 *  code =  SIP result code to deliver
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 */
int sip_gen_response(sip_ticket_t *ticket, int code) {
   osip_message_t *response;
   int sts;
   osip_via_t *via;
   int port;
   char *buffer;
   size_t buflen;
   struct in_addr addr;

   /* create the response template */
   if ((response=msg_make_template_reply(ticket, code))==NULL) {
      ERROR("sip_gen_response: error in msg_make_template_reply");
      return STS_FAILURE;
   }

   /* we must check if first via has x.x.x.x address. If not, we must resolve it */
   osip_message_get_via (response, 0, &via);
   if (via == NULL)
   {
      ERROR("sip_gen_response: Cannot send response - no via field");
      return STS_FAILURE;
   }


   /* name resolution */
   if (utils_inet_aton(via->host, &addr) == 0)
   {
      /* need name resolution */
      DEBUGC(DBCLASS_DNS,"resolving name:%s",via->host);
      sts = get_ip_by_host(via->host, &addr);
      if (sts == STS_FAILURE) {
         DEBUGC(DBCLASS_PROXY, "sip_gen_response: cannot resolve via [%s]",
                via->host);
         return STS_FAILURE;
      }
   }   

   sts = sip_message_to_str(response, &buffer, &buflen);
   if (sts != 0) {
      ERROR("sip_gen_response: msg_2char failed");
      return STS_FAILURE;
   }


   if (via->port) {
      port=atoi(via->port);
   } else {
      port=SIP_PORT;
   }

   /* send to destination */
   sipsock_send(addr, port, ticket->protocol, buffer, buflen);

   /* free the resources */
   osip_message_free(response);
   osip_free(buffer);
   return STS_SUCCESS;
}
Exemplo n.º 5
0
/*
 * check if a given request is addressed to local. I.e. it is addressed
 * to the proxy 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 (sip_ticket_t *ticket) {
   osip_message_t *sip=ticket->sipmsg;
   int found;
   struct in_addr addr_uri, addr_myself;
   int port;
   int i;

   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<2; i++) {
      /*
       * search my in/outbound interfaces
       */
      DEBUGC(DBCLASS_BABBLE,"resolving IP of interface %s",
             (i==IF_INBOUND)? "inbound":"outbound");
      if (get_interface_ip(i, &addr_myself) != STS_SUCCESS) {
         continue;
      }

      /* check the extracted HOST against my own host addresses */
      if (sip->req_uri->port) {
         port=atoi(sip->req_uri->port);
      } else {
         port=SIP_PORT;
      }

      if ( (memcmp(&addr_myself, &addr_uri, sizeof(addr_myself))==0) &&
           (port == configuration.sip_listen_port) ) {
         DEBUG("address match [%s]", utils_inet_ntoa(addr_uri));
         found=1;
	 break;
      }
   }

   DEBUGC(DBCLASS_DNS, "SIP URI is %slocal", found? "":"not ");
   return (found)? STS_TRUE : STS_FALSE;
}
Exemplo n.º 6
0
/*
 * 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;
}
Exemplo n.º 7
0
/*
 * SIP_ADD_MYVIA
 *
 * interface == IF_OUTBOUND, IF_INBOUND
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 */
int sip_add_myvia (sip_ticket_t *ticket, int interface) {
   struct in_addr addr;
   char tmp[URL_STRING_SIZE];
   osip_via_t *via;
   int sts;
   char branch_id[VIA_BRANCH_SIZE];
   char *myaddr;

   if (get_interface_ip(interface, &addr) != STS_SUCCESS) {
      return STS_FAILURE;
   }

   sts = sip_calculate_branch_id(ticket, branch_id);

   myaddr=utils_inet_ntoa(addr);
   sprintf(tmp, "SIP/2.0/UDP %s:%i;branch=%s",
           myaddr, configuration.sip_listen_port,
           branch_id);

   DEBUGC(DBCLASS_BABBLE,"adding VIA:%s",tmp);

   sts = osip_via_init(&via);
   if (sts!=0) return STS_FAILURE; /* allocation failed */

   sts = osip_via_parse(via, tmp);
   if (sts!=0) return STS_FAILURE;

   osip_list_add(ticket->sipmsg->vias,via,0);

   return STS_SUCCESS;
}
Exemplo n.º 8
0
/*--------------------------------------------------------------------*/
static int sip_patch_topvia(sip_ticket_t *ticket) {
   osip_via_t *via;

   if((via = osip_list_get(&(ticket->sipmsg->vias), 0)) != NULL) {
      /* clone Via header */

      /* set new IP (from IP) */
      osip_free(via->host);
      via->host=osip_malloc(IPSTRING_SIZE);
      snprintf(via->host, IPSTRING_SIZE, "%s",
               utils_inet_ntoa(ticket->from.sin_addr));
      via->host[IPSTRING_SIZE-1] ='\0';

      /* set new port number */
      osip_free(via->port);
      via->port=osip_malloc(6); /* 5 digits + \0 */
      snprintf(via->port, 5, "%u", ntohs(ticket->from.sin_port));
      via->port[5-1] ='\0';

      DEBUGC(DBCLASS_PLUGIN, "plugin_fix_bogus_via:  -> %s:%s",
             via->host, via->port);

   }

   return STS_SUCCESS;
}
Exemplo n.º 9
0
/*
 * kills the rtp_proxy thread
 *
 * RETURNS
 *	-
 */
void rtpproxy_kill( void ) {
   void *thread_status;
   osip_call_id_t cid;
   int i, sts;

   /* stop any active RTP stream */
   for (i=0;i<RTPPROXY_SIZE;i++) {
      if (rtp_proxytable[i].rtp_rx_sock != 0) {
         cid.number = rtp_proxytable[i].callid_number;
         cid.host   = rtp_proxytable[i].callid_host;
         sts = rtp_relay_stop_fwd(&cid, rtp_proxytable[i].direction, 0);
      }
   }
   

   /* kill the thread */
   if (rtpproxy_tid) {
      pthread_cancel(rtpproxy_tid);
      pthread_kill(rtpproxy_tid, SIGALRM);
      pthread_join(rtpproxy_tid, &thread_status);
   }

   DEBUGC(DBCLASS_RTP,"killed RTP proxy thread");
   return;
}
Exemplo n.º 10
0
/*
 * 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;
   int port;
   int i;

   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<2; i++) {
      /*
       * search my in/outbound interfaces
       */
      DEBUGC(DBCLASS_BABBLE,"resolving IP of interface %s",
             (i==IF_INBOUND)? "inbound":"outbound");
      if (get_interface_ip(i, &addr_myself) != STS_SUCCESS) {
         continue;
      }

      /* 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;
}
Exemplo n.º 11
0
/*
 * sends an UDP datagram to the specified destination
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 */
int sipsock_send(struct in_addr addr, int port, int protocol,
                 char *buffer, int size) {
   struct sockaddr_in dst_addr;
   int sts;

   /* first time: allocate a socket for sending */
   if (sip_udp_socket == 0) {
      ERROR("SIP socket not allocated");
      return STS_FAILURE;
   }

   if (buffer == NULL) {
      ERROR("sipsock_send got NULL buffer");
      return STS_FAILURE;
   }

   if (protocol != PROTO_UDP) {
      ERROR("sipsock_send: only UDP supported by now");
      return STS_FAILURE;
   }

   dst_addr.sin_family = AF_INET;
   memcpy(&dst_addr.sin_addr.s_addr, &addr, sizeof(struct in_addr));
   dst_addr.sin_port= htons(port);

   DEBUGC(DBCLASS_NET,"send UDP packet to %s: %i", utils_inet_ntoa(addr),port);
   DUMP_BUFFER(DBCLASS_NETTRAF, buffer, size);

   sts = sendto(sip_udp_socket, buffer, size, 0,
                (const struct sockaddr *)&dst_addr,
                (socklen_t)sizeof(dst_addr));
   
   if (sts == -1) {
      if (errno != ECONNREFUSED) {
         ERROR("sendto() [%s:%i size=%i] call failed: %s",
               utils_inet_ntoa(addr),
               port, size, strerror(errno));
         return STS_FAILURE;
      }
      DEBUGC(DBCLASS_BABBLE,"sendto() [%s:%i] call failed: %s",
             utils_inet_ntoa(addr), port, strerror(errno));
   }

   return STS_SUCCESS;
}
Exemplo n.º 12
0
/*
 * Secure enviroment:
 * If running as root, put myself into a chroot jail and
 * change UID/GID to user as requested in config file
 */
void secure_enviroment (void) {
   int sts;
   struct passwd *passwd=NULL;

   DEBUGC(DBCLASS_CONFIG,"running w/uid=%i, euid=%i, gid=%i, egid=%i",
          (int)getuid(), (int)geteuid(), (int)getgid(), (int)getegid());

   if ((getuid()==0) || (geteuid()==0)) {
      /*
       * preparation - after chrooting there will be NOTHING more around
       */
      if (configuration.user) passwd=getpwnam(configuration.user);

      /*
       * change root directory into chroot jail
       */
      if (configuration.chrootjail) {
         /* !!!
          * Before chrooting I must at least once trigger the resolver
          * as it loads some dynamic libraries. Once chrootet
          * these libraries will *not* be found and gethostbyname()
          * calls will simply fail (return NULL pointer and h_errno=0).
          * Also (at least for FreeBSD) syslog() needs to be called
          * before chroot()ing - this is done in main() by an INFO().
          * Took me a while to figure THIS one out
          */
         struct in_addr dummy;
         get_ip_by_host("localhost", &dummy);
         DEBUGC(DBCLASS_CONFIG,"chrooting to %s",
                configuration.chrootjail);
         sts = chroot(configuration.chrootjail);
	 if (sts != 0) DEBUGC(DBCLASS_CONFIG,"chroot(%s) failed: %s",
	                      configuration.chrootjail, strerror(errno));
         sts=chdir("/");
      }

      /*
       * change user ID and group ID 
       */
      if (passwd) {
         DEBUGC(DBCLASS_CONFIG,"changing uid/gid to %s",
                configuration.user);
         sts = setgid(passwd->pw_gid);
         DEBUGC(DBCLASS_CONFIG,"changed gid to %i - %s",
	        (int)passwd->pw_gid, (sts==0)?"Ok":"Failed");

         sts = setegid(passwd->pw_gid);
         DEBUGC(DBCLASS_CONFIG,"changed egid to %i - %s",
	        (int)passwd->pw_gid, (sts==0)?"Ok":"Failed");

         sts = seteuid(passwd->pw_uid);
         DEBUGC(DBCLASS_CONFIG,"changed euid to %i - %s",
	        (int)passwd->pw_uid, (sts==0)?"Ok":"Failed");
      }
   }
}
Exemplo n.º 13
0
/*
 * verifies the from address agains the access lists
 * defined in the configuration file.
 *
 * returns a bitmask with ACCESSCTL_SIP, ACCESSCTL_REG
 */
int accesslist_check (struct sockaddr_in from) {
   int access = 0;

   DEBUGC(DBCLASS_ACCESS,"deny  list (SIP):%s",
      configuration.hosts_deny_sip? configuration.hosts_deny_sip : "*NULL*");
   DEBUGC(DBCLASS_ACCESS,"allow list (SIP):%s",
      configuration.hosts_allow_sip? configuration.hosts_allow_sip : "*NULL*");
   DEBUGC(DBCLASS_ACCESS,"allow list (REG):%s",
      configuration.hosts_allow_reg? configuration.hosts_allow_reg : "*NULL*");

/*
 * check DENY list
 */
   if ( (configuration.hosts_deny_sip !=NULL) &&
        (strcmp(configuration.hosts_deny_sip,"")!=0) ) {
      /* non-empty list -> check agains it */
      if (process_aclist(configuration.hosts_deny_sip, from)== STS_SUCCESS) {
         /* yup - this one is blacklisted */
         DEBUGC(DBCLASS_ACCESS,"caught by deny list");
         return 0;
      }
   }

/*
 * check SIP allow list
 */
   if ( (configuration.hosts_allow_sip !=NULL) &&
        (strcmp(configuration.hosts_allow_sip,"")!=0) ) {
      /* non-empty list -> check agains it */
      if (process_aclist(configuration.hosts_allow_sip, from)==STS_SUCCESS) {
         /* SIP access granted */
         DEBUGC(DBCLASS_ACCESS,"granted SIP access");
         access |= ACCESSCTL_SIP;
      }
   } else {
      access |= ACCESSCTL_SIP;
   }

/*
 * check SIP registration allow list
 */
   if ( (configuration.hosts_allow_reg !=NULL) &&
        (strcmp(configuration.hosts_allow_reg,"")!=0) ) {
      /* non-empty list -> check agains it */
      if (process_aclist(configuration.hosts_allow_reg, from)==STS_SUCCESS) {
         /* SIP registration access granted */
         DEBUGC(DBCLASS_ACCESS,"granted REG/SIP access");
         access |= ACCESSCTL_REG | ACCESSCTL_SIP;
      }
   } else {
      access |= ACCESSCTL_REG;
   }

   DEBUGC(DBCLASS_ACCESS,"access check =%i", access);
   return access;
}
Exemplo n.º 14
0
/*
 * module-local functions
 */
static int stun_validate_response(char *buffer, int len, char *tid){

   /* expect min. STUN header + 1 attribute */
   if (len < 24) {
      DEBUGC(DBCLASS_BABBLE,"stun_validate_response: no STUN response (too short)");
      return STS_FAILURE;
   }

   if (ntohs(*((int*)&buffer[0]) & 0x0000ffff) != 0x0101) {
      DEBUGC(DBCLASS_BABBLE,"stun_validate_response: no STUN response (type)");
      return STS_FAILURE;
   }

   if (memcmp(&buffer[4], tid, STUN_TID_SIZE) != 0) {
      DEBUGC(DBCLASS_BABBLE,"stun_validate_response: wrong STUN response (TID)");
      return STS_FAILURE;
   }

   DEBUGC(DBCLASS_BABBLE,"valid STUN response");
   return STS_SUCCESS;
}
Exemplo n.º 15
0
static int stun_send_request(char *tid){
   struct in_addr addr;
   int sts;
   char stun_rq[28];	/*&&& testing */
   size_t size=28;

   /* name resolution */
   if (utils_inet_aton(plugin_cfg.server, &addr) == 0)
   {
      /* need name resolution */
      DEBUGC(DBCLASS_DNS,"resolving name:%s", plugin_cfg.server);
      sts = get_ip_by_host(plugin_cfg.server, &addr);
      if (sts == STS_FAILURE) {
         DEBUGC(DBCLASS_DNS, "stun_send_request: cannot resolve STUN server [%s]",
                plugin_cfg.server);
         return STS_FAILURE;
      }
   }   

   /* compose STUN BIND request - poor mans way */
   stun_rq[0]=0x00;	// type
   stun_rq[1]=0x01;
   stun_rq[2]=0x00;	// length
   stun_rq[3]=0x08;
   memcpy (&stun_rq[4], tid, STUN_TID_SIZE);
   stun_rq[20]=0x00;	// ATTR change request
   stun_rq[21]=0x03;
   stun_rq[22]=0x00;	// ATTR len 4
   stun_rq[23]=0x04;
   stun_rq[24]=0x00;	// Change IP not set, Change port not set
   stun_rq[25]=0x00;
   stun_rq[26]=0x00;
   stun_rq[27]=0x00;

   /* and send via the SIP UDP port */
   sts = sipsock_send(addr, plugin_cfg.port, PROTO_UDP, stun_rq, size);

   return STS_SUCCESS;
}
Exemplo n.º 16
0
Arquivo: proxy.c Projeto: OPSF/uClinux
/*
 * PROXY_REWRITE_REQUEST_URI
 *
 * rewrites the incoming Request URI
 * 
 * RETURNS
 *	STS_SUCCESS on success
 */
int proxy_rewrite_request_uri(osip_message_t *mymsg, int idx){
   char *host;
   char *port;
   osip_uri_t *url;

   if ((idx >= URLMAP_SIZE) || (idx < 0)) {
      WARN("proxy_rewrite_request_uri: called with invalid index");
      return STS_FAILURE;
   }

   DEBUGC(DBCLASS_PROXY,"rewriting incoming Request URI");
   url=osip_message_get_uri(mymsg);

   /* set the true host */
   if (url->host) osip_free(url->host);url->host=NULL;
   if (urlmap[idx].true_url->host) {
      DEBUGC(DBCLASS_BABBLE,"proxy_rewrite_request_uri: host=%s",
             urlmap[idx].true_url->host);
      host = (char *)malloc(strlen(urlmap[idx].true_url->host)+1);
      memcpy(host, urlmap[idx].true_url->host, strlen(urlmap[idx].true_url->host));
      host[strlen(urlmap[idx].true_url->host)]='\0';
      osip_uri_set_host(url, host);
   }

   /* set the true port */
   if (url->port) osip_free(url->port);url->port=NULL;
   if (urlmap[idx].true_url->port) {
      DEBUGC(DBCLASS_BABBLE,"proxy_rewrite_request_uri: port=%s",
             urlmap[idx].true_url->port);
      port = (char *)malloc(strlen(urlmap[idx].true_url->port)+1);
      memcpy(port, urlmap[idx].true_url->port, strlen(urlmap[idx].true_url->port));
      port[strlen(urlmap[idx].true_url->port)]='\0';
      osip_uri_set_port(url, port);
   }
   return STS_SUCCESS;
}
Exemplo n.º 17
0
/*
 * compare_client_id:
 * Compares two client_id_t structures. If both have the Contact item
 * defined (not NULL), then compare it and return.
 * If one (or both) do NOT have the contact item defined, then
 * fall back on comparing the from_ip (IP address).
 *
 * returns:
 * STS_SUCCESS on match
 * STS_FAILURE on no match
 */
int  compare_client_id(client_id_t cid1, client_id_t cid2) {

   /* Prio 1: Contact - if present in both structures */
   if ((cid1.idstring[0] != '\0') && (cid2.idstring[0] != '\0')) {
      if (strncmp(cid1.idstring, cid2.idstring, CLIENT_ID_SIZE) == 0) {
         DEBUGC(DBCLASS_BABBLE, "compare_client_id: contact match [%s]",
                cid1.idstring);
         return STS_SUCCESS;
      }
      DEBUGC(DBCLASS_BABBLE, "compare_client_id: contact NO match [%s<->%s]",
             cid1.idstring, cid2.idstring);
      return STS_FAILURE;
   }

   /* Prio 2: IP (always present) - fallback, if no ID string present. */
   if (memcmp(&cid1.from_ip, &cid2.from_ip, sizeof(struct in_addr)) == 0) {
      DEBUGC(DBCLASS_BABBLE, "compare_client_id: IP match [%s]",
             utils_inet_ntoa(cid1.from_ip));
      return STS_SUCCESS;
   }

   DEBUGC(DBCLASS_BABBLE, "compare_client_id: no match");
   return STS_FAILURE;
}
Exemplo n.º 18
0
/*
 * Create the PID file
 */
int createpidfile(char *pidfilename) {
   FILE *f = NULL;
   int sts;
   DEBUGC(DBCLASS_CONFIG,"creating PID file [%s]", pidfilename);
   sts=unlink(pidfilename);
   if ((sts==0) || (errno == ENOENT)) {
      if ((f=fopen(pidfilename, "w"))) {
         fprintf(f,"%i\n",(int)getpid());
         fclose(f);
      } else {
         WARN("couldn't create new PID file: %s", strerror(errno));
         return STS_FAILURE;
      }
   } else {
      WARN("couldn't delete old PID file: %s", strerror(errno));
      return STS_FAILURE;
   }
   return STS_SUCCESS;
}
Exemplo n.º 19
0
/*
 * shut down the URL mapping table
 */
void register_save(void) {
   int i;
   FILE *stream;

   if (configuration.registrationfile) {
      DEBUGC(DBCLASS_REG,"saving registration table");
      /* write urlmap back to file */
      stream = fopen(configuration.registrationfile, "w+");
      if (!stream) {
         /* try to unlink it and open again */
         unlink(configuration.registrationfile);
         stream = fopen(configuration.registrationfile, "w+");

         /* open file for write failed, complain */
         if (!stream) {
            ERROR("unable to write registration file");
            return;
         }
      }

      for (i=0;i < URLMAP_SIZE; i++) {
         fprintf(stream, "***:%i:%i\n", urlmap[i].active, urlmap[i].expires);
         if (urlmap[i].active) {
            #define W(X) fprintf(stream, "%s\n", (X)? X:"");

            W(urlmap[i].true_url->scheme);
            W(urlmap[i].true_url->username);
            W(urlmap[i].true_url->host);
            W(urlmap[i].true_url->port);
            W(urlmap[i].masq_url->scheme);
            W(urlmap[i].masq_url->username);
            W(urlmap[i].masq_url->host);
            W(urlmap[i].masq_url->port);
            W(urlmap[i].reg_url->scheme);
            W(urlmap[i].reg_url->username);
            W(urlmap[i].reg_url->host);
            W(urlmap[i].reg_url->port);
         }
      }
      fclose(stream);
   }
   return;
}
Exemplo n.º 20
0
/*
 * get_interface_ip:
 * fetches own IP address by interface INBOUND/OUTBOUND
 * takes into account a possible outbound_host setting.
 *
 * STS_SUCCESS on returning a valid IP and interface is UP
 * STS_FAILURE if interface is DOWN or other problem
 */
int  get_interface_ip(int interface, struct in_addr *retaddr) {
   int sts=STS_FAILURE;

   if ((interface == IF_OUTBOUND) && 
              (configuration.outbound_host) &&
              (strcmp(configuration.outbound_host, "")!=0)) {
      DEBUGC(DBCLASS_DNS, "fetching outbound IP by HOSTNAME");
      if (retaddr) {
         sts = get_ip_by_host(configuration.outbound_host, retaddr);
      } else {
         sts = STS_SUCCESS;
      }

   } else  {
      sts = get_interface_real_ip(interface, retaddr);
   }

   return sts;
}
Exemplo n.º 21
0
/*
 * SIP_ADD_MYVIA
 *
 * interface == IF_OUTBOUND, IF_INBOUND
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 */
int sip_add_myvia (sip_ticket_t *ticket, int interface,
		   struct in_addr *local_ip) {
   struct in_addr addr;
   char tmp[URL_STRING_SIZE] = {0};
   osip_via_t *via;
   int sts;
   char branch_id[VIA_BRANCH_SIZE];

   if (local_ip == NULL) {
      if (interface == IF_OUTBOUND) {
         if (get_ip_by_ifname(configuration.outbound_if, &addr) != STS_SUCCESS) {
            ERROR("can't find interface %s - configuration error?",
                configuration.outbound_if);
            return STS_FAILURE;
         }
      } else {
         if (get_ip_by_ifname(configuration.inbound_if, &addr) != STS_SUCCESS) {
            ERROR("can't find inbound interface %s - configuration error?",
                configuration.inbound_if);
            return STS_FAILURE;
         }
      }
   } else {
      addr = *local_ip;
   }


   sts = sip_calculate_branch_id(ticket, branch_id);

   snprintf(tmp,URL_STRING_SIZE, "SIP/2.0/UDP %s:%i;branch=%s;", utils_inet_ntoa(addr),
           configuration.sip_listen_port, branch_id);
   DEBUGC(DBCLASS_BABBLE,"adding VIA:%s",tmp);

   sts = osip_via_init(&via);
   if (sts!=0) return STS_FAILURE; /* allocation failed */

   sts = osip_via_parse(via, tmp);
   if (sts!=0) return STS_FAILURE;

   osip_list_add(ticket->sipmsg->vias,via,0);

   return STS_SUCCESS;
}
Exemplo n.º 22
0
/*
 * read a message from SIP listen socket (UDP datagram)
 *
 * RETURNS number of bytes read
 *         from is modified to return the sockaddr_in of the sender
 */
int sipsock_read(int fd, void *buf, size_t bufsize,
                 struct sockaddr_in *from, int *protocol) {
   int count;
   socklen_t fromlen;
   /* start of AU4D00875 by d00107688 to support bind 2008-10-15*/
    if (fd < 0)
    {
        count = 0;
        return count;
    }
   /* end of AU4D00875 by d00107688 to support bind 2008-10-15*/
   fromlen=sizeof(struct sockaddr_in);
   *protocol = PROTO_UDP; /* up to now, unly UDP */
   #if 0
   count=recvfrom(sip_udp_socket, buf, bufsize, 0,
                  (struct sockaddr *)from, &fromlen);
   #else
   /*BEGIN 3092906251 s00201037 2013-10-15 added*/   
   count=recvfrom(fd, buf, bufsize, 0,
                  from, &fromlen);
   //   count=recvfrom(fd, buf, bufsize, 0,
     //             (struct sockaddr *)from, &fromlen);
   /*END 3092906251 s00201037 2013-10-15 added*/	 
   #endif

   if (count<0) {
      WARN("recvfrom() returned error [%s]",strerror(errno));
      *protocol = PROTO_UNKN;
   }

   DEBUGC(DBCLASS_NET,"received UDP packet from %s, count=%i",
          utils_inet_ntoa(from->sin_addr), count);
   DUMP_BUFFER(DBCLASS_NETTRAF, buf, count);
   /*BEGIN 3092906251 s00201037 2013-10-15 added*/
   lansrcport = 0;
   lansrcport = ntohs(from->sin_port);
   lansrcip = htonl(inet_addr(utils_inet_ntoa(from->sin_addr)));
   /*END 3092906251 s00201037 2013-10-15 added*/

   return count;
}
Exemplo n.º 23
0
/*
 * SIP_DEL_MYVIA
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on error
 */
int sip_del_myvia (sip_ticket_t *ticket, struct in_addr *local_ip) {
   osip_via_t *via;
   int sts;

   DEBUGC(DBCLASS_PROXY,"deleting topmost VIA");
   via = osip_list_get (ticket->sipmsg->vias, 0);
   
   if ( via == NULL ) {
      ERROR("Got empty VIA list - is your UA configured properly?");
      return STS_FAILURE;
   }

   if ( is_via_local(via, local_ip) == STS_FALSE ) {
      ERROR("I'm trying to delete a VIA but it's not mine! host=%s",via->host);
      return STS_FAILURE;
   }

   sts = osip_list_remove(ticket->sipmsg->vias, 0);
   osip_via_free (via);
   return STS_SUCCESS;
}
Exemplo n.º 24
0
/*
 * get_interface_real_ip:
 * fetches the real IP address of my interface INBOUND/OUTBOUND
 *
 * STS_SUCCESS on returning a valid IP and interface is UP
 * STS_FAILURE if interface is DOWN or other problem
 */
int  get_interface_real_ip(int interface, struct in_addr *retaddr) {
   int sts=STS_FAILURE;
   char *tmp=NULL;

      if (interface == IF_INBOUND) {
         tmp = configuration.inbound_if;
      } else if (interface == IF_OUTBOUND) {
         tmp = configuration.outbound_if;
      }

   if (tmp && (strcmp(tmp, "")!=0)) {
      DEBUGC(DBCLASS_DNS, "fetching interface IP by INTERFACE [%i]", interface);
      sts = get_ip_by_ifname(tmp, retaddr);
      if (sts != STS_SUCCESS) {
         ERROR("can't find interface %s - configuration error?", tmp);
      }

   } else {
      ERROR("Don't know what interface to look for - configuration error?");
   }

   return sts;
}
Exemplo n.º 25
0
/*
 * resolve a hostname and return in_addr
 * handles its own little DNS cache.
 *
 * RETURNS
 *	STS_SUCCESS on success
 *	STS_FAILURE on failure
 */
int get_ip_by_host(char *hostname, struct in_addr *addr) {
   int i, j, k, idx;
   time_t t1, t2;
   struct hostent *hostentry;
#if defined(HAVE_GETHOSTBYNAME_R)
   struct hostent result_buffer;
   char tmp[GETHOSTBYNAME_BUFLEN];
#endif
   int error;
   static struct {
      time_t expires_timestamp;	/* time of expiration */
      struct in_addr addr;	/* IP address or 0.0.0.0 if a bad entry */
      char   error_count;	/* counts failed resolution attempts */
      char   bad_entry;		/* != 0 if resolving failed */
      char hostname[HOSTNAME_SIZE+1];
   } dns_cache[DNS_CACHE_SIZE];
   static int cache_initialized=0;

   if (hostname == NULL) {
      ERROR("get_ip_by_host: NULL hostname requested");
      return STS_FAILURE;
   }

   if (addr == NULL) {
      ERROR("get_ip_by_host: NULL in_addr passed");
      return STS_FAILURE;
   }

   /* first time: initialize DNS cache */
   if (cache_initialized == 0) {
      DEBUGC(DBCLASS_DNS, "initializing DNS cache (%i entries)", DNS_CACHE_SIZE);
      memset(dns_cache, 0, sizeof(dns_cache));
      cache_initialized=1;
   }

   time(&t1);
   /* clean expired entries */
   for (i=0; i<DNS_CACHE_SIZE; i++) {
      if (dns_cache[i].hostname[0]=='\0') continue;
      if ( (dns_cache[i].expires_timestamp) < t1 ) {
         DEBUGC(DBCLASS_DNS, "cleaning DNS cache (entry %i)", i);
         memset (&dns_cache[i], 0, sizeof(dns_cache[0]));
      }
   }

   /*
    * search requested entry in cache
    */
   idx=0;
   for (i=0; i<DNS_CACHE_SIZE; i++) {
      if (dns_cache[i].hostname[0]=='\0') continue; /* empty */
      if (strcasecmp(hostname, dns_cache[i].hostname) == 0) { /* match */
         memcpy(addr, &dns_cache[i].addr, sizeof(struct in_addr));
         if (dns_cache[i].bad_entry) {
            DEBUGC(DBCLASS_DNS, "DNS lookup - blacklisted from cache: %s",
                   hostname);
            return STS_FAILURE;
         }
         if (dns_cache[i].error_count > 0) {
            DEBUGC(DBCLASS_DNS, "DNS lookup - previous resolution failed: %s"
                   ", attempt %i", hostname, dns_cache[i].error_count);
            idx=i;
            break;
         }
         DEBUGC(DBCLASS_DNS, "DNS lookup - from cache: %s -> %s",
                hostname, utils_inet_ntoa(*addr));
         return STS_SUCCESS;
      }
   }
   
   /* I did not find it in cache, so I have to resolve it */
   error = 0;

   /* need to deal with reentrant versions of gethostbyname_r()
    * as we may use threads... */
#if defined(HAVE_GETHOSTBYNAME_R)

   /* gethostbyname_r() with 3 arguments (e.g. osf/1) */
   #if defined(HAVE_FUNC_GETHOSTBYNAME_R_3)
   gethostbyname_r(hostname,		/* the FQDN */
		   &result_buffer,	/* the result buffer */ 
		   &hostentry
		   );
   if (hostentry == NULL) error = h_errno;

   /* gethostbyname_r() with 5 arguments (e.g. solaris, linux libc5) */
   #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
   hostentry = gethostbyname_r(hostname,        /* the FQDN */
			       &result_buffer,  /* the result buffer */
			       tmp,
			       GETHOSTBYNAME_BUFLEN,
			       &error);

   /* gethostbyname_r() with 6 arguments (e.g. linux glibc) */
   #elif defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
   gethostbyname_r(hostname,        /* the FQDN */
		   &result_buffer,  /* the result buffer */
		   tmp,
		   GETHOSTBYNAME_BUFLEN,
		   &hostentry,
		   &error);
   #else
      #error "gethostbyname_r() with 3, 5 or 6 arguments supported only"
   #endif   
#elif defined(HAVE_GETHOSTBYNAME)
   hostentry=gethostbyname(hostname);
   if (hostentry == NULL) error = h_errno;
#else
   #error "need gethostbyname() or gethostbyname_r()"
#endif
   /* Here I have 'hostentry' and 'error' */


   if (hostentry==NULL) {
      /*
       * Some errors just tell us that there was no IP resolvable.
       * From the manpage:
       *   HOST_NOT_FOUND
       *      The specified host is unknown.
       *   NO_ADDRESS or NO_DATA
       *      The requested name is valid but does not have an IP
       *      address.
       */
      if ((error == HOST_NOT_FOUND) ||
          (error == NO_ADDRESS) ||
          (error == NO_DATA)) {
#ifdef HAVE_HSTRERROR
         DEBUGC(DBCLASS_DNS, "gethostbyname(%s) failed: h_errno=%i [%s]",
                hostname, h_errno, hstrerror(error));
#else
         DEBUGC(DBCLASS_DNS, "gethostbyname(%s) failed: h_errno=%i",
                hostname, error);
#endif
      } else {
#ifdef HAVE_HSTRERROR
         ERROR("gethostbyname(%s) failed: h_errno=%i [%s]",
               hostname, h_errno, hstrerror(h_errno));
#else
         ERROR("gethostbyname(%s) failed: h_errno=%i",hostname, h_errno);
#endif
      }
   }

   if (hostentry) {
      memcpy(addr, hostentry->h_addr, sizeof(struct in_addr));
      DEBUGC(DBCLASS_DNS, "DNS lookup - resolved: %s -> %s",
             hostname, utils_inet_ntoa(*addr));
   }

   /* if we already have the entry, skip finding a new empty one */
   if (idx == 0) {
      /*
       * find an empty slot in the cache
       */
      j=0;
      k=0;
      t1=INT_MAX;
      t2=INT_MAX;
      for (i=0; i<DNS_CACHE_SIZE; i++) {
         if (dns_cache[i].hostname[0]=='\0') break;
         if ((dns_cache[i].expires_timestamp < t1) &&
             (dns_cache[i].bad_entry == 0)) {
            /* remember oldest good entry */
            t1=dns_cache[i].expires_timestamp;
            j=i;
         } else 
         if (dns_cache[i].expires_timestamp < t2) {
            /* remember oldest bad entry */
            t2=dns_cache[i].expires_timestamp;
            k=i;
         }
      }
      /* if no empty slot found, victimize oldest one.
       * Give preference to the oldest "bad" entry if 
       * one exists */
      if (i >= DNS_CACHE_SIZE) {
         if (k > 0) i=k;
         else       i=j;
      }
      idx=i;
      memset(&dns_cache[idx], 0, sizeof(dns_cache[0]));
   }

   /*
    * store the result in the cache
    */
   DEBUGC(DBCLASS_DNS, "DNS lookup - store into cache, entry %i)", idx);
   strncpy(dns_cache[idx].hostname, hostname, HOSTNAME_SIZE);
   dns_cache[idx].expires_timestamp = time(NULL) + DNS_GOOD_AGE;
   if (hostentry) {
      memcpy(&dns_cache[idx].addr, addr, sizeof(struct in_addr));
      dns_cache[idx].error_count = 0;
      dns_cache[idx].bad_entry = 0;
   } else {
      dns_cache[idx].error_count++;
      DEBUGC(DBCLASS_DNS, "DNS lookup - errcnt=%i", dns_cache[idx].error_count);
      if (dns_cache[idx].error_count >= DNS_ATTEMPTS) {
         DEBUGC(DBCLASS_DNS, "DNS lookup - blacklisting entry");
         dns_cache[idx].expires_timestamp = time(NULL) + DNS_BAD_AGE;
         dns_cache[idx].bad_entry = 1;
      }
      return STS_FAILURE;
   }
   return STS_SUCCESS;
}
Exemplo n.º 26
0
/*
 * handles register requests and updates the URL mapping table
 *
 * RETURNS:
 *    STS_SUCCESS : successfully registered
 *    STS_FAILURE : registration failed
 *    STS_NEED_AUTH : authentication needed
 */
int register_client(sip_ticket_t *ticket, int force_lcl_masq) {
   int i, j, n, sts;
   int expires;
   time_t time_now;
   osip_contact_t *contact;
   osip_uri_t *url1_to, *url1_contact=NULL;
   osip_uri_t *url2_to;
   osip_header_t *expires_hdr;
   osip_uri_param_t *expires_param=NULL;
   
   /*
    * Authorization - do only if I'm not just acting as outbound proxy
    * but am ment to be the registrar
    */
   if (force_lcl_masq == 0) {
      /*
       * RFC 3261, Section 16.3 step 6
       * Proxy Behavior - Request Validation - Proxy-Authorization
       */
      sts = authenticate_proxy(ticket->sipmsg);
      if (sts == STS_FAILURE) {
         /* failed */
         WARN("proxy authentication failed for %s@%s",
              (ticket->sipmsg->to->url->username)? 
              ticket->sipmsg->to->url->username : "******",
              ticket->sipmsg->to->url->host);
         return STS_FAILURE;
      } else if (sts == STS_NEED_AUTH) {
         /* needed */
         DEBUGC(DBCLASS_REG,"proxy authentication needed for %s@%s",
                ticket->sipmsg->to->url->username,
                ticket->sipmsg->to->url->host);
         return STS_NEED_AUTH;
      }
   }

/*
   fetch 1st Via entry and remember this address. Incoming requests
   for the registered address have to be passed on to that host.

   To: -> address to be registered
   Contact: -> host is reachable there
               Note: in case of un-REGISTER, the contact header may
                     contain '*' only - which means "all registrations
                     made by this UA"
   
   => Mapping is
   To: <1--n> Contact
   
*/
   time(&time_now);

   DEBUGC(DBCLASS_BABBLE,"sip_register:");

   /*
    * First make sure, we have a proper Contact header:
    *  - url
    *  - url -> hostname
    *
    * Libosip parses an:
    * "Contact: *"
    * the following way (Note: Display name!! and URL is NULL)
    * (gdb) p *((osip_contact_t*)(sip->contacts.node->element))
    * $5 = {displayname = 0x8af8848 "*", url = 0x0, gen_params = 0x8af8838}
    */

   osip_message_get_contact(ticket->sipmsg, 0, &contact);
   if ((contact == NULL) ||
       (contact->url == NULL) ||
       (contact->url->host == NULL)) {
      /* Don't have required Contact fields.
         This may be a Registration query or unregistering all registered
         records for this UA. We should simply forward this request to its
         destination. However, if this is an unregistration from a client
         that is not registered (Grandstream "unregister at startup" option)
         -> How do I handle this one?
         Right now we do a direction lookup and if this fails we generate
         an OK message by ourself (fake) */
      DEBUGC(DBCLASS_REG, "empty Contact header - "
             "seems to be a registration query");
      sts = sip_find_direction(ticket, NULL);
      if (sts != STS_SUCCESS) {
         /* answer the request myself. Most likely this is an UNREGISTER
          * request when the client just booted */
         sts = register_response(ticket, STS_SUCCESS);
         return STS_SIP_SENT;
      }

      return STS_SUCCESS;
   }

   url1_contact=contact->url;

   /* evaluate Expires Header field */
   osip_message_get_expires(ticket->sipmsg, 0, &expires_hdr);

  /*
   * look for an Contact expires parameter - in case of REGISTER
   * these two are equal. The Contact expires has higher priority!
   */
   if (ticket->sipmsg->contacts.node &&
       ticket->sipmsg->contacts.node->element) {
      osip_contact_param_get_byname(
              (osip_contact_t*) ticket->sipmsg->contacts.node->element,
              EXPIRES, &expires_param);
   }

   if (expires_param && expires_param->gvalue) {
      /* get expires from contact Header */
      expires=atoi(expires_param->gvalue);
      if ((expires < 0) || (expires >= UINT_MAX ))
         expires=configuration.default_expires;
   } else if (expires_hdr && expires_hdr->hvalue) {
      /* get expires from expires Header */
      expires=atoi(expires_hdr->hvalue);
      if ((expires < 0) || (expires >= UINT_MAX ))
         expires=configuration.default_expires;
   } else {
      char tmp[16];
      /* it seems, the expires field is not present everywhere... */
      DEBUGC(DBCLASS_REG,"no 'expires' header found - set time to %i sec",
             configuration.default_expires);
      expires=configuration.default_expires;
      sprintf(tmp,"%i",expires);
      osip_message_set_expires(ticket->sipmsg, tmp);
   }

   url1_to=ticket->sipmsg->to->url;



   /*
    * REGISTER
    */
   if (expires > 0) {
      DEBUGC(DBCLASS_REG,"register: %s@%s expires=%i seconds",
          (url1_contact->username) ? url1_contact->username : "******",
          (url1_contact->host) ? url1_contact->host : "*NULL*",
          expires);

      /*
       * Update registration. There are two possibilities:
       * - already registered, then update the existing record
       * - not registered, then create a new record
       */

      j=-1;
      for (i=0; i<URLMAP_SIZE; i++) {
         if (urlmap[i].active == 0) {
            if (j < 0) j=i; /* remember first hole */
            continue;
         }

         url2_to=urlmap[i].reg_url;

         /* check address-of-record ("public address" of user) */
         if (compare_url(url1_to, url2_to)==STS_SUCCESS) {
            DEBUGC(DBCLASS_REG, "found entry for %s@%s <-> %s@%s at "
                   "slot=%i, exp=%li",
                   (url1_contact->username) ? url1_contact->username : "******",
                   (url1_contact->host) ? url1_contact->host : "*NULL*",
                   (url2_to->username) ? url2_to->username : "******",
                   (url2_to->host) ? url2_to->host : "*NULL*",
                   i, (long)urlmap[i].expires-time_now);
            break;
         }
      }

      if ( (j < 0) && (i >= URLMAP_SIZE) ) {
         /* oops, no free entries left... */
         ERROR("URLMAP is full - registration failed");
         return STS_FAILURE;
      }

      if (i >= URLMAP_SIZE) {
         /* entry not existing, create new one */
         i=j;

         /* write entry */
         urlmap[i].active=1;
         /* Contact: field */
         osip_uri_clone( ((osip_contact_t*)
                         (ticket->sipmsg->contacts.node->element))->url, 
                         &urlmap[i].true_url);
         /* To: field */
         osip_uri_clone( ticket->sipmsg->to->url, 
                    &urlmap[i].reg_url);

         DEBUGC(DBCLASS_REG,"create new entry for %s@%s <-> %s@%s at slot=%i",
                (url1_contact->username) ? url1_contact->username : "******",
                (url1_contact->host) ? url1_contact->host : "*NULL*",
                (urlmap[i].reg_url->username) ? urlmap[i].reg_url->username : "******",
                (urlmap[i].reg_url->host) ? urlmap[i].reg_url->host : "*NULL*",
                i);

         /*
          * try to figure out if we ought to do some masquerading
          */
         osip_uri_clone( ticket->sipmsg->to->url, 
                         &urlmap[i].masq_url);

         n=configuration.mask_host.used;
         if (n != configuration.masked_host.used) {
            ERROR("# of mask_host is not equal to # of masked_host in config!");
            n=0;
         }

         DEBUG("%i entries in MASK config table", n);
         for (j=0; j<n; j++) {
            DEBUG("compare [%s] <-> [%s]",configuration.mask_host.string[j],
                  ticket->sipmsg->to->url->host);
            if (strcmp(configuration.mask_host.string[j],
                ticket->sipmsg->to->url->host)==0)
               break;
         }
         if (j<n) { 
            /* we are masquerading this UA, replace the host part of the url */
            DEBUGC(DBCLASS_REG,"masquerading UA %s@%s as %s@%s",
                   (url1_contact->username) ? url1_contact->username : "******",
                   (url1_contact->host) ? url1_contact->host : "*NULL*",
                   (url1_contact->username) ? url1_contact->username : "******",
                   configuration.masked_host.string[j]);
            urlmap[i].masq_url->host=realloc(urlmap[i].masq_url->host,
                                    strlen(configuration.masked_host.string[j])+1);
            strcpy(urlmap[i].masq_url->host, configuration.masked_host.string[j]);
         }
      } else { /* if new entry */
         /* This is an existing entry */
         /*
          * Some phones (like BudgeTones *may* dynamically grab a SIP port
          * so we might want to update the true_url and reg_url each time
          * we get an REGISTER
          */

         /* Contact: field (true_url) */
         osip_uri_free(urlmap[i].true_url);
         osip_uri_clone( ((osip_contact_t*)
                         (ticket->sipmsg->contacts.node->element))->url, 
                         &urlmap[i].true_url);
         /* To: field (reg_url) */
         osip_uri_free(urlmap[i].reg_url);
         osip_uri_clone( ticket->sipmsg->to->url, 
                         &urlmap[i].reg_url);
      }

      /*
       * for proxying: force device to be masqueraded
       * as with the outbound IP (masq_url)
       */
      if (force_lcl_masq) {
         struct in_addr addr;
         char *addrstr;

         if (get_interface_ip(IF_OUTBOUND, &addr) != STS_SUCCESS) {
            return STS_FAILURE;
         }

         /* host part */
         addrstr = utils_inet_ntoa(addr);
         DEBUGC(DBCLASS_REG,"masquerading UA %s@%s local %s@%s",
                (url1_contact->username) ? url1_contact->username : "******",
                (url1_contact->host) ? url1_contact->host : "*NULL*",
                (url1_contact->username) ? url1_contact->username : "******",
                addrstr);
         urlmap[i].masq_url->host=realloc(urlmap[i].masq_url->host,
                                          strlen(addrstr)+1);
         strcpy(urlmap[i].masq_url->host, addrstr);

         /* port number if required */
         if (configuration.sip_listen_port != SIP_PORT) {
            urlmap[i].masq_url->port=realloc(urlmap[i].masq_url->port, 16);
            sprintf(urlmap[i].masq_url->port, "%i",
                    configuration.sip_listen_port);
         }
      }

      /* give some safety margin for the next update */
      if (expires > 0) expires+=30;

      /* update registration timeout */
      urlmap[i].expires=time_now+expires;

   /*
    * un-REGISTER
    */
   } else { /* expires > 0 */
      /*
       * Remove registration
       * Siproxd will ALWAYS remove ALL bindings for a given
       * address-of-record
       */
      for (i=0; i<URLMAP_SIZE; i++) {
         if (urlmap[i].active == 0) continue;

         url2_to=urlmap[i].reg_url;

         if (compare_url(url1_to, url2_to)==STS_SUCCESS) {
            DEBUGC(DBCLASS_REG, "removing registration for %s@%s at slot=%i",
                   (url2_to->username) ? url2_to->username : "******",
                   (url2_to->host) ? url2_to->host : "*NULL*", i);
            urlmap[i].expires=0;
            break;
         }
      }
   }

   return STS_SUCCESS;
}
Exemplo n.º 27
0
/*
 * get_ip_by_ifname:
 * fetches own IP address by its interface name
 *
 * STS_SUCCESS on returning a valid IP and interface is UP
 * STS_FAILURE if interface is DOWN or other problem
 */
int get_ip_by_ifname(char *ifname, struct in_addr *retaddr) {
   struct in_addr ifaddr; /* resulting IP */
   int i, j;
   int ifflags=0, isup=0;
   time_t t;
   static struct {
      time_t timestamp;
      struct in_addr ifaddr;	/* IP */
      int isup;			/* interface is UP */
      char ifname[IFNAME_SIZE+1];
   } ifaddr_cache[IFADR_CACHE_SIZE];
   static int cache_initialized=0;
#ifdef HAVE_GETIFADDRS
   struct ifaddrs *ifa;
   struct ifaddrs *ifa_list;
#else
   struct ifreq ifr;
   struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
   int sockfd;
#endif

   if (ifname == NULL) {
      WARN("get_ip_by_ifname: got NULL ifname passed - please check config"
           "file ('if_inbound' and 'if_outbound')");
      return STS_FAILURE;
   }

   /* first time: initialize ifaddr cache */
   if (cache_initialized == 0) {
      DEBUGC(DBCLASS_DNS, "initializing ifaddr cache (%i entries)", 
             IFADR_CACHE_SIZE);
      memset(ifaddr_cache, 0, sizeof(ifaddr_cache));
      cache_initialized=1;
   }

   if (retaddr) memset(retaddr, 0, sizeof(struct in_addr));

   time(&t);
   /* clean expired entries */
   for (i=0; i<IFADR_CACHE_SIZE; i++) {
      if (ifaddr_cache[i].ifname[0]=='\0') continue;
      if ( (ifaddr_cache[i].timestamp+IFADR_MAX_AGE) < t ) {
         DEBUGC(DBCLASS_DNS, "cleaning ifaddr cache (entry %i)", i);
         memset (&ifaddr_cache[i], 0, sizeof(ifaddr_cache[0]));
      }
   }

   /*
    * search requested entry in cache
    */
   for (i=0; i<IFADR_CACHE_SIZE; i++) {
      if (ifaddr_cache[i].ifname[0]=='\0') continue;
      if (strcmp(ifname, ifaddr_cache[i].ifname) == 0) { /* match */
         if (retaddr) memcpy(retaddr, &ifaddr_cache[i].ifaddr,
                             sizeof(struct in_addr));
         DEBUGC(DBCLASS_DNS, "ifaddr lookup - from cache: %s -> %s %s",
	        ifname, utils_inet_ntoa(ifaddr_cache[i].ifaddr),
                (ifaddr_cache[i].isup)? "UP":"DOWN");
         return (ifaddr_cache[i].isup)? STS_SUCCESS: STS_FAILURE;
      } /* if */
   } /* for i */

   /* not found in cache, go and get it */

#ifdef HAVE_GETIFADDRS
   if (getifaddrs(&ifa_list)) {
      ERROR("Error in getifaddrs: %s",strerror(errno));
      return STS_FAILURE;
   }

   i=0; /* use "found" marker */
   for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
      DEBUGC(DBCLASS_BABBLE,"getifaddrs - %s / %s, ifa_addr=%p, addrfamily=%i",
             ifname, ifa->ifa_name,ifa->ifa_addr,
             (ifa->ifa_addr)?ifa->ifa_addr->sa_family:-1);

      if (ifa && ifa->ifa_name && ifa->ifa_addr && 
          ifa->ifa_addr->sa_family == AF_INET &&
          strcmp(ifa->ifa_name, ifname) == 0) {
         /* found the entry */
         i=1;
         memcpy(&ifaddr, &((struct sockaddr_in*)ifa->ifa_addr)->sin_addr, sizeof(struct in_addr));
         ifflags=ifa->ifa_flags;
         DEBUGC(DBCLASS_BABBLE,"getifaddrs - MATCH, sin_addr=%s",
                utils_inet_ntoa(ifaddr));
         break;
      }
   }
   freeifaddrs(ifa_list);

   if (i==0) {
      DEBUGC(DBCLASS_DNS,"Interface %s not found.", ifname);
      return STS_FAILURE;
   }

#else
   memset(&ifr, 0, sizeof(ifr));

   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
      ERROR("Error in socket: %s",strerror(errno));
      return STS_FAILURE;
   }

/*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&6 ifname=0x%p",ifname);
   strcpy(ifr.ifr_name, ifname);
   sin->sin_family = AF_INET;

   /* get interface flags */
   if(ioctl(sockfd, SIOCGIFFLAGS, &ifr) != 0) {
      ERROR("Error in ioctl SIOCGIFFLAGS: %s [%s]",
            strerror(errno), ifname);
      close(sockfd);
      return STS_FAILURE;
   } 
   ifflags=ifr.ifr_flags;
/*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&7 ifname=0x%p",ifname);

   /* get address */
   if(ioctl(sockfd, SIOCGIFADDR, &ifr) != 0) {
      ERROR("Error in ioctl SIOCGIFADDR: %s (interface %s)",
      strerror(errno), ifname);
      close(sockfd);
      return STS_FAILURE;
   }

/*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&8 ifname=0x%p",ifname);
   memcpy(&ifaddr, &sin->sin_addr, sizeof(struct in_addr));
/*&&&*/DEBUGC(DBCLASS_BABBLE,"&&&9 ifname=0x%p",ifname);
   close(sockfd);
#endif

   if (ifflags & IFF_UP) isup=1;
   else isup=0;

   DEBUGC(DBCLASS_DNS, "get_ip_by_ifname: if %s has IP:%s (flags=%x) %s",
          ifname, utils_inet_ntoa(ifaddr), ifflags,
          (isup)? "UP":"DOWN");

   /*
    *find an empty slot in the cache
    */
   j=0;
   for (i=0; i<IFADR_CACHE_SIZE; i++) {
      if (ifaddr_cache[i].ifname[0]=='\0') break;
      if (ifaddr_cache[i].timestamp < t) {
         /* remember oldest entry */
         t=ifaddr_cache[i].timestamp;
	 j=i;
      }
   }
   /* if no empty slot found, take oldest one */
   if (i >= IFADR_CACHE_SIZE) i=j;

   /*
    * store the result in the cache
    */
   DEBUGC(DBCLASS_DNS, "ifname lookup - store into cache, entry %i)", i);
   memset(&ifaddr_cache[i], 0, sizeof(ifaddr_cache[0]));
   strncpy(ifaddr_cache[i].ifname, ifname, IFNAME_SIZE);
   ifaddr_cache[i].timestamp=t;
   memcpy(&ifaddr_cache[i].ifaddr, &ifaddr, sizeof(struct in_addr));
   ifaddr_cache[i].isup=isup;

   if (retaddr) memcpy(retaddr, &ifaddr, sizeof(struct in_addr));

   return (isup)? STS_SUCCESS : STS_FAILURE;
}
Exemplo n.º 28
0
/*
 * send answer to a registration request.
 *  flag = STS_SUCCESS    -> positive answer (200)
 *  flag = STS_FAILURE    -> negative answer (503)
 *  flag = STS_NEED_AUTH  -> proxy authentication needed (407)
 *
 * RETURNS
 *      STS_SUCCESS on success
 *      STS_FAILURE on error
 */
int register_response(sip_ticket_t *ticket, int flag) {
   osip_message_t *response;
   int code;
   int sts;
   osip_via_t *via;
   int port;
   char *buffer;
   size_t buflen;
   struct in_addr addr;
   osip_header_t *expires_hdr;

   /* ok -> 200, fail -> 503 */
   switch (flag) {
   case STS_SUCCESS:
      code = 200;       /* OK */
      break;
   case STS_FAILURE:
      code = 503;       /* failed */
      break;
   case STS_NEED_AUTH:
      code = 407;       /* proxy authentication needed */
      break;
   default:
      code = 503;       /* failed */
      break;
   }

   /* create the response template */
   if ((response=msg_make_template_reply(ticket, code))==NULL) {
      ERROR("register_response: error in msg_make_template_reply");
      return STS_FAILURE;
   }

   /* insert the expiration header */
   osip_message_get_expires(ticket->sipmsg, 0, &expires_hdr);
   if (expires_hdr) {
      osip_message_set_expires(response, expires_hdr->hvalue);
   }

   /* if we send back an proxy authentication needed, 
      include the Proxy-Authenticate field */
   if (code == 407) {
      auth_include_authrq(response);
   }

   /* get the IP address from existing VIA header */
   osip_message_get_via (response, 0, &via);
   if (via == NULL) {
      ERROR("register_response: Cannot send response - no via field");
      return STS_FAILURE;
   }

   /* name resolution needed? */
   if (utils_inet_aton(via->host,&addr) == 0) {
      /* yes, get IP address */
      sts = get_ip_by_host(via->host, &addr);
      if (sts == STS_FAILURE) {
         DEBUGC(DBCLASS_REG, "register_response: cannot resolve VIA [%s]",
                via->host);
         return STS_FAILURE;
      }
   }   

   sts = sip_message_to_str(response, &buffer, &buflen);
   if (sts != 0) {
      ERROR("register_response: msg_2char failed");
      return STS_FAILURE;
   }

   /* send answer back */
   if (via->port) {
      port=atoi(via->port);
      if ((port<=0) || (port>65535)) port=SIP_PORT;
   } else {
      port=configuration.sip_listen_port;
   }

   sipsock_send(addr, port, ticket->protocol, buffer, buflen);

   /* free the resources */
   osip_message_free(response);
   free(buffer);
   return STS_SUCCESS;
}
Exemplo n.º 29
0
/*
 * set expiration timeout as received with SIP response
 *
 * RETURNS
 *      STS_SUCCESS on success
 *      STS_FAILURE on error
 */
int register_set_expire(sip_ticket_t *ticket) {
   int i, j;
   int expires=-1;
   osip_contact_t *contact=NULL;
   time_t time_now;
   osip_header_t *expires_hdr=NULL;
   osip_uri_param_t *expires_param=NULL;

   if (ticket->direction != RESTYP_INCOMING) {
      WARN("register_set_expire called with != incoming response");
      return STS_FAILURE;
   }

   time(&time_now);

   DEBUGC(DBCLASS_REG,"REGISTER response, looking for 'Expire' information");

   /* evaluate Expires Header field */
   osip_message_get_expires(ticket->sipmsg, 0, &expires_hdr);

   /* loop for all existing contact headers in message */
   for (j=0; (contact != NULL) || (j==0); j++) {
      osip_message_get_contact(ticket->sipmsg, j, &contact);

     /*
      * look for an Contact expires parameter - in case of REGISTER
      * these two are equal. The Contact expires has higher priority!
      */
      if (contact==NULL) continue;

      osip_contact_param_get_byname(contact, EXPIRES, &expires_param);

      if (expires_param && expires_param->gvalue) {
         /* get expires from contact Header */
         expires=atoi(expires_param->gvalue);
         if ((expires < 0) || (expires >= UINT_MAX ))
            expires=configuration.default_expires;
      } else if (expires_hdr && expires_hdr->hvalue) {
         /* get expires from expires Header */
         expires=atoi(expires_hdr->hvalue);
         if ((expires < 0) || (expires >= UINT_MAX ))
            expires=configuration.default_expires;
      }

      DEBUGC(DBCLASS_REG,"Expires=%i, expires_param=%p, expires_hdr=%p",
             expires, expires_param, expires_hdr);
      if (expires > 0) {

         /* search for an entry */
         for (i=0;i<URLMAP_SIZE;i++){
            if (urlmap[i].active == 0) continue;
            if ((compare_url(contact->url, urlmap[i].masq_url)==STS_SUCCESS)) break;
         }

         /* found a mapping entry */
         if (i<URLMAP_SIZE) {
            /* update registration timeout */
            DEBUGC(DBCLASS_REG,"changing registration timeout to %i"
                               " entry [%i]", expires, i);
            urlmap[i].expires=time_now+expires;
         } else {
            DEBUGC(DBCLASS_REG,"no urlmap entry found");
         }
      }
   } /* for j */
   return STS_SUCCESS;
}
Exemplo n.º 30
0
int main(int argc, char** argv) {
  s32 opt;
  u32 loop_cnt = 0, purge_age = 0, seed;
  u8 sig_loaded = 0, show_once = 0, no_statistics = 0,
     display_mode = 0, has_fake = 0;
  s32 oindex = 0;
  u8 *wordlist = NULL, *output_dir = NULL;
  u8 *sig_list_strg = NULL;
  u8 *gtimeout_str = NULL;
  u32 gtimeout = 0;

  struct termios term;
  struct timeval tv;
  u64 st_time, en_time;

  signal(SIGINT, ctrlc_handler);
  signal(SIGWINCH, resize_handler);
  signal(SIGPIPE, SIG_IGN);
  SSL_library_init();

/* Options, options, and options */

  static struct option long_options[] = {
    {"auth", required_argument, 0, 'A' },
    {"host", required_argument, 0, 'F' },
    {"cookie", required_argument, 0, 'C' },
    {"reject-cookies", required_argument, 0, 'N' },
    {"header", required_argument, 0, 'H' },
    {"user-agent", required_argument, 0, 'b' },
#ifdef PROXY_SUPPORT
    {"proxy", required_argument, 0, 'J' },
#endif /* PROXY_SUPPORT */
    {"max-depth", required_argument, 0, 'd' },
    {"max-child", required_argument, 0, 'c' },
    {"max-descendants", required_argument, 0, 'x' },
    {"max-requests", required_argument, 0, 'r' },
    {"max-rate", required_argument, 0, 'l'},
    {"probability", required_argument, 0, 'p' },
    {"seed", required_argument, 0, 'q' },
    {"include", required_argument, 0, 'I' },
    {"exclude", required_argument, 0, 'X' },
    {"skip-param", required_argument, 0, 'K' },
    {"skip-forms", no_argument, 0, 'O' },
    {"include-domain", required_argument, 0, 'D' },
    {"ignore-links", no_argument, 0, 'P' },
    {"no-ext-fuzzing", no_argument, 0, 'Y' },
    {"log-mixed-content", no_argument, 0, 'M' },
    {"skip-error-pages", no_argument, 0, 'Z' },
    {"log-external-urls", no_argument, 0, 'U' },
    {"log-cache-mismatches", no_argument, 0, 'E' },
    {"form-value", no_argument, 0, 'T' },
    {"rw-wordlist", required_argument, 0, 'W' },
    {"no-keyword-learning", no_argument, 0, 'L' },
    {"mode", required_argument, 0, 'J' },
    {"wordlist", required_argument, 0, 'S'},
    {"trust-domain", required_argument, 0, 'B' },
    {"max-connections", required_argument, 0, 'g' },
    {"max-host-connections", required_argument, 0, 'm' },
    {"max-fail", required_argument, 0, 'f' },
    {"request-timeout", required_argument, 0, 't' },
    {"network-timeout", required_argument, 0, 'w' },
    {"idle-timeout", required_argument, 0, 'i' },
    {"response-size", required_argument, 0, 's' },
    {"discard-binary", required_argument, 0, 'e' },
    {"output", required_argument, 0, 'o' },
    {"help", no_argument, 0, 'h' },
    {"quiet", no_argument, 0, 'u' },
    {"verbose", no_argument, 0, 'v' },
    {"scan-timeout", required_argument, 0, 'k'},
    {"signatures", required_argument, 0, 'z'},
    {"checks", no_argument, 0, 0},
    {"checks-toggle", required_argument, 0, 0},
    {"no-checks", no_argument, 0, 0},
    {"fast", no_argument, 0, 0},
    {"auth-form", required_argument, 0, 0},
    {"auth-form-target", required_argument, 0, 0},
    {"auth-user", required_argument, 0, 0},
    {"auth-user-field", required_argument, 0, 0},
    {"auth-pass", required_argument, 0, 0},
    {"auth-pass-field", required_argument, 0, 0},
    {"auth-verify-url", required_argument, 0, 0},
    {0, 0, 0, 0 }

  };
  /* Come up with a quasi-decent random seed. */

  gettimeofday(&tv, NULL);
  seed = tv.tv_usec ^ (tv.tv_sec << 16) ^ getpid();

  SAY("skipfish version " VERSION " by <*****@*****.**>\n");

  while ((opt = getopt_long(argc, argv,
          "+A:B:C:D:EF:G:H:I:J:K:LMNOPQR:S:T:UW:X:YZ"
          "b:c:d:ef:g:hi:k:l:m:o:p:q:r:s:t:uvw:x:z:",
          long_options, &oindex)) >= 0)

    switch (opt) {

      case 'A': {
          u8* x = (u8*)strchr(optarg, ':');
          if (!x) FATAL("Credentials must be in 'user:pass' form.");
          *(x++) = 0;
          auth_user = (u8*)optarg;
          auth_pass = x;
          auth_type = AUTH_BASIC;
          break;
        }

#ifdef PROXY_SUPPORT
      case 'J':  {
          u8* x = (u8*)strchr(optarg, ':');
          if (!x) FATAL("Proxy data must be in 'host:port' form.");
          *(x++) = 0;
          use_proxy = (u8*)optarg;
          use_proxy_port = atoi((char*)x);
          if (!use_proxy_port) FATAL("Incorrect proxy port number.");
          break;
        }
#endif /* PROXY_SUPPORT */

      case 'F': {
          u8* x = (u8*)strchr(optarg, '=');
          u32 fake_addr;
          if (!x) FATAL("Fake mappings must be in 'host=IP' form.");
          *x = 0;
          fake_addr = inet_addr((char*)x + 1);
          if (fake_addr == (u32)-1)
            FATAL("Could not parse IP address '%s'.", x + 1);
          fake_host((u8*)optarg, fake_addr);
          has_fake = 1;
          break;
        }

      case 'H': {
          u8* x = (u8*)strchr(optarg, '=');
          if (!x) FATAL("Extra headers must be in 'name=value' form.");
          *x = 0;
          if (!strcasecmp(optarg, "Cookie"))
            FATAL("Do not use -H to set cookies (try -C instead).");
          SET_HDR((u8*)optarg, x + 1, &global_http_par);
          break;
        }

      case 'C': {
          u8* x = (u8*)strchr(optarg, '=');
          if (!x) FATAL("Cookies must be in 'name=value' form.");
          if (strchr(optarg, ';'))
            FATAL("Split multiple cookies into separate -C options.");
          *x = 0;
          SET_CK((u8*)optarg, x + 1, &global_http_par);
          break;
        }

      case 'D':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(allow_domains, num_allow_domains, optarg);
        break;

      case 'K':
        APPEND_FILTER(skip_params, num_skip_params, optarg);
        break;

      case 'B':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(trust_domains, num_trust_domains, optarg);
        break;

      case 'I':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(allow_urls, num_allow_urls, optarg);
        break;

      case 'X':
        if (*optarg == '*') optarg++;
        APPEND_FILTER(deny_urls, num_deny_urls, optarg);
        break;

      case 'T': {
          u8* x = (u8*)strchr(optarg, '=');
          if (!x) FATAL("Rules must be in 'name=value' form.");
          *x = 0;
          add_form_hint((u8*)optarg, x + 1);
          break;
        }

      case 'N':
        ignore_cookies = 1;
        break;

      case 'Y':
        no_fuzz_ext = 1;
        break;

      case 'q':
        if (sscanf(optarg, "0x%08x", &seed) != 1)
          FATAL("Invalid seed format.");
        srandom(seed);
        break;

      case 'Q':
        suppress_dupes = 1;
        break;

      case 'P':
        no_parse = 1;
        break;

      case 'M':
        warn_mixed = 1;
        break;

      case 'U':
        log_ext_urls = 1;
        break;

      case 'L':
        dont_add_words = 1;
        break;

      case 'E':
        pedantic_cache = 1;
        break;

      case 'O':
        no_forms = 1;
        break;

      case 'R':
        purge_age = atoi(optarg);
        if (purge_age < 3) FATAL("Purge age invalid or too low (min 3).");
        break;

      case 'd':
        max_depth = atoi(optarg);
        if (max_depth < 2) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'c':
        max_children = atoi(optarg);
        if (!max_children) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'x':
        max_descendants = atoi(optarg);
        if (!max_descendants) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'p':
        crawl_prob = atoi(optarg);
        if (!crawl_prob) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'W':
        if (wordlist)
          FATAL("Only one -W parameter permitted (use -S to load supplemental dictionaries).");

        if (!strcmp(optarg, "-")) wordlist = (u8*)"/dev/null";
        else wordlist = (u8*)optarg;

        break;

      case 'S':
        load_keywords((u8*)optarg, 1, 0);
        break;

      case 'z':
        load_signatures((u8*)optarg);
        sig_loaded = 1;
        break;

      case 'b':
        if (optarg[0] == 'i') browser_type = BROWSER_MSIE; else
        if (optarg[0] == 'f') browser_type = BROWSER_FFOX; else
        if (optarg[0] == 'p') browser_type = BROWSER_PHONE; else
          usage(argv[0]);
        break;

      case 'g':
        max_connections = atoi(optarg);
        if (!max_connections) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'm':
        max_conn_host = atoi(optarg);
        if (!max_conn_host) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'G':
        max_guesses = atoi(optarg);
        if (!max_guesses) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'r':
        max_requests = atoi(optarg);
        if (!max_requests) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'l':
        max_requests_sec = atof(optarg);
        if (!max_requests_sec) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'f':
        max_fail = atoi(optarg);
        if (!max_fail) FATAL("Invalid value '%s'.", optarg);
        break;

      case 't':
        resp_tmout = atoi(optarg);
        if (!resp_tmout) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'w':
        rw_tmout = atoi(optarg);
        if (!rw_tmout) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'i':
        idle_tmout = atoi(optarg);
        if (!idle_tmout) FATAL("Invalid value '%s'.", optarg);
        break;

      case 's':
        size_limit = atoi(optarg);
        if (!size_limit) FATAL("Invalid value '%s'.", optarg);
        break;

      case 'o':
        if (output_dir) FATAL("Multiple -o options not allowed.");
        output_dir = (u8*)optarg;

        rmdir(optarg);

        if (mkdir(optarg, 0755))
          PFATAL("Unable to create '%s'.", output_dir);

        break;

      case 'u':
        no_statistics = 1;
        break;

      case 'v':
        verbosity++;
        break;


      case 'e':
        delete_bin = 1;
        break;

      case 'k':
        if (gtimeout_str) FATAL("Multiple -k options not allowed.");
        gtimeout_str = (u8*)optarg;
        break;

      case 'Z':
        no_500_dir = 1;
        break;

      case 0:
        if (!strcmp("checks", long_options[oindex].name ))
          display_injection_checks();
        if (!strcmp("checks-toggle", long_options[oindex].name ))
          toggle_injection_checks((u8*)optarg, 1, 1);
        if (!strcmp("no-checks", long_options[oindex].name ))
          no_checks = 1;
        if (!strcmp("signatures", long_options[oindex].name ))
          load_signatures((u8*)optarg);
        if(!strcmp("fast", long_options[oindex].name ))
          toggle_injection_checks((u8*)"2,4,5,13,14,15,16", 0, 0);
        if (!strcmp("auth-form", long_options[oindex].name ))
          auth_form = (u8*)optarg;
        if (!strcmp("auth-user", long_options[oindex].name ))
          auth_user = (u8*)optarg;
        if (!strcmp("auth-pass", long_options[oindex].name ))
          auth_pass = (u8*)optarg;
        if (!strcmp("auth-pass-field", long_options[oindex].name ))
          auth_pass_field = (u8*)optarg;
        if (!strcmp("auth-user-field", long_options[oindex].name ))
          auth_user_field = (u8*)optarg;
        if (!strcmp("auth-form-target", long_options[oindex].name ))
          auth_form_target = (u8*)optarg;
        if (!strcmp("auth-verify-url", long_options[oindex].name ))
          auth_verify_url = (u8*)optarg;

        break;

      default:
        usage(argv[0]);

  }

#ifdef PROXY_SUPPORT
  if (has_fake && use_proxy)
    FATAL("-F and -J should not be used together.");
#endif /* PROXY_SUPPORT */

  if (access(ASSETS_DIR "/index.html", R_OK))
    PFATAL("Unable to access '%s/index.html' - wrong directory?", ASSETS_DIR);

  srandom(seed);

  if (optind == argc)
    FATAL("Scan target not specified (try -h for help).");

  if (!output_dir)
    FATAL("Output directory not specified (try -h for help).");

  if(verbosity && !no_statistics && isatty(2))
    FATAL("Please use -v in combination with the -u flag or, "
          "run skipfish while redirecting stderr to a file. ");


  if (resp_tmout < rw_tmout)
    resp_tmout = rw_tmout;

  if (max_connections < max_conn_host)
    max_connections = max_conn_host;

  /* Parse the timeout string - format h:m:s */
  if (gtimeout_str) {
    int i = 0;
    int m[3] = { 1, 60, 3600 };

    u8* tok = (u8*)strtok((char*)gtimeout_str, ":");

    while(tok && i <= 2) {
      gtimeout += atoi((char*)tok) * m[i];
      tok = (u8*)strtok(NULL, ":");
      i++;
    }

    if(!gtimeout)
      FATAL("Wrong timeout format, please use h:m:s (hours, minutes, seconds)");
    DEBUG("* Scan timeout is set to %d seconds\n", gtimeout);
  }


  if (!wordlist) {
    wordlist = (u8*)"/dev/null";
    DEBUG("* No wordlist specified with -W: defaulting to /dev/null\n");
  }

  /* If no signature files have been specified via command-line: load
     the default file */
  if (!sig_loaded)
    load_signatures((u8*)SIG_FILE);

  load_keywords(wordlist, 0, purge_age);

  /* Load the signatures list for the matching */
  if (sig_list_strg) load_signatures(sig_list_strg);

  /* Try to authenticate when the auth_user and auth_pass fields are set. */
  if (auth_user && auth_pass) {
    authenticate();

    while (next_from_queue()) {
      usleep(1000);
    }

    switch (auth_state) {
      case ASTATE_DONE:
        DEBUGC(L1, "*- Authentication succeeded!\n");
        break;

      default:
        DEBUG("Auth state: %d\n", auth_state);
        FATAL("Authentication failed (use -uv for more info)\n");
        break;
    }
  }

  /* Schedule all URLs in the command line for scanning. */

  while (optind < argc) {
    struct http_request *req;

    /* Support @ notation for reading URL lists from files. */

    if (argv[optind][0] == '@') {
      read_urls((u8*)argv[optind++] + 1);
      continue;
    }

    req = ck_alloc(sizeof(struct http_request));

    if (parse_url((u8*)argv[optind], req, NULL))
      FATAL("Scan target '%s' is not a valid absolute URL.", argv[optind]);

    if (!url_allowed_host(req))
      APPEND_FILTER(allow_domains, num_allow_domains,
                    __DFL_ck_strdup(req->host));

    if (!url_allowed(req))
      FATAL("URL '%s' explicitly excluded by -I / -X rules.", argv[optind]);

    maybe_add_pivot(req, NULL, 2);
    destroy_request(req);

    optind++;
  }

  /* Char-by char stdin. */

  tcgetattr(0, &term);
  term.c_lflag &= ~ICANON;
  tcsetattr(0, TCSANOW, &term);
  fcntl(0, F_SETFL, O_NONBLOCK);

  gettimeofday(&tv, NULL);
  st_time = tv.tv_sec * 1000LL + tv.tv_usec / 1000;

#ifdef SHOW_SPLASH
  if (!no_statistics) splash_screen();
#endif /* SHOW_SPLASH */

  if (!no_statistics) SAY("\x1b[H\x1b[J");
  else SAY(cLGN "[*] " cBRI "Scan in progress, please stay tuned...\n");

  u64 refresh_time = 0;

  /* Enter the crawler loop */
  while ((next_from_queue() && !stop_soon) || (!show_once++)) {

    u8 keybuf[8];

    u64 end_time;
    u64 run_time;
    struct timeval tv_tmp;

    gettimeofday(&tv_tmp, NULL);
    end_time = tv_tmp.tv_sec * 1000LL + tv_tmp.tv_usec / 1000;

    run_time = end_time - st_time;
    if (gtimeout > 0 && run_time && run_time/1000 > gtimeout) {
      DEBUG("* Stopping scan due to timeout\n");
      stop_soon = 1;
    }

    req_sec = (req_count - queue_cur / 1.15) * 1000 / (run_time + 1);

    if (no_statistics || ((loop_cnt++ % 100) && !show_once && idle == 0))
      continue;

    if (end_time > refresh_time) {
      refresh_time = (end_time + 10);

      if (clear_screen) {
        SAY("\x1b[H\x1b[2J");
        clear_screen = 0;
      }

      SAY(cYEL "\x1b[H"
          "skipfish version " VERSION " by [email protected]\n\n"
           cBRI "  -" cPIN " %s " cBRI "-\n\n" cNOR,
           allow_domains[0]);


      if (!display_mode) {
        http_stats(st_time);
        SAY("\n");
        database_stats();
      } else {
        http_req_list();
      }

      SAY("        \r");
    }

    if (fread(keybuf, 1, sizeof(keybuf), stdin) > 0) {
      display_mode ^= 1;
      clear_screen = 1;
    }
  }

  gettimeofday(&tv, NULL);
  en_time = tv.tv_sec * 1000LL + tv.tv_usec / 1000;

  SAY("\n");

  if (stop_soon)
    SAY(cYEL "[!] " cBRI "Scan aborted by user, bailing out!" cNOR "\n");

  term.c_lflag |= ICANON;
  tcsetattr(0, TCSANOW, &term);
  fcntl(0, F_SETFL, O_SYNC);

  save_keywords((u8*)wordlist);

  write_report(output_dir, en_time - st_time, seed);

#ifdef LOG_STDERR
  SAY("\n== PIVOT DEBUG ==\n");
  dump_pivots(0, 0);
  SAY("\n== END OF DUMP ==\n\n");
#endif /* LOG_STDERR */

  SAY(cLGN "[+] " cBRI "This was a great day for science!" cRST "\n\n");

#ifdef DEBUG_ALLOCATOR
  if (!stop_soon) {
    destroy_database();
    destroy_signature_lists();
    destroy_http();
    destroy_signatures();
    __TRK_report();
  }
#endif /* DEBUG_ALLOCATOR */

  fflush(0);

  EVP_cleanup();
  CRYPTO_cleanup_all_ex_data();

  return 0;

}