|
@@ -1,1453 +0,0 @@
|
|
|
-/*
|
|
|
- * $Id$
|
|
|
- *
|
|
|
- * Copyright (C) 2002-2003 Fhg Fokus
|
|
|
- *
|
|
|
- * This file is sipsak, a free sip testing tool.
|
|
|
- *
|
|
|
- * sipsak is free software; you can redistribute it and/or modify
|
|
|
- * it under the terms of the GNU General Public License as published by
|
|
|
- * the Free Software Foundation; either version 2 of the License, or
|
|
|
- * (at your option) any later version.
|
|
|
- *
|
|
|
- * sipsak is distributed in the hope that it will be useful,
|
|
|
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
- * GNU General Public License for more details.
|
|
|
- */
|
|
|
-
|
|
|
-/* sipsak written by nils ohlmeier ([email protected]).
|
|
|
- based up on a modifyed version of shoot.
|
|
|
- set DEBUG on compile will produce much more output. primarily
|
|
|
- it will print out the sended and received messages before or after
|
|
|
- every network action.
|
|
|
-*/
|
|
|
-
|
|
|
-/* changes by [email protected]; now messages can be really received;
|
|
|
- status code returned is 2 for some local errors , 0 for success
|
|
|
- and 1 for remote error -- ICMP/timeout; can be used to test if
|
|
|
- a server is alive; 1xx messages are now ignored; windows support
|
|
|
- dropped
|
|
|
-*/
|
|
|
-
|
|
|
-/*
|
|
|
-shot written by ashhar farhan, is not bound by any licensing at all.
|
|
|
-you are free to use this code as you deem fit. just dont blame the author
|
|
|
-for any problems you may have using it.
|
|
|
-bouquets and brickbats to [email protected]
|
|
|
-*/
|
|
|
-
|
|
|
-/* TO-DO:
|
|
|
- - improve dontsend
|
|
|
- - filter out retransmissions
|
|
|
- - support for short notation
|
|
|
- - support for IPv6
|
|
|
-*/
|
|
|
-
|
|
|
-//set ts=4 :-)
|
|
|
-
|
|
|
-#include <stdlib.h>
|
|
|
-#include <stdio.h>
|
|
|
-#include <sys/types.h>
|
|
|
-#include <sys/time.h>
|
|
|
-#include <string.h>
|
|
|
-#include <ctype.h>
|
|
|
-#include <time.h>
|
|
|
-#include <unistd.h>
|
|
|
-#include <netdb.h>
|
|
|
-#include <sys/socket.h>
|
|
|
-#include <sys/utsname.h>
|
|
|
-
|
|
|
-#include <regex.h>
|
|
|
-#include <netinet/in.h>
|
|
|
-#include <arpa/inet.h>
|
|
|
-#include <sys/poll.h>
|
|
|
-
|
|
|
-#define SIPSAK_VERSION "v0.6"
|
|
|
-#define RESIZE 1024
|
|
|
-#define BUFSIZE 4096
|
|
|
-#define FQDN_SIZE 200
|
|
|
-#define REQ_INV 1
|
|
|
-#define REQ_REG 2
|
|
|
-#define REQ_OPT 3
|
|
|
-#define REQ_FLOOD 4
|
|
|
-#define REQ_RAND 5
|
|
|
-#define VIA_STR "Via: SIP/2.0/UDP "
|
|
|
-#define VIA_STR_LEN 17
|
|
|
-#define MAX_FRW_STR "Max-Forwards: "
|
|
|
-#define MAX_FRW_STR_LEN 14
|
|
|
-#define SIP20_STR " SIP/2.0\r\n"
|
|
|
-#define SIP20_STR_LEN 10
|
|
|
-#define SIP200_STR "SIP/2.0 200 OK\r\n"
|
|
|
-#define SIP200_STR_LEN 16
|
|
|
-#define REG_STR "REGISTER"
|
|
|
-#define REG_STR_LEN 8
|
|
|
-#define OPT_STR "OPTIONS"
|
|
|
-#define OPT_STR_LEN 7
|
|
|
-#define MES_STR "MESSAGE"
|
|
|
-#define MES_STR_LEN 7
|
|
|
-#define FROM_STR "From: "
|
|
|
-#define FROM_STR_LEN 6
|
|
|
-#define TO_STR "To: "
|
|
|
-#define TO_STR_LEN 4
|
|
|
-#define CALL_STR "Call-ID: "
|
|
|
-#define CALL_STR_LEN 9
|
|
|
-#define CSEQ_STR "CSeq: "
|
|
|
-#define CSEQ_STR_LEN 6
|
|
|
-#define CONT_STR "Contact: "
|
|
|
-#define CONT_STR_LEN 9
|
|
|
-#define CON_TXT_STR "Content-Type: text/plain\r\n"
|
|
|
-#define CON_TXT_STR_LEN 26
|
|
|
-#define CON_LEN_STR "Content-Length: "
|
|
|
-#define CON_LEN_STR_LEN 16
|
|
|
-#define SIPSAK_MES_STR "USRLOC test message from SIPsak for user "
|
|
|
-#define SIPSAK_MES_STR_LEN 41
|
|
|
-#define EXP_STR "Expires: "
|
|
|
-#define EXP_STR_LEN 9
|
|
|
-#define USRLOC_EXP_DEF 15
|
|
|
-#define FLOOD_METH "OPTIONS"
|
|
|
-
|
|
|
-/* lots of global variables. ugly but makes life easier. */
|
|
|
-long address;
|
|
|
-int verbose, nameend, namebeg, expires_t, flood, warning_ext;
|
|
|
-int maxforw, lport, rport, randtrash, trashchar, numeric;
|
|
|
-int file_b, uri_b, trace, via_ins, usrloc, redirects;
|
|
|
-char *username, *domainname;
|
|
|
-char fqdn[FQDN_SIZE], messusern[FQDN_SIZE];
|
|
|
-char message[BUFSIZE], mes_reply[BUFSIZE];
|
|
|
-
|
|
|
-/* take either a dot.decimal string of ip address or a
|
|
|
-domain name and returns a NETWORK ordered long int containing
|
|
|
-the address. i chose to internally represent the address as long for speedier
|
|
|
-comparisions.
|
|
|
-
|
|
|
-any changes to getaddress have to be patched back to the net library.
|
|
|
-contact: [email protected]
|
|
|
-
|
|
|
- returns zero if there is an error.
|
|
|
- this is convenient as 0 means 'this' host and the traffic of
|
|
|
- a badly behaving dns system remains inside (you send to 0.0.0.0)
|
|
|
-*/
|
|
|
-
|
|
|
-long getaddress(char *host)
|
|
|
-{
|
|
|
- int i, dotcount=0;
|
|
|
- char *p = host;
|
|
|
- struct hostent* pent;
|
|
|
- long l, *lp;
|
|
|
-
|
|
|
- /*try understanding if this is a valid ip address
|
|
|
- we are skipping the values of the octets specified here.
|
|
|
- for instance, this code will allow 952.0.320.567 through*/
|
|
|
- while (*p)
|
|
|
- {
|
|
|
- for (i = 0; i < 3; i++, p++)
|
|
|
- if (!isdigit(*p))
|
|
|
- break;
|
|
|
- if (*p != '.')
|
|
|
- break;
|
|
|
- p++;
|
|
|
- dotcount++;
|
|
|
- }
|
|
|
-
|
|
|
- /* three dots with upto three digits in before, between and after ? */
|
|
|
- if (dotcount == 3 && i > 0 && i <= 3)
|
|
|
- return inet_addr(host);
|
|
|
-
|
|
|
- /* try the system's own resolution mechanism for dns lookup:
|
|
|
- required only for domain names.
|
|
|
- inspite of what the rfc2543 :D Using SRV DNS Records recommends,
|
|
|
- we are leaving it to the operating system to do the name caching.
|
|
|
-
|
|
|
- this is an important implementational issue especially in the light
|
|
|
- dynamic dns servers like dynip.com or dyndns.com where a dial
|
|
|
- ip address is dynamically assigned a sub domain like farhan.dynip.com
|
|
|
-
|
|
|
- although expensive, this is a must to allow OS to take
|
|
|
- the decision to expire the DNS records as it deems fit.
|
|
|
- */
|
|
|
- pent = gethostbyname(host);
|
|
|
- if (!pent) {
|
|
|
- perror("no gethostbyname");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- lp = (long *) (pent->h_addr);
|
|
|
- l = *lp;
|
|
|
- return l;
|
|
|
-}
|
|
|
-
|
|
|
-/* because the full qualified domain name is needed by many other
|
|
|
- functions it will be determined by this function.
|
|
|
-*/
|
|
|
-void get_fqdn(){
|
|
|
- char hname[100], dname[100], hlp[18];
|
|
|
- size_t namelen=100;
|
|
|
- struct hostent* he;
|
|
|
- int i;
|
|
|
- unsigned char *addrp;
|
|
|
- char *fqdnp;
|
|
|
-
|
|
|
- if (gethostname(&hname[0], namelen) < 0) {
|
|
|
- printf("error: cannot determine hostname\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- /* a hostname with dots should be a domainname */
|
|
|
- if ((strchr(hname, '.'))==NULL) {
|
|
|
-#ifdef DEBUG
|
|
|
- printf("hostname without dots. determine domainname...\n");
|
|
|
-#endif
|
|
|
- if (getdomainname(&dname[0], namelen) < 0) {
|
|
|
- printf("error: cannot determine domainname\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- sprintf(fqdn, "%s.%s", hname, dname);
|
|
|
- }
|
|
|
- else {
|
|
|
- strcpy(fqdn, hname);
|
|
|
- }
|
|
|
-
|
|
|
- if (numeric) {
|
|
|
- he=gethostbyname(fqdn);
|
|
|
- if (he) {
|
|
|
- addrp = he->h_addr_list[0];
|
|
|
- hlp[0]=fqdn[0]='\0';
|
|
|
- fqdnp = &fqdn[0];
|
|
|
- for (i = 0; i < 3; i++) {
|
|
|
- sprintf(hlp, "%i.", addrp[i]);
|
|
|
- fqdnp = strcat(fqdn, hlp);
|
|
|
- }
|
|
|
- sprintf(hlp, "%i", addrp[3]);
|
|
|
- fqdnp = strcat(fqdn, hlp);
|
|
|
- }
|
|
|
- else {
|
|
|
- printf("error: can not resolve hostname\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-#ifdef DEBUG
|
|
|
- printf("fqdnhostname: %s\n", fqdn);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-/* add a Via Header Field in the message. */
|
|
|
-void add_via(char *mes)
|
|
|
-{
|
|
|
- char *via_line, *via, *backup;
|
|
|
-
|
|
|
- /* first build our own Via-header-line */
|
|
|
- via_line = malloc(VIA_STR_LEN+strlen(fqdn)+9);
|
|
|
- sprintf(via_line, "%s%s:%i\r\n", VIA_STR, fqdn, lport);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("our Via-Line: %s\n", via_line);
|
|
|
-#endif
|
|
|
-
|
|
|
- if (strlen(mes)+strlen(via_line)>= BUFSIZE){
|
|
|
- printf("can't add our Via Header Line because file is too big\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if ((via=strstr(mes,"Via:"))==NULL){
|
|
|
- /* We doesn't find a Via so we insert our via
|
|
|
- direct after the first line. */
|
|
|
- via=strchr(mes,'\n');
|
|
|
- via++;
|
|
|
- }
|
|
|
- /* finnaly make a backup, insert our via and append the backup */
|
|
|
- backup=malloc(strlen(via)+1);
|
|
|
- strncpy(backup, via, strlen(via)+1);
|
|
|
- strncpy(via, via_line, strlen(via_line));
|
|
|
- strncpy(via+strlen(via_line), backup, strlen(backup)+1);
|
|
|
- free(via_line);
|
|
|
- free(backup);
|
|
|
- if (verbose)
|
|
|
- printf("New message with Via-Line:\n%s\n", mes);
|
|
|
-}
|
|
|
-
|
|
|
-/* copy the via lines from the message to the message
|
|
|
- reply for correct routing of our reply.
|
|
|
-*/
|
|
|
-void cpy_vias(char *reply){
|
|
|
- char *first_via, *middle_via, *last_via, *backup;
|
|
|
-
|
|
|
- /* lets see if we find any via */
|
|
|
- if ((first_via=strstr(reply, "Via:"))==NULL){
|
|
|
- printf("error: the received message doesn't contain a Via header\n");
|
|
|
- exit(1);
|
|
|
- }
|
|
|
- last_via=first_via+4;
|
|
|
- middle_via=last_via;
|
|
|
- /* proceed additional via lines */
|
|
|
- while ((middle_via=strstr(last_via, "Via:"))!=NULL)
|
|
|
- last_via=middle_via+4;
|
|
|
- last_via=strchr(last_via, '\n');
|
|
|
- middle_via=strchr(mes_reply, '\n')+1;
|
|
|
- /* make a backup, insert the vias after the first line and append
|
|
|
- backup
|
|
|
- */
|
|
|
- backup=malloc(strlen(middle_via)+1);
|
|
|
- strcpy(backup, middle_via);
|
|
|
- strncpy(middle_via, first_via, last_via-first_via+1);
|
|
|
- strcpy(middle_via+(last_via-first_via+1), backup);
|
|
|
- free(backup);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("message reply with vias included:\n%s\n", mes_reply);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-/* create a valid sip header for the different modes */
|
|
|
-void create_msg(char *buff, int action){
|
|
|
- unsigned int c;
|
|
|
- char *usern;
|
|
|
-
|
|
|
- c=rand();
|
|
|
- switch (action){
|
|
|
- case REQ_REG:
|
|
|
-#ifdef DEBUG
|
|
|
- printf("username: %s\ndomainname: %s\n", username, domainname);
|
|
|
-#endif
|
|
|
- usern=malloc(strlen(username)+10);
|
|
|
- sprintf(messusern, "%s sip:%s%i", MES_STR, username, namebeg);
|
|
|
- sprintf(usern, "%s%i", username, namebeg);
|
|
|
- /* build the register, message and the 200 we need in for
|
|
|
- USRLOC on one function call*/
|
|
|
- sprintf(buff, "%s sip:%s%s%s%s:%i\r\n%s<sip:%s@%s>\r\n"
|
|
|
- "%s<sip:%s@%s>\r\n%s%u@%s\r\n%s%i %s\r\n%s<sip:%s@%s:%i>\r\n"
|
|
|
- "%s%i\r\n\r\n", REG_STR, domainname, SIP20_STR, VIA_STR, fqdn,
|
|
|
- lport, FROM_STR, usern, domainname, TO_STR, usern, domainname,
|
|
|
- CALL_STR, c, fqdn, CSEQ_STR, 3*namebeg+1, REG_STR, CONT_STR,
|
|
|
- usern, fqdn, lport, EXP_STR, expires_t);
|
|
|
- c=rand();
|
|
|
- sprintf(message, "%s sip:%s@%s%s%s%s:%i\r\n%s<sip:sipsak@%s:%i>\r\n"
|
|
|
- "%s<sip:%s@%s>\r\n%s%u@%s\r\n%s%i %s\r\n%s%s%i\r\n\r\n%s%s%i.",
|
|
|
- MES_STR, usern, domainname, SIP20_STR, VIA_STR, fqdn, lport,
|
|
|
- FROM_STR, fqdn, lport, TO_STR, usern, domainname, CALL_STR, c,
|
|
|
- fqdn, CSEQ_STR, 3*namebeg+2, MES_STR, CON_TXT_STR, CON_LEN_STR,
|
|
|
- SIPSAK_MES_STR_LEN+strlen(usern), SIPSAK_MES_STR, username,
|
|
|
- namebeg);
|
|
|
- sprintf(mes_reply, "%s%s<sip:sipsak@%s:%i>\r\n%s<sip:%s@%s>\r\n"
|
|
|
- "%s%u@%s\r\n%s%i %s\r\n%s 0\r\n\r\n", SIP200_STR, FROM_STR,
|
|
|
- fqdn, lport, TO_STR, usern, domainname, CALL_STR, c, fqdn,
|
|
|
- CSEQ_STR, 3*namebeg+2, MES_STR, CON_LEN_STR);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("message:\n%s\n", message);
|
|
|
- printf("message reply:\n%s\n", mes_reply);
|
|
|
-#endif
|
|
|
- free(usern);
|
|
|
- break;
|
|
|
- case REQ_OPT:
|
|
|
- sprintf(buff, "%s sip:%s@%s%s%s<sip:sipsak@%s:%i>\r\n"
|
|
|
- "%s<sip:%s@%s>\r\n%s%u@%s\r\n%s%i %s\r\n"
|
|
|
- "%s<sip:sipsak@%s:%i>\r\n\r\n", OPT_STR, username, domainname,
|
|
|
- SIP20_STR, FROM_STR, fqdn, lport, TO_STR, username, domainname,
|
|
|
- CALL_STR, c, fqdn, CSEQ_STR, namebeg, OPT_STR, CONT_STR, fqdn,
|
|
|
- lport);
|
|
|
- break;
|
|
|
- case REQ_FLOOD:
|
|
|
-#ifdef REGISTER_HACK
|
|
|
- usern=malloc(strlen(username)+10);
|
|
|
- sprintf(usern, "%s%i", username, namebeg);
|
|
|
- sprintf(buff, "%s sip:%s%s%s%s:%i\r\n%s<sip:%s@%s>\r\n"
|
|
|
- "%s<sip:%s@%s>\r\n%s%u@%s\r\n%s%i %s\r\n%s<sip:%s@%s:%i>\r\n"
|
|
|
- "%s%i\r\n\r\n", REG_STR, domainname, SIP20_STR, VIA_STR, fqdn,
|
|
|
- lport, FROM_STR, usern, domainname, TO_STR, usern, domainname,
|
|
|
- CALL_STR, c, fqdn, CSEQ_STR, namebeg, REG_STR, CONT_STR,
|
|
|
- usern, fqdn, lport, EXP_STR, expires_t);
|
|
|
- free(usern);
|
|
|
-#else
|
|
|
- sprintf(buff, "%s sip:%s%s%s%s:9\r\n%s<sip:sipsak@%s:9>\r\n"
|
|
|
- "%s<sip:%s>\r\n%s%u@%s\r\n%s%i %s\r\n%s<sipsak@%s:9>\r\n\r\n",
|
|
|
- FLOOD_METH, domainname, SIP20_STR, VIA_STR, fqdn, FROM_STR,
|
|
|
- fqdn, TO_STR, domainname, CALL_STR, c, fqdn, CSEQ_STR, namebeg,
|
|
|
- FLOOD_METH, CONT_STR, fqdn);
|
|
|
-#endif
|
|
|
- break;
|
|
|
- case REQ_RAND:
|
|
|
- sprintf(buff, "%s sip:%s%s%s%s:%i\r\n%s<sip:sipsak@%s:%i>\r\n"
|
|
|
- "%s<sip:%s>\r\n%s%u@%s\r\n%s%i %s\r\n%s<sipsak@%s:%i>\r\n\r\n",
|
|
|
- OPT_STR, domainname, SIP20_STR, VIA_STR, fqdn, lport, FROM_STR,
|
|
|
- fqdn, lport, TO_STR, domainname, CALL_STR, c, fqdn, CSEQ_STR,
|
|
|
- namebeg, OPT_STR, CONT_STR, fqdn, lport);
|
|
|
- break;
|
|
|
- default:
|
|
|
- printf("error: unknown request type to create\n");
|
|
|
- exit(2);
|
|
|
- break;
|
|
|
- }
|
|
|
-#ifdef DEBUG
|
|
|
- printf("request:\n%s", buff);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-/* check for the existence of a Max-Forwards header field. if its
|
|
|
- present it sets it to the given value, if not it will be inserted.*/
|
|
|
-void set_maxforw(char *mes){
|
|
|
- char *max, *backup, *crlf;
|
|
|
-
|
|
|
- if ((max=strstr(mes,"Max-Forwards"))==NULL){
|
|
|
- /* no max-forwards found so insert it after the first line*/
|
|
|
- max=strchr(mes,'\n');
|
|
|
- max++;
|
|
|
- backup=malloc(strlen(max)+1);
|
|
|
- strncpy(backup, max, strlen(max)+1);
|
|
|
- sprintf(max, "%s%i\r\n", MAX_FRW_STR, maxforw);
|
|
|
- max=strchr(max,'\n');
|
|
|
- max++;
|
|
|
- strncpy(max, backup, strlen(backup)+1);
|
|
|
- free(backup);
|
|
|
- if (verbose)
|
|
|
- printf("Max-Forwards %i inserted into header\n", maxforw);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("New message with inserted Max-Forwards:\n%s\n", mes);
|
|
|
-#endif
|
|
|
- }
|
|
|
- else{
|
|
|
- /* found max-forwards => overwrite the value with maxforw*/
|
|
|
- crlf=strchr(max,'\n');
|
|
|
- crlf++;
|
|
|
- backup=malloc(strlen(crlf)+1);
|
|
|
- strncpy(backup, crlf, strlen(crlf)+1);
|
|
|
- crlf=max + MAX_FRW_STR_LEN;
|
|
|
- sprintf(crlf, "%i\r\n", maxforw);
|
|
|
- crlf=strchr(max,'\n');
|
|
|
- crlf++;
|
|
|
- strncpy(crlf, backup, strlen(backup)+1);
|
|
|
- crlf=crlf+strlen(backup);
|
|
|
- free(backup);
|
|
|
- if (verbose)
|
|
|
- printf("Max-Forwards set to %i\n", maxforw);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("New message with changed Max-Forwards:\n%s\n", mes);
|
|
|
-#endif
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* replaces the uri in first line of mes with the other uri */
|
|
|
-void uri_replace(char *mes, char *uri)
|
|
|
-{
|
|
|
- char *foo, *backup;
|
|
|
-
|
|
|
- foo=strchr(mes, '\n');
|
|
|
- foo++;
|
|
|
- backup=malloc(strlen(foo)+1);
|
|
|
- strncpy(backup, foo, strlen(foo)+1);
|
|
|
- foo=strstr(mes, "sip");
|
|
|
- strncpy(foo, uri, strlen(uri));
|
|
|
- strncpy(foo+strlen(uri), SIP20_STR, SIP20_STR_LEN);
|
|
|
- strncpy(foo+strlen(uri)+SIP20_STR_LEN, backup, strlen(backup)+1);
|
|
|
- free(backup);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("Message with modified uri:\n%s\n", mes);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-/* trashes one character in buff randomly */
|
|
|
-void trash_random(char *message)
|
|
|
-{
|
|
|
- int r;
|
|
|
- float t;
|
|
|
- char *position;
|
|
|
-
|
|
|
- t=(float)rand()/RAND_MAX;
|
|
|
- r=t * (float)strlen(message);
|
|
|
- position=message+r;
|
|
|
- r=t*(float)255;
|
|
|
- *position=(char)r;
|
|
|
-#ifdef DEBUG
|
|
|
- printf("request:\n%s\n", message);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-/* tryes to find the warning header filed and prints out the IP */
|
|
|
-void warning_extract(char *message)
|
|
|
-{
|
|
|
- char *warning, *end, *mid, *server;
|
|
|
- int srvsize;
|
|
|
-
|
|
|
- warning=strstr(message, "Warning");
|
|
|
- if (warning) {
|
|
|
- end=strchr(warning, '"');
|
|
|
- end--;
|
|
|
- warning=strchr(warning, '3');
|
|
|
- warning=warning+4;
|
|
|
- mid=strchr(warning, ':');
|
|
|
- if (mid) end=mid;
|
|
|
- srvsize=end - warning + 1;
|
|
|
- server=malloc(srvsize);
|
|
|
- memset(server, 0, srvsize);
|
|
|
- server=strncpy(server, warning, srvsize - 1);
|
|
|
- printf("%s ", server);
|
|
|
- }
|
|
|
- else {
|
|
|
- if (verbose) printf("'no Warning header found' ");
|
|
|
- else printf("?? ");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-int cseq(char *message)
|
|
|
-{
|
|
|
- char *cseq;
|
|
|
- int num=-1;
|
|
|
-
|
|
|
- cseq=strstr(message, "CSeq");
|
|
|
- if (cseq) {
|
|
|
- cseq+=6;
|
|
|
- num=atoi(cseq);
|
|
|
- if (num < 1) {
|
|
|
-#ifdef DEBUG
|
|
|
- printf("CSeq found but not convertable\n");
|
|
|
-#endif
|
|
|
- return 0;
|
|
|
- }
|
|
|
- return num;
|
|
|
- }
|
|
|
-#ifdef DEBUG
|
|
|
- printf("no CSeq found\n");
|
|
|
-#endif
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/* this function is taken from traceroute-1.4_p12
|
|
|
- which is distributed under the GPL and it returns
|
|
|
- the difference between to timeval structs */
|
|
|
-double deltaT(struct timeval *t1p, struct timeval *t2p)
|
|
|
-{
|
|
|
- register double dt;
|
|
|
-
|
|
|
- dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
|
|
|
- (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
|
|
|
- return (dt);
|
|
|
-}
|
|
|
-
|
|
|
-/* this is the main function with the loops and modes */
|
|
|
-void shoot(char *buff)
|
|
|
-{
|
|
|
- struct sockaddr_in addr, sockname;
|
|
|
- struct timeval tv, sendtime, recvtime, firstsendt;
|
|
|
- struct timezone tz;
|
|
|
- struct pollfd sockerr;
|
|
|
- int ssock, redirected, retryAfter, nretries;
|
|
|
- int sock, i, len, ret, usrlocstep, randretrys;
|
|
|
- int dontsend, cseqcmp, cseqtmp;
|
|
|
- char *contact, *crlf, *foo, *bar;
|
|
|
- char reply[BUFSIZE];
|
|
|
- fd_set fd;
|
|
|
- socklen_t slen;
|
|
|
- regex_t redexp, proexp, okexp, tmhexp, errexp;
|
|
|
-
|
|
|
- /* initalize some local vars */
|
|
|
- redirected = 1;
|
|
|
- nretries = 5;
|
|
|
- retryAfter = 5000;
|
|
|
- usrlocstep=dontsend = 0;
|
|
|
-
|
|
|
- /* create a sending socket */
|
|
|
- sock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
- if (sock==-1) {
|
|
|
- perror("no client socket");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
-
|
|
|
- /* create a listening socket */
|
|
|
- ssock = (int)socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
- if (ssock==-1) {
|
|
|
- perror("no server socket");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
-
|
|
|
- sockname.sin_family=AF_INET;
|
|
|
- sockname.sin_addr.s_addr = htonl( INADDR_ANY );
|
|
|
- sockname.sin_port = htons((short)lport);
|
|
|
- if (bind( ssock, (struct sockaddr *) &sockname, sizeof(sockname) )==-1) {
|
|
|
- perror("no bind");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
-
|
|
|
- /* for the via line we need our listening port number */
|
|
|
- if ((via_ins||usrloc) && lport==0){
|
|
|
- memset(&sockname, 0, sizeof(sockname));
|
|
|
- slen=sizeof(sockname);
|
|
|
- getsockname(ssock, (struct sockaddr *)&sockname, &slen);
|
|
|
- lport=ntohs(sockname.sin_port);
|
|
|
- }
|
|
|
-
|
|
|
- /* set all regular expression to simplfy the result code indetification */
|
|
|
- regcomp(&proexp, "^SIP/[0-9]\\.[0-9] 1[0-9][0-9] ",
|
|
|
- REG_EXTENDED|REG_NOSUB|REG_ICASE);
|
|
|
- regcomp(&okexp, "^SIP/[0-9]\\.[0-9] 200 ",
|
|
|
- REG_EXTENDED|REG_NOSUB|REG_ICASE);
|
|
|
- regcomp(&redexp, "^SIP/[0-9]\\.[0-9] 3[0-9][0-9] ",
|
|
|
- REG_EXTENDED|REG_NOSUB|REG_ICASE);
|
|
|
- regcomp(&errexp, "^SIP/[0-9]\\.[0-9] 4[0-9][0-9] ",
|
|
|
- REG_EXTENDED|REG_NOSUB|REG_ICASE);
|
|
|
- regcomp(&tmhexp, "^SIP/[0-9]\\.[0-9] 483 ",
|
|
|
- REG_EXTENDED|REG_NOSUB|REG_ICASE);
|
|
|
-
|
|
|
- if (usrloc){
|
|
|
- /* in usrloc every test consists of three steps */
|
|
|
- nretries=3*(nameend-namebeg)+3;
|
|
|
- create_msg(buff, REQ_REG);
|
|
|
- }
|
|
|
- else if (trace){
|
|
|
- /* for trace we need some spezial initis */
|
|
|
- if (maxforw!=-1)
|
|
|
- nretries=maxforw;
|
|
|
- else
|
|
|
- nretries=255;
|
|
|
- namebeg=1;
|
|
|
- maxforw=0;
|
|
|
- create_msg(buff, REQ_OPT);
|
|
|
- add_via(buff);
|
|
|
- }
|
|
|
- else if (flood){
|
|
|
- /* this should be the max of an (32 bit) int without the sign */
|
|
|
- if (namebeg==-1) namebeg=2147483647;
|
|
|
- nretries=namebeg;
|
|
|
- namebeg=1;
|
|
|
- create_msg(buff, REQ_FLOOD);
|
|
|
- }
|
|
|
- else if (randtrash){
|
|
|
- randretrys=0;
|
|
|
- namebeg=1;
|
|
|
- create_msg(buff, REQ_RAND);
|
|
|
- nameend=strlen(buff);
|
|
|
- if (trashchar){
|
|
|
- if (trashchar < nameend)
|
|
|
- nameend=trashchar;
|
|
|
- else
|
|
|
- printf("warning: number of trashed chars to big. setting to "
|
|
|
- "request lenght\n");
|
|
|
- }
|
|
|
- nretries=nameend-1;
|
|
|
- trash_random(buff);
|
|
|
- }
|
|
|
- else {
|
|
|
- /* for non of the modes we also need some inits */
|
|
|
- if (!file_b) {
|
|
|
- namebeg=1;
|
|
|
- create_msg(buff, REQ_OPT);
|
|
|
- }
|
|
|
- retryAfter = 500;
|
|
|
- if(maxforw!=-1)
|
|
|
- set_maxforw(buff);
|
|
|
- if(via_ins)
|
|
|
- add_via(buff);
|
|
|
- }
|
|
|
-
|
|
|
- /* if we got a redirect this loop ensures sending to the
|
|
|
- redirected server*/
|
|
|
- while (redirected) {
|
|
|
- /* we don't want to send for ever */
|
|
|
- redirected=0;
|
|
|
-
|
|
|
- /* destination socket init here because it could be changed in a
|
|
|
- case of a redirect */
|
|
|
- addr.sin_addr.s_addr = address;
|
|
|
- addr.sin_port = htons((short)rport);
|
|
|
- addr.sin_family = AF_INET;
|
|
|
-
|
|
|
- /* we connect as per the RFC 2543 recommendations
|
|
|
- modified from sendto/recvfrom */
|
|
|
- ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
|
|
|
- if (ret==-1) {
|
|
|
- perror("no connect");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
-
|
|
|
- /* here we go for the number of nretries which healily depends on the
|
|
|
- mode */
|
|
|
- for (i = 0; i <= nretries; i++)
|
|
|
- {
|
|
|
- if (trace) {
|
|
|
- set_maxforw(buff);
|
|
|
- }
|
|
|
- /* some initial output */
|
|
|
- else if (usrloc && verbose) {
|
|
|
- switch (usrlocstep) {
|
|
|
- case 0:
|
|
|
- printf("registering user %s%i... ", username, namebeg);
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- printf("sending message... ");
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- printf("sending message reply... ");
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (flood && verbose) {
|
|
|
- printf("flooding message number %i\n", i+1);
|
|
|
- }
|
|
|
- else if (randtrash && verbose) {
|
|
|
- printf("message with %i randomized chars\n", i+1);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("request:\n%s\n", buff);
|
|
|
-#endif
|
|
|
- }
|
|
|
- else if (!trace && !usrloc && !flood && !randtrash && verbose){
|
|
|
- printf("** request **\n%s\n", buff);
|
|
|
- }
|
|
|
-
|
|
|
- if (! dontsend) {
|
|
|
- /* lets fire the request to the server and store when we did */
|
|
|
- ret = send(sock, buff, strlen(buff), 0);
|
|
|
- (void)gettimeofday(&sendtime, &tz);
|
|
|
- if (ret==-1) {
|
|
|
- perror("send failure");
|
|
|
- exit( 1 );
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- dontsend = 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* in flood we are only interested in sending so skip the rest */
|
|
|
- if (!flood) {
|
|
|
- /* set the timeout and wait for a response */
|
|
|
- tv.tv_sec = retryAfter/1000;
|
|
|
- tv.tv_usec = (retryAfter % 1000) * 1000;
|
|
|
-
|
|
|
- FD_ZERO(&fd);
|
|
|
- FD_SET(ssock, &fd);
|
|
|
-
|
|
|
- ret = select(FD_SETSIZE, &fd, NULL, NULL, &tv);
|
|
|
- (void)gettimeofday(&recvtime, &tz);
|
|
|
- if (ret == 0)
|
|
|
- {
|
|
|
- /* lets see if we at least received an icmp error */
|
|
|
- sockerr.fd=sock;
|
|
|
- sockerr.events=POLLERR;
|
|
|
- if ((poll(&sockerr, 1, 10))==1) {
|
|
|
- if (sockerr.revents && POLLERR) {
|
|
|
- recv(sock, reply, strlen(reply), 0);
|
|
|
- perror("send failure: ");
|
|
|
- if (randtrash)
|
|
|
- printf ("last message before send failure:"
|
|
|
- "\n%s\n", buff);
|
|
|
- exit(1);
|
|
|
- }
|
|
|
- }
|
|
|
- /* printout that we did not received anything */
|
|
|
- if (trace) printf("%i: timeout after %i ms\n", i,
|
|
|
- retryAfter);
|
|
|
- else if (verbose) printf("** timeout after %i ms**\n",
|
|
|
- retryAfter);
|
|
|
- if (randtrash) {
|
|
|
- printf("did not get a response on this request:"
|
|
|
- "\n%s\n", buff);
|
|
|
- if (i+1 < nameend) {
|
|
|
- if (randretrys == 2) {
|
|
|
- printf("sended the following message three "
|
|
|
- "times without getting a response:\n%s\n"
|
|
|
- "give up further retransmissions...\n",
|
|
|
- buff);
|
|
|
- exit(1);
|
|
|
- }
|
|
|
- else {
|
|
|
- printf("resending it without additional "
|
|
|
- "random changes...\n\n");
|
|
|
- randretrys++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- retryAfter = retryAfter * 2;
|
|
|
- if (retryAfter > 5000)
|
|
|
- retryAfter = 5000;
|
|
|
- /* if we did not exit until here lets try another send */
|
|
|
- continue;
|
|
|
- }
|
|
|
- else if ( ret == -1 ) {
|
|
|
- perror("select error");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- else if (FD_ISSET(ssock, &fd)) {
|
|
|
- /* no timeout, no error ... something has happened :-) */
|
|
|
- if (!trace && !usrloc && !randtrash)
|
|
|
- printf ("\nmessage received\n");
|
|
|
- }
|
|
|
- else {
|
|
|
- printf("\nselect returned succesfuly, nothing received\n");
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- /* we are retrieving only the extend of a decent
|
|
|
- MSS = 1500 bytes */
|
|
|
- len = sizeof(addr);
|
|
|
- ret = recv(ssock, reply, BUFSIZE, 0);
|
|
|
- if(ret > 0)
|
|
|
- {
|
|
|
- reply[ret] = 0;
|
|
|
- /* store the time of our first send */
|
|
|
- if (i==0)
|
|
|
- memcpy(&firstsendt, &sendtime, sizeof(struct timeval));
|
|
|
- /* check for old CSeq => ignore retransmission */
|
|
|
- if (usrloc) {
|
|
|
- switch (usrlocstep) {
|
|
|
- case 0:
|
|
|
- cseqcmp = 3*namebeg+1;
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- case 2:
|
|
|
- cseqcmp = 3*namebeg+2;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- cseqcmp = namebeg;
|
|
|
- cseqtmp = cseq(reply);
|
|
|
- if ((0 < cseqtmp) && (cseqtmp < cseqcmp)) {
|
|
|
- printf("received retransmission: irgnoring\n");
|
|
|
- dontsend = 1;
|
|
|
- i--;
|
|
|
- continue;
|
|
|
- }
|
|
|
- /* lets see if received a redirect */
|
|
|
- if (redirects && regexec(&redexp, reply, 0, 0, 0)==0) {
|
|
|
- printf("** received redirect ");
|
|
|
- if (warning_ext) {
|
|
|
- printf("from ");
|
|
|
- warning_extract(reply);
|
|
|
- printf("\n");
|
|
|
- }
|
|
|
- else printf("\n");
|
|
|
- /* we'll try to handle 301 and 302 here, other 3xx
|
|
|
- are to complex */
|
|
|
- regcomp(&redexp, "^SIP/[0-9]\\.[0-9] 30[1-2] ",
|
|
|
- REG_EXTENDED|REG_NOSUB|REG_ICASE);
|
|
|
- if (regexec(&redexp, reply, 0, 0, 0)==0) {
|
|
|
- /* try to find the contact in the redirect */
|
|
|
- if ((foo=strstr(reply, "Contact"))==NULL) {
|
|
|
- printf("error: cannot find Contact in this "
|
|
|
- "redirect:\n%s\n", reply);
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- crlf=strchr(foo, '\n');
|
|
|
- if ((contact=strchr(foo, '\r'))!=NULL
|
|
|
- && contact<crlf)
|
|
|
- crlf=contact;
|
|
|
- bar=malloc(crlf-foo+1);
|
|
|
- strncpy(bar, foo, crlf-foo);
|
|
|
- *(bar+(crlf-foo))='\0';
|
|
|
- if ((contact=strstr(bar, "sip"))==NULL) {
|
|
|
- printf("error: cannot find sip in the Contact "
|
|
|
- "of this redirect:\n%s\n", reply);
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if ((foo=strchr(contact, ';'))!=NULL)
|
|
|
- *foo='\0';
|
|
|
- if ((foo=strchr(contact, '>'))!=NULL)
|
|
|
- *foo='\0';
|
|
|
- if ((crlf=strchr(contact,':'))!=NULL){
|
|
|
- crlf++;
|
|
|
- /* extract the needed information*/
|
|
|
- if ((foo=strchr(crlf,':'))!=NULL){
|
|
|
- *foo='\0';
|
|
|
- foo++;
|
|
|
- rport = atoi(foo);
|
|
|
- if (!rport) {
|
|
|
- printf("error: cannot handle the port "
|
|
|
- "in the uri in Contact:\n%s\n",
|
|
|
- reply);
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- }
|
|
|
- /* correct our request */
|
|
|
- uri_replace(buff, contact);
|
|
|
- if ((foo=strchr(contact,'@'))!=NULL){
|
|
|
- foo++;
|
|
|
- crlf=foo;
|
|
|
- }
|
|
|
- /* get the new destination IP*/
|
|
|
- address = getaddress(crlf);
|
|
|
- if (!address){
|
|
|
- printf("error: cannot determine host "
|
|
|
- "address from Contact of redirect:"
|
|
|
- "\%s\n", reply);
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- }
|
|
|
- else{
|
|
|
- printf("error: missing : in Contact of this "
|
|
|
- "redirect:\n%s\n", reply);
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- free(bar);
|
|
|
- memset(&addr, 0, sizeof(addr));
|
|
|
- redirected=1;
|
|
|
- i=nretries;
|
|
|
- }
|
|
|
- else {
|
|
|
- printf("error: cannot handle this redirect:"
|
|
|
- "\n%s\n", reply);
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- }
|
|
|
- else if (trace) {
|
|
|
- if (regexec(&tmhexp, reply, 0, 0, 0)==0) {
|
|
|
- /* we received 483 to many hops */
|
|
|
- printf("%i: ", i);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("(%.3f ms)\n%s\n",
|
|
|
- deltaT(&sendtime, &recvtime), reply);
|
|
|
-#else
|
|
|
- warning_extract(reply);
|
|
|
- crlf=strchr(reply, '\n');
|
|
|
- *crlf='\0';
|
|
|
- printf("(%.3f ms) %s\n",
|
|
|
- deltaT(&sendtime, &recvtime), reply);
|
|
|
-#endif
|
|
|
- namebeg++;
|
|
|
- maxforw++;
|
|
|
- create_msg(buff, REQ_OPT);
|
|
|
- add_via(buff);
|
|
|
- continue;
|
|
|
- }
|
|
|
- else if (regexec(&proexp, reply, 0, 0, 0)==0) {
|
|
|
- /* we received a provisional response */
|
|
|
- printf("%i: ", i);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("(%.3f ms)\n%s\n",
|
|
|
- deltaT(&sendtime, &recvtime), reply);
|
|
|
-#else
|
|
|
- warning_extract(reply);
|
|
|
- crlf=strchr(reply, '\n');
|
|
|
- *crlf='\0';
|
|
|
- printf("(%.3f ms) %s\n",
|
|
|
- deltaT(&sendtime, &recvtime), reply);
|
|
|
-#endif
|
|
|
- dontsend=1;
|
|
|
- i--;
|
|
|
- continue;
|
|
|
- }
|
|
|
- else {
|
|
|
- /* anything else then 483 or provisional will
|
|
|
- be treated as final */
|
|
|
- if (maxforw==i) printf("%i: ", i);
|
|
|
- else printf("\t");
|
|
|
- warning_extract(crlf);
|
|
|
- crlf=strchr(reply,'\n');
|
|
|
- *crlf='\0';
|
|
|
- crlf++;
|
|
|
- contact=strstr(crlf, "Contact");
|
|
|
- printf("(%.3f ms) %s\n",
|
|
|
- deltaT(&sendtime, &recvtime), reply);
|
|
|
- if (contact){
|
|
|
- crlf=strchr(contact,'\n');
|
|
|
- *crlf='\0';
|
|
|
- printf("\t%s\n", contact);
|
|
|
- }
|
|
|
- else {
|
|
|
- printf("\twithout Contact header\n");
|
|
|
- }
|
|
|
- exit(0);
|
|
|
- }
|
|
|
- }
|
|
|
- else if (usrloc) {
|
|
|
- switch (usrlocstep) {
|
|
|
- case 0:
|
|
|
- /* at first we have sended a register and look
|
|
|
- at the response now*/
|
|
|
- if (regexec(&okexp, reply, 0, 0, 0)==0) {
|
|
|
- if (verbose)
|
|
|
- printf (" OK\n");
|
|
|
-#ifdef DEBUG
|
|
|
- printf("\n%s\n", reply);
|
|
|
-#endif
|
|
|
- strcpy(buff, message);
|
|
|
- usrlocstep=1;
|
|
|
- }
|
|
|
- else {
|
|
|
- if (verbose)
|
|
|
- printf("received:\n%s\n", reply);
|
|
|
- printf("error: didn't received '200 OK' "
|
|
|
- "on regsiter. aborting\n");
|
|
|
- exit(1);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- /* now we sended the message and look if its
|
|
|
- forwarded to us*/
|
|
|
- if (!strncmp(reply, messusern,
|
|
|
- strlen(messusern))) {
|
|
|
- if (verbose) {
|
|
|
- crlf=strstr(reply, "\r\n\r\n");
|
|
|
- crlf=crlf+4;
|
|
|
- printf(" received message\n "
|
|
|
- "'%s'\n", crlf);
|
|
|
- }
|
|
|
-#ifdef DEBUG
|
|
|
- printf("\n%s\n", reply);
|
|
|
-#endif
|
|
|
- cpy_vias(reply);
|
|
|
- strcpy(buff, mes_reply);
|
|
|
- usrlocstep=2;
|
|
|
- }
|
|
|
- else {
|
|
|
- if (verbose)
|
|
|
- printf("\nreceived:\n%s\n", reply);
|
|
|
- printf("error: didn't received the "
|
|
|
- "'MESSAGE' we sended. aborting\n");
|
|
|
- exit(1);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- /* finnaly we sended our reply on the message
|
|
|
- and look if this is also forwarded to us*/
|
|
|
- if (regexec(&okexp, reply, 0, 0, 0)==0) {
|
|
|
- if (verbose)
|
|
|
- printf(" reply received\n\n");
|
|
|
- else
|
|
|
- printf("USRLOC for %s%i completed "
|
|
|
- "successful\n", username, namebeg);
|
|
|
- if (namebeg==nameend) {
|
|
|
- printf("All USRLOC tests completed "
|
|
|
- "successful.\n");
|
|
|
- exit(0);
|
|
|
- }
|
|
|
- namebeg++;
|
|
|
- create_msg(buff, REQ_REG);
|
|
|
- usrlocstep=0;
|
|
|
- }
|
|
|
- else {
|
|
|
- if (verbose)
|
|
|
- printf("\nreceived:\n%s\n", reply);
|
|
|
- printf("error: didn't received the '200 "
|
|
|
- "OK' that we sended as the reply on "
|
|
|
- "the message\n");
|
|
|
- exit(1);
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (randtrash) {
|
|
|
- /* in randomzing trash we are expexting 4?? error codes
|
|
|
- everything else should not be normal */
|
|
|
- if (regexec(&errexp, reply, 0, 0, 0)==0) {
|
|
|
-#ifdef DEBUG
|
|
|
- printf("received:\n%s\n", reply);
|
|
|
-#endif
|
|
|
- if (verbose) printf("received expected 4xx ");
|
|
|
- if (warning_ext) {
|
|
|
- printf ("from ");
|
|
|
- warning_extract(reply);
|
|
|
- printf("\n");
|
|
|
- }
|
|
|
- else printf("\n");
|
|
|
- }
|
|
|
- else {
|
|
|
- printf("warning: did not received 4xx\n");
|
|
|
- if (verbose)
|
|
|
- printf("sended:\n%s\nreceived:\n%s\n", buff,
|
|
|
- reply);
|
|
|
- }
|
|
|
- if (nameend==(i+1)) {
|
|
|
- if (randretrys == 0) {
|
|
|
- printf("random end reached. server survived "
|
|
|
- ":) respect!\n");
|
|
|
- }
|
|
|
- else {
|
|
|
- printf("maximum sendings reached but did not "
|
|
|
- "get a response on this request:\n%s\n",
|
|
|
- buff);
|
|
|
- }
|
|
|
- exit(0);
|
|
|
- }
|
|
|
- else trash_random(buff);
|
|
|
- }
|
|
|
- else {
|
|
|
- /* in the normal send and reply case anything other
|
|
|
- then 1xx will be treated as final response*/
|
|
|
- printf("** reply received ");
|
|
|
- if (i==0)
|
|
|
- printf("after %.3f ms **\n",
|
|
|
- deltaT(&sendtime, &recvtime));
|
|
|
- else
|
|
|
- printf("%.3f ms after first send\n and %.3f ms "
|
|
|
- "after last send **\n",
|
|
|
- deltaT(&firstsendt, &recvtime),
|
|
|
- deltaT(&sendtime, &recvtime));
|
|
|
- if (verbose) printf("%s\n", reply);
|
|
|
- else {
|
|
|
- crlf=strchr(reply, '\n');
|
|
|
- *crlf='\0';
|
|
|
- printf(" %s\n", reply);
|
|
|
- }
|
|
|
- if (regexec(&proexp, reply, 0, 0, 0)==0) {
|
|
|
- printf(" provisional received; still waiting "
|
|
|
- "for a final response\n ");
|
|
|
- continue;
|
|
|
- } else {
|
|
|
- printf(" final received\n ");
|
|
|
- exit(0);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- } /* ret > 0 */
|
|
|
- else {
|
|
|
- perror("recv error");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- } /* !flood */
|
|
|
- else {
|
|
|
- if (namebeg==nretries) {
|
|
|
- printf("flood end reached\n");
|
|
|
- exit(0);
|
|
|
- }
|
|
|
- namebeg++;
|
|
|
- create_msg(buff, REQ_FLOOD);
|
|
|
- }
|
|
|
- } /* for nretries */
|
|
|
-
|
|
|
- } /* while redirected */
|
|
|
- if (randtrash) exit(0);
|
|
|
- printf("** I give up retransmission....\n");
|
|
|
- exit(1);
|
|
|
-}
|
|
|
-
|
|
|
-/* prints out some usage help and exits */
|
|
|
-void print_help() {
|
|
|
- printf("sipsak %s ", SIPSAK_VERSION);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("(compiled with DEBUG) ");
|
|
|
-#endif
|
|
|
- printf("\n\n"
|
|
|
- " shoot : sipsak [-f filename] -s sip:uri\n"
|
|
|
- " trace : sipsak -T -s sip:uri\n"
|
|
|
- " USRLOC: sipsak -U [-b number] -e number [-x number] -s sip:uri\n"
|
|
|
- " flood : sipsak -F [-c number] -s sip:uri\n"
|
|
|
- " random: sipsak -R [-t number] -s sip:uri\n\n"
|
|
|
- " additional parameter in every mode:\n"
|
|
|
- " [-d] [-i] [-l port] [-m number] [-n] [-r port] [-v] "
|
|
|
- "[-V] [-w]\n"
|
|
|
- " -h displays this help message\n"
|
|
|
- " -V prints version string only\n"
|
|
|
- " -f filename the file which contains the SIP message to send\n"
|
|
|
- " -s sip:uri the destination server uri in form "
|
|
|
- "sip:[user@]servername[:port]\n"
|
|
|
- " -T activates the traceroute mode\n"
|
|
|
- " -U activates the USRLOC mode\n"
|
|
|
- " -b number the starting number appendix to the user name in "
|
|
|
- "USRLOC mode\n"
|
|
|
- " (default: 0)\n"
|
|
|
- " -e number the ending numer of the appendix to the user name in "
|
|
|
- "USRLOC\n"
|
|
|
- " mode\n"
|
|
|
- " -x number the expires header field value (default: 15)\n"
|
|
|
- " -F activates the flood mode\n"
|
|
|
- " -c number the maximum CSeq number for flood mode "
|
|
|
- "(default: 2^31)\n"
|
|
|
- " -R activates the random modues (dangerous)\n"
|
|
|
- " -t number the maximum number of trashed character in random "
|
|
|
- "mode\n"
|
|
|
- " (default: request length)\n"
|
|
|
- " -l port the local port to use (default: any)\n"
|
|
|
- " -r port the remote port to use (default: 5060)\n"
|
|
|
- " -m number the value for the max-forwards header field\n"
|
|
|
- " -n use IPs instead of fqdn in the Via-Line\n"
|
|
|
- " -i deactivate the insertion of a Via-Line\n"
|
|
|
- " -d ignore redirects\n"
|
|
|
- " -v be more verbose\n"
|
|
|
- " -w extract IP from the warning in reply\n\n"
|
|
|
- "The manupulation function are only tested with nice RFC conform "
|
|
|
- "SIP-messages,\n"
|
|
|
- "so don't expect them to work with ugly or malformed messages.\n");
|
|
|
- exit(0);
|
|
|
-};
|
|
|
-
|
|
|
-int main(int argc, char *argv[])
|
|
|
-{
|
|
|
- FILE *pf;
|
|
|
- char buff[BUFSIZE];
|
|
|
- int length, c;
|
|
|
- char *delim, *delim2;
|
|
|
-
|
|
|
- /* some initialisation to be shure */
|
|
|
- file_b=uri_b=trace=lport=usrloc=flood=verbose=randtrash=trashchar = 0;
|
|
|
- numeric=warning_ext = 0;
|
|
|
- namebeg=nameend=maxforw = -1;
|
|
|
- via_ins=redirects = 1;
|
|
|
- username = NULL;
|
|
|
- address = 0;
|
|
|
- rport = 5060;
|
|
|
- expires_t = USRLOC_EXP_DEF;
|
|
|
- memset(buff, 0, BUFSIZE);
|
|
|
- memset(message, 0, BUFSIZE);
|
|
|
- memset(mes_reply, 0, BUFSIZE);
|
|
|
- memset(fqdn, 0, FQDN_SIZE);
|
|
|
- memset(messusern, 0, FQDN_SIZE);
|
|
|
-
|
|
|
- if (argc==1) print_help();
|
|
|
-
|
|
|
- /* lots of command line switches to handle*/
|
|
|
- while ((c=getopt(argc,argv,"b:c:de:f:Fhil:m:nr:Rs:t:TUvVwx:")) != EOF){
|
|
|
- switch(c){
|
|
|
- case 'b':
|
|
|
- if ((namebeg=atoi(optarg))==-1) {
|
|
|
- printf("error: non-numerical appendix begin for the "
|
|
|
- "username\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'c':
|
|
|
- if ((namebeg=atoi(optarg))==-1) {
|
|
|
- printf("error: non-numerical CSeq maximum\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'd':
|
|
|
- redirects=0;
|
|
|
- break;
|
|
|
- case 'e':
|
|
|
- if ((nameend=atoi(optarg))==-1) {
|
|
|
- printf("error: non-numerical appendix end for the "
|
|
|
- "username\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'F':
|
|
|
- flood=1;
|
|
|
- break;
|
|
|
- case 'f':
|
|
|
- /* file is opened in binary mode so that the cr-lf is
|
|
|
- preserved */
|
|
|
- pf = fopen(optarg, "rb");
|
|
|
- if (!pf){
|
|
|
- puts("unable to open the file.\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- length = fread(buff, 1, sizeof(buff), pf);
|
|
|
- if (length >= sizeof(buff)){
|
|
|
- printf("error:the file is too big. try files of less "
|
|
|
- "than %i bytes.\n", BUFSIZE);
|
|
|
- printf(" or recompile the program with bigger "
|
|
|
- "BUFSIZE defined.\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- fclose(pf);
|
|
|
- buff[length] = '\0';
|
|
|
- file_b=1;
|
|
|
- break;
|
|
|
- case 'h':
|
|
|
- print_help();
|
|
|
- break;
|
|
|
- case 'i':
|
|
|
- via_ins=0;
|
|
|
- break;
|
|
|
- case 'l':
|
|
|
- lport=atoi(optarg);
|
|
|
- if (!lport) {
|
|
|
- puts("error: non-numerical local port number");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'm':
|
|
|
- maxforw=atoi(optarg);
|
|
|
- if (maxforw==-1) {
|
|
|
- printf("error: non-numerical number of max-forwards\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'n':
|
|
|
- numeric = 1;
|
|
|
- break;
|
|
|
- case 'r':
|
|
|
- rport=atoi(optarg);
|
|
|
- if (!rport) {
|
|
|
- printf("error: non-numerical remote port number\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'R':
|
|
|
- randtrash=1;
|
|
|
- break;
|
|
|
- case 's':
|
|
|
- /* we try to extract as much informationas we can from the uri*/
|
|
|
- if (!strncmp(optarg,"sip",3)){
|
|
|
- if ((delim=strchr(optarg,':'))!=NULL){
|
|
|
- delim++;
|
|
|
- if ((delim2=strchr(delim,'@'))!=NULL){
|
|
|
- username=malloc(delim2-delim+1);
|
|
|
- strncpy(username, delim, delim2-delim);
|
|
|
- delim2++;
|
|
|
- delim=delim2;
|
|
|
- }
|
|
|
- if ((delim2=strchr(delim,':'))!=NULL){
|
|
|
- *delim2 = '\0';
|
|
|
- delim2++;
|
|
|
- rport = atoi(delim2);
|
|
|
- if (!rport) {
|
|
|
- printf("error: non-numerical remote port "
|
|
|
- "number\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- }
|
|
|
- domainname=malloc(strlen(delim)+1);
|
|
|
- strncpy(domainname, delim, strlen(delim));
|
|
|
- address = getaddress(delim);
|
|
|
- if (!address){
|
|
|
- printf("error:unable to determine the remote host "
|
|
|
- "address\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- }
|
|
|
- else{
|
|
|
- printf("error: sip:uri doesn't contain a : ?!\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- }
|
|
|
- else{
|
|
|
- printf("error: sip:uri doesn't not begin with sip\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- uri_b=1;
|
|
|
- break; break;
|
|
|
- case 't':
|
|
|
- trashchar=atoi(optarg);
|
|
|
- if (!trashchar) {
|
|
|
- printf("error: non-numerical number of trashed "
|
|
|
- "character\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'T':
|
|
|
- trace=1;
|
|
|
- break;
|
|
|
- case 'U':
|
|
|
- usrloc=1;
|
|
|
- break;
|
|
|
- case 'v':
|
|
|
- verbose=1;
|
|
|
- break;
|
|
|
- case 'V':
|
|
|
- printf("sipsak %s ", SIPSAK_VERSION);
|
|
|
-#ifdef DEBUG
|
|
|
- printf("(compiled with DEBUG)");
|
|
|
-#endif
|
|
|
- printf("\n");
|
|
|
- exit(0);
|
|
|
- break;
|
|
|
- case 'w':
|
|
|
- warning_ext=1;
|
|
|
- break;
|
|
|
- case 'x':
|
|
|
- expires_t=atoi(optarg);
|
|
|
- break;
|
|
|
- default:
|
|
|
- printf("error: unknown parameter %c\n", c);
|
|
|
- exit(2);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* lots of conditions to check */
|
|
|
- if (trace) {
|
|
|
- if (usrloc || flood || randtrash) {
|
|
|
- printf("error: trace can't be combined with usrloc, random or "
|
|
|
- "flood\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (!uri_b) {
|
|
|
- printf("error: for trace mode a sip:uri is realy needed\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (file_b) {
|
|
|
- printf("warning: file will be ignored for tracing.");
|
|
|
- }
|
|
|
- if (!username) {
|
|
|
- printf("error: for trace mode without a file the sip:uir have to "
|
|
|
- "contain a username\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (!via_ins){
|
|
|
- printf("warning: Via-Line is needed for tracing. Ignoring -i\n");
|
|
|
- via_ins=1;
|
|
|
- }
|
|
|
- if (!warning_ext) {
|
|
|
- printf("warning: IP extract from warning activated to be more "
|
|
|
- "informational\n");
|
|
|
- warning_ext=1;
|
|
|
- }
|
|
|
- if (maxforw==-1) maxforw=255;
|
|
|
- }
|
|
|
- else if (usrloc) {
|
|
|
- if (trace || flood || randtrash) {
|
|
|
- printf("error: usrloc can't be combined with trace, random or "
|
|
|
- "flood\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (!username || !uri_b || nameend==-1) {
|
|
|
- printf("error: for the USRLOC mode you have to give a sip:uri with "
|
|
|
- "a username and the\n username appendix end at least\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (via_ins) {
|
|
|
- via_ins=0;
|
|
|
- }
|
|
|
- if (redirects) {
|
|
|
- printf("warning: redirects are not expected in USRLOC. "
|
|
|
- "disableing\n");
|
|
|
- redirects=0;
|
|
|
- }
|
|
|
- if (namebeg==-1)
|
|
|
- namebeg=0;
|
|
|
- }
|
|
|
- else if (flood) {
|
|
|
- if (trace || usrloc || randtrash) {
|
|
|
- printf("error: flood can't be combined with trace, random or "
|
|
|
- "usrloc\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (!uri_b) {
|
|
|
- printf("error: we need at least a sip uri for flood\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (redirects) {
|
|
|
- printf("warning: redirects are not expected in flood. "
|
|
|
- "disableing\n");
|
|
|
- redirects=0;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (randtrash) {
|
|
|
- if (trace || usrloc || flood) {
|
|
|
- printf("error: random can't be combined with trace, flood or "
|
|
|
- "usrloc\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (!uri_b) {
|
|
|
- printf("error: need at least a sip uri for random\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (redirects) {
|
|
|
- printf("warning: redirects are not expected in random. "
|
|
|
- "disableing\n");
|
|
|
- redirects=0;
|
|
|
- }
|
|
|
- if (verbose) {
|
|
|
- printf("warning: random characters may destroy your terminal "
|
|
|
- "output\n");
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- if (!uri_b) {
|
|
|
- printf("error: a spi uri is needed at least\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
- if (!(username || file_b)) {
|
|
|
- printf("error: ether a file or an username in the sip uri is "
|
|
|
- "required\n");
|
|
|
- exit(2);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- /* determine our hostname */
|
|
|
- get_fqdn();
|
|
|
-
|
|
|
- /* this is not a cryptographic random number generator,
|
|
|
- but hey this is only a test-tool => should be satisfying*/
|
|
|
- srand(time(0));
|
|
|
-
|
|
|
- /* here we go...*/
|
|
|
- shoot(buff);
|
|
|
-
|
|
|
- /* normaly we won't come back here, but to satisfy the compiler */
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|