protoshoot.c

00001 /* $Id$ */
00002 /*
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License 
00024  * along with this program; if not, write to the Free Software 
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  */
00027 /*
00028  * History:
00029  *  2005-09-09  basic tcp support added (andrei)
00030  */
00031 
00032 
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include <string.h>
00038 #include <ctype.h>
00039 #include <netdb.h>
00040 #include <unistd.h>
00041 #include <sys/types.h>
00042 #include <fcntl.h>
00043 #include <sys/socket.h>
00044 #include <netinet/in.h>
00045 #include <netinet/tcp.h>
00046 #ifdef USE_SCTP
00047 #include <netinet/sctp.h>
00048 #endif /* USE_SCTP */
00049 #include <arpa/inet.h>
00050 #include <signal.h>
00051 
00052 
00053 static char *id="$Id$";
00054 static char *version="protoflood 0.3";
00055 static char* help_msg="\
00056 Usage: udp_flood -f file -d address -p port -c count [-v]\n\
00057 Options:\n\
00058     -f file       file with the content of the udp packet (max 65k)\n\
00059     -d address    destination address\n\
00060     -p port       destination port\n\
00061     -c count      number of packets to be sent\n\
00062     -s usec       microseconds to sleep before sending \"throttle\" packets\n\
00063     -t throttle   number of packets to send before sleeping\n\
00064     -r            sleep randomly up to -s usec packets (see -s) \n\
00065     -T            use tcp instead of udp \n\
00066     -S            use sctp instead of udp \n\
00067     -1            use sctp in one to one mode \n\
00068     -n no         tcp connection number \n\
00069     -R            close the tcp connections with RST (SO_LINGER) \n\
00070     -v            increase verbosity level\n\
00071     -V            version number\n\
00072     -h            this help message\n\
00073 ";
00074 
00075 #define BUF_SIZE 65535
00076 
00077 
00078 enum protos { PROTO_NONE, PROTO_UDP, PROTO_TCP, PROTO_SCTP };
00079 
00080 int main (int argc, char** argv)
00081 {
00082         int fd;
00083         int sock;
00084         char c;
00085         int n,r;
00086         char* tmp;
00087         char buf[BUF_SIZE];
00088         struct hostent* he;
00089         struct sockaddr_in addr;
00090         
00091         int count;
00092         int verbose;
00093         char *fname;
00094         char *dst;
00095         int port;
00096         unsigned long usec;
00097         int throttle;
00098         int random_sleep;
00099         enum protos proto;
00100         int sctp_o2o;
00101         int tcp_rst;
00102         int con_no;
00103         int t;
00104         struct linger t_linger;
00105         int k;
00106         int err;
00107         
00108         /* init */
00109         count=1;
00110         verbose=0;
00111         fname=0;
00112         dst="127.0.0.1";
00113         port=5060;
00114         usec=0;
00115         throttle=0;
00116         random_sleep=0;
00117         proto=PROTO_UDP;
00118         tcp_rst=0;
00119         con_no=1;
00120         sctp_o2o=0;
00121         err=0;
00122 
00123         opterr=0;
00124         while ((c=getopt(argc,argv, "f:c:d:p:s:t:n:rTS1RvhV"))!=-1){
00125                 switch(c){
00126                         case 'f':
00127                                 fname=optarg;
00128                                 break;
00129                         case 'v':
00130                                 verbose++;
00131                                 break;
00132                         case 'd':
00133                                 dst=optarg;
00134                                 break;
00135                         case 'p':
00136                                 port=strtol(optarg, &tmp, 10);
00137                                 if ((tmp==0)||(*tmp)){
00138                                         fprintf(stderr, "bad port number: -p %s\n", optarg);
00139                                         goto error;
00140                                 }
00141                                 break;
00142                         case 'c':
00143                                 count=strtol(optarg, &tmp, 10);
00144                                 if ((tmp==0)||(*tmp)){
00145                                         fprintf(stderr, "bad count: -c %s\n", optarg);
00146                                         goto error;
00147                                 }
00148                                 break;
00149                         case 's':
00150                                 usec=strtol(optarg, &tmp, 10);
00151                                 if ((tmp==0)||(*tmp)){
00152                                         fprintf(stderr, "bad count: -c %s\n", optarg);
00153                                         goto error;
00154                                 }
00155                                 break;
00156                         case 't':
00157                                 throttle=strtol(optarg, &tmp, 10);
00158                                 if ((tmp==0)||(*tmp)){
00159                                         fprintf(stderr, "bad count: -c %s\n", optarg);
00160                                         goto error;
00161                                 }
00162                                 break;
00163                         case 'n':
00164                                 con_no=strtol(optarg, &tmp, 10);
00165                                 if ((tmp==0)||(*tmp)||(con_no<1)){
00166                                         fprintf(stderr, "bad count: -c %s\n", optarg);
00167                                         goto error;
00168                                 }
00169                                 break;
00170                         case 'r':
00171                                 random_sleep=1;
00172                                 break;
00173                         case 'T':
00174                                 proto=PROTO_TCP;
00175                                 break;
00176                         case 'S':
00177 #ifdef USE_SCTP
00178                                 proto=PROTO_SCTP;
00179 #else
00180                                 fprintf(stderr, "sctp not supported (recompile with "
00181                                                                 "-DUSE_SCTP)\n");
00182                                 goto error;
00183 #endif /* USE_SCTP */
00184                                 break;
00185                         case '1':
00186                                 sctp_o2o=1;
00187                                 break;
00188                         case 'R':
00189                                 tcp_rst=1;
00190                                 break;
00191                         case 'V':
00192                                 printf("version: %s\n", version);
00193                                 printf("%s\n",id);
00194                                 exit(0);
00195                                 break;
00196                         case 'h':
00197                                 printf("version: %s\n", version);
00198                                 printf("%s", help_msg);
00199                                 exit(0);
00200                                 break;
00201                         case '?':
00202                                 if (isprint(optopt))
00203                                         fprintf(stderr, "Unknown option `-%c´\n", optopt);
00204                                 else
00205                                         fprintf(stderr, "Unknown character `\\x%x´\n", optopt);
00206                                 goto error;
00207                         case ':':
00208                                 fprintf(stderr, "Option `-%c´ requires an argument.\n",
00209                                                 optopt);
00210                                 goto error;
00211                                 break;
00212                         default:
00213                                         abort();
00214                 }
00215         }
00216         
00217         /* check if all the required params are present */
00218         if (fname==0){
00219                 fprintf(stderr, "Missing -f file\n");
00220                 exit(-1);
00221         }
00222         if (dst==0){
00223                 fprintf(stderr, "Missing destination (-d ...)\n");
00224                 exit(-1);
00225         }
00226         if(port==0){
00227                 fprintf(stderr, "Missing port number (-p port)\n");
00228                 exit(-1);
00229         }else if(port<0){
00230                 fprintf(stderr, "Invalid port number (-p %d)\n", port);
00231                 exit(-1);
00232         }
00233         if(count==0){
00234                 fprintf(stderr, "Missing packet count (-c number)\n");
00235                 exit(-1);
00236         }else if(count<0){
00237                 fprintf(stderr, "Invalid packet count (-c %d)\n", count);
00238                 exit(-1);
00239         }
00240         if (proto==PROTO_UDP || (proto==PROTO_SCTP && !sctp_o2o)) con_no=1;
00241         
00242         /* ignore sigpipe */
00243         if (signal(SIGPIPE, SIG_IGN)==SIG_ERR){
00244                 fprintf(stderr, "failed to ignore SIGPIPE: %s\n", strerror(errno));
00245                 exit(-1);
00246         }
00247         
00248         /* open packet file */
00249         fd=open(fname, O_RDONLY);
00250         if (fd<0){
00251                 fprintf(stderr, "ERROR: loading packet-file(%s): %s\n", fname,
00252                                 strerror(errno));
00253                 goto error;
00254         }
00255         n=read(fd, buf, BUF_SIZE);
00256         if (n<0){
00257                 fprintf(stderr, "ERROR: reading file(%s): %s\n", fname,
00258                                 strerror(errno));
00259                 goto error;
00260         }
00261         if (verbose) printf("read %d bytes from file %s\n", n, fname);
00262         close(fd);
00263 
00264         /* resolve destination */
00265         he=gethostbyname(dst);
00266         if (he==0){
00267                 fprintf(stderr, "ERROR: could not resolve %s\n", dst);
00268                 goto error;
00269         }
00270         /* open socket*/
00271         addr.sin_family=he->h_addrtype;
00272         addr.sin_port=htons(port);
00273 #ifdef HAVE_SOCKADDR_SA_LEN
00274         addr.sin_len=sizeof(struct sockaddr_in);
00275 #endif
00276         memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
00277         
00278         for (k=0; k<con_no; k++){
00279                 switch(proto){
00280                         case PROTO_UDP:
00281                                 sock = socket(he->h_addrtype, SOCK_DGRAM, 0);
00282                                 break;
00283                         case PROTO_TCP:
00284                                 sock = socket(he->h_addrtype, SOCK_STREAM, 0);
00285                                 break;
00286 #ifdef USE_SCTP
00287                         case PROTO_SCTP:
00288                                 sock = socket(he->h_addrtype, 
00289                                                                 sctp_o2o?SOCK_STREAM:SOCK_SEQPACKET,
00290                                                                 IPPROTO_SCTP);
00291                                 break;
00292 #endif /* USE_SCTP */
00293                         default:
00294                                 fprintf(stderr, "BUG: unkown proto %d\n", proto);
00295                                 goto error;
00296                 }
00297                 if (sock==-1){
00298                         fprintf(stderr, "ERROR: socket: %s\n", strerror(errno));
00299                         goto error;
00300                 }
00301                 if (proto==PROTO_TCP){
00302                         t=1;
00303                         if (setsockopt(sock, IPPROTO_TCP , TCP_NODELAY, &t, sizeof(t))<0){
00304                                 fprintf(stderr, "ERROR: could not disable Nagle: %s\n",
00305                                                                 strerror(errno));
00306                         }
00307                         if (tcp_rst){
00308                                 t_linger.l_onoff=1;
00309                                 t_linger.l_linger=0;
00310                                 if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &t_linger,
00311                                                                         sizeof(t_linger))<0){
00312                                         fprintf(stderr, "ERROR: could not set SO_LINGER: %s\n",
00313                                                                         strerror(errno));
00314                                 }
00315                         }
00316                 }
00317 #ifdef USE_SCTP
00318                 else if (proto==PROTO_SCTP){
00319                         t=1;
00320                         if (setsockopt(sock, IPPROTO_SCTP, SCTP_NODELAY, &t, sizeof(t))<0){
00321                                 fprintf(stderr, "ERROR: could not disable Nagle: %s\n",
00322                                                                 strerror(errno));
00323                         }
00324                 }
00325 #endif /* USE_SCTP */
00326 
00327                 if (
00328 #ifdef USE_SCTP
00329                         (proto!=PROTO_SCTP || sctp_o2o) &&
00330 #endif /* USE_SCTP */
00331                         (connect(sock, (struct sockaddr*) &addr,
00332                                         sizeof(struct sockaddr))!=0)){
00333                         fprintf(stderr, "ERROR: connect: %s\n", strerror(errno));
00334                         goto error;
00335                 }
00336                 
00337                 
00338                 /* flood loop */
00339                 t=throttle;
00340                 for (r=0; r<count; r++){
00341                         if ((verbose>1)&&((r%1000)==999)){  putchar('.'); fflush(stdout); }
00342 #ifdef USE_SCTP
00343                         if (proto==PROTO_SCTP && !sctp_o2o){
00344                                 if (sctp_sendmsg(sock, buf, n,  (struct sockaddr*) &addr,
00345                                                                         sizeof(struct sockaddr), 0, SCTP_UNORDERED,
00346                                                                         0, 0, 0)==-1){
00347                                         fprintf(stderr, "Error(%d): send: %s\n", err,
00348                                                         strerror(errno));
00349                                         err++;;
00350                                 }
00351                         }else
00352 #endif /* USE_SCTP */
00353                         {
00354                                 if (send(sock, buf, n, 0)==-1) {
00355                                         fprintf(stderr, "Error(%d): send: %s\n", err,
00356                                                         strerror(errno));
00357                                         err++;;
00358                                 }
00359                         }
00360                         if (usec){
00361                                 t--;
00362                                 if (t==0){
00363                                         usleep(random_sleep?
00364                                                                 (unsigned long)((double)usec*rand()/RAND_MAX):usec);
00365                                         t=throttle;
00366                                 }
00367                         }
00368                 }
00369                 
00370                 close(sock);
00371                 if ((verbose) && (k%1000==999)) { putchar('#'); fflush(stdout); }
00372         }
00373         if (proto==PROTO_TCP || proto==PROTO_SCTP){
00374                 printf("\n%d packets sent on %d %s connections (%d on each of them),"
00375                                 " %d bytes each => total %d bytes\n",
00376                                 count*con_no-err, con_no, (proto==PROTO_TCP)?"tcp":"sctp",
00377                                 count, n,
00378                                 (con_no*count-err)*n);
00379         }else{
00380                 printf("\n%d packets sent, %d bytes each => total %d bytes\n",
00381                                 count-err, n, n*(count-err));
00382         }
00383         if (err) printf("%d errors\n", err);
00384         exit(0);
00385 
00386 error:
00387         fprintf(stderr, "exiting due to error (%s)\n", strerror(errno));
00388         exit(-1);
00389 }