]> sjero.net Git - dccpping/blob - dccpping.c
Use a DCCP socket to reserve a source port, determine correct source address, and...
[dccpping] / dccpping.c
1 /******************************************************************************
2 Utility to ping hosts using DCCP REQ packets to test for DCCP connectivity.
3
4 Copyright (C) 2012  Samuel Jero <sj323707@ohio.edu>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 Author: Samuel Jero <sj323707@ohio.edu>
20 Date: 11/2012
21 ******************************************************************************/
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <signal.h>
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/socket.h>
34 #include <sys/select.h>
35 #include <netinet/ip.h>
36 #include <netinet/ip6.h>
37 #include <netinet/in.h>
38 #include <netinet/ip_icmp.h>
39 #include <netinet/icmp6.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42 #include <net/if.h>
43 #include <ifaddrs.h>
44 #include <linux/dccp.h>
45 #include "checksums.h"
46
47
48 /*Use the DCCP source port to multiplex DCCP Ping streams by PID*/
49 #define DCCP_SERVICE_CODE 0x50455246
50 #define DEFAULT_PORT 33434
51
52 #define DCCPPING_VERSION 1.0
53 #define MAX(x,y) (x>y ? x : y)
54 extern int errno;
55
56
57 /*Structure for simpler IPv4/IPv6 Address handling*/
58 typedef union ipaddr{
59         struct sockaddr *gen;
60         struct sockaddr_in *ipv4;
61         struct sockaddr_in6 *ipv6;
62 } ipaddr_ptr_t;
63
64 /*Possible Responses to a Request*/
65 enum responses{
66         UNKNOWN=0,
67         RESET,
68         RESPONSE,
69         SYNC,
70         DEST_UNREACHABLE,
71         TTL_EXPIRATION,
72         TOO_BIG,
73         PARAMETER_PROBLEM,
74         DCCP_ERROR
75 };
76
77 /*Output strings corresponding to enum responses*/
78 static const char* response_label[]= {
79 "Unknown",
80 "Closed Port (Reset)",
81 "Open Port (Response)",
82 "Open Port (Sync)",
83 "Destination Unreachable",
84 "TTL Expiration",
85 "Packet Too Big",
86 "DCCP Not Supported (Parameter Problem)",
87 "Protocol Error (DCCP Reset)"
88 };
89
90 /*Structure to keep track of information about a request*/
91 struct request{
92         int                             request_seq;
93         int                             packet_seq;
94         int                             num_replies;
95         int                             num_errors;
96         struct timeval  sent;
97         struct timeval  reply;
98         enum responses  reply_type;
99         struct request  *next;
100         struct request  *prev;
101 };
102
103 /*Request Queue head structure*/
104 struct request_queue{
105         struct request *head;
106         struct request *tail;
107 };
108
109 /*Statistics about the requests and replies sent*/
110 struct stats{
111         int                             requests_sent;
112         int                             replies_received;
113         int                             errors;
114         double                  rtt_min;
115         double                  rtt_avg;
116         double                  rtt_max;
117         struct timeval  start;
118         struct timeval  stop;
119 };
120
121 struct params{
122         int count;                              /*Number of pings (-1 is infinity)*/
123         int dest_port;                  /*Destination port*/
124         int src_port;                   /*Source port---used to encode pid*/
125         int ttl;                                /*TTL*/
126         long interval;                  /*Delay between pings in ms*/
127         int ip_type;                    /*IPv4 or IPv6*/
128         ipaddr_ptr_t dest_addr; /*Destination Address*/
129         ipaddr_ptr_t src_addr;  /*Source Address*/
130         int dccp_socket;                /*DCCP Socket used to grab src addr/port*/
131 };
132
133
134 int                                     debug=0;                /*set to 1 to turn on debugging information*/
135 struct request_queue    queue;                  /*Queue of requests to track RTT/duplicate information*/
136 struct stats                    ping_stats;             /*Ping Statistics*/
137 struct params                   parms;                  /*Parameters for ping*/
138
139
140 void getAddresses(char *src, char* dst);
141 void doping();
142 void handleDCCPpacket(int rcv_socket, int send_socket);
143 void handleICMP4packet(int rcv_socket);
144 void handleICMP6packet(int rcv_socket);
145 void buildRequestPacket(unsigned char* buffer, int *len, int seq);
146 void updateRequestPacket(unsigned char* buffer, int *len, int seq);
147 int logPacket(int req_seq, int packet_seq);
148 int logResponse(ipaddr_ptr_t *src, int seq, int type);
149 void clearQueue();
150 void sigHandler();
151 void usage();
152 void version();
153 void sanitize_environment();
154 void dbgprintf(int level, const char *fmt, ...);
155
156
157 /*Parse commandline options*/
158 int main(int argc, char *argv[])
159 {
160         char c;
161         char *src=NULL;
162         char *dst=NULL;
163
164         /*Set Defaults*/
165         queue.head=NULL;
166         queue.tail=NULL;
167         ping_stats.replies_received=0;
168         ping_stats.requests_sent=0;
169         ping_stats.rtt_avg=0;
170         ping_stats.rtt_max=0;
171         ping_stats.rtt_min=0;
172         ping_stats.errors=0;
173         parms.count=-1;
174         parms.dest_port=DEFAULT_PORT;
175         parms.ttl=64;
176         parms. interval=1000;
177         parms.ip_type=AF_UNSPEC;
178         parms.dest_addr.gen=NULL;
179         parms.src_addr.gen=NULL;
180         parms.dccp_socket=-1;
181
182         sanitize_environment();
183
184         while ((c = getopt(argc, argv, "64vhc:p:i:dt:S:")) != -1) {
185                 switch (c) {
186                         case '6':
187                                 parms.ip_type=AF_INET6;
188                                 break;
189                         case '4':
190                                 parms.ip_type=AF_INET;
191                                 break;
192                         case 'c':
193                                 parms.count = atoi(optarg);
194                                 if(parms.count<=0){
195                                         dbgprintf(0, "Error: count must be positive");
196                                         exit(1);
197                                 }
198                                 break;
199                         case 'p':
200                                 parms.dest_port = atoi(optarg);
201                                 break;
202                         case 'i':
203                                 parms.interval = (long)(atof(optarg) * 1000.0);
204                                 if (parms.interval <= 0) {
205                                         dbgprintf(0, "Error: Invalid interval\n");
206                                         exit(1);
207                                 }
208                                 break;
209                         case 'd':
210                                 debug++;
211                                 break;
212                         case 't':
213                                 parms.ttl = atoi(optarg);
214                                 if (parms.ttl < 1 || parms.ttl > 255) {
215                                         dbgprintf(0,"Error: Invalid TTL\n");
216                                 }
217                                 break;
218                         case 'S':
219                                 src=optarg;
220                                 break;
221                         case 'v':
222                                 version();
223                                 break;
224                         case 'h':
225                                 /*Intentional Fall-through*/
226                         default:
227                                 usage();
228                                 break;
229                 }
230         }
231
232         argc -= optind;
233         argv += optind;
234
235         if (argc != 1) {
236                 usage();
237         }
238         dst=argv[0];
239
240         getAddresses(src, dst);
241         if(parms.src_addr.gen==NULL || parms.dest_addr.gen==NULL){
242                 dbgprintf(0,"Error: Can't determine source or destination address\n");
243                 exit(1);
244         }
245
246         signal(SIGINT, sigHandler);
247         doping();
248
249         free(parms.src_addr.gen);
250         free(parms.dest_addr.gen);
251         close(parms.dccp_socket);
252         clearQueue();
253         return 0;
254 }
255
256 void getAddresses(char *src, char* dst){
257         struct addrinfo hint;
258         struct addrinfo *dtmp, *stmp;
259         struct ifaddrs *temp, *cur;
260         struct sockaddr_in6* iv61;
261         struct sockaddr_in6* iv62;
262         struct sockaddr_in* iv41;
263         struct sockaddr_in* iv42;
264         int addrlen;
265         int err;
266         char pbuf[1000];
267
268         /*Lookup destination Address*/
269         memset(&hint,0,sizeof(struct addrinfo));
270         hint.ai_family=parms.ip_type;
271         hint.ai_flags=AI_V4MAPPED | AI_ADDRCONFIG;
272
273         if((err=getaddrinfo(dst,NULL,&hint,&dtmp))!=0){
274                 dbgprintf(0,"Error: Couldn't lookup destination %s (%s)\n", dst, gai_strerror(err));
275                 exit(1);
276         }
277         if(dtmp==NULL){
278                 dbgprintf(0,"Error: Unknown Host %s\n", dst);
279                 exit(1);
280         }else{
281                 addrlen=dtmp->ai_addrlen;
282                 hint.ai_family=parms.ip_type=dtmp->ai_family;
283                 parms.dest_addr.gen=malloc(dtmp->ai_addrlen);
284                 if(parms.dest_addr.gen==NULL){
285                         dbgprintf(0,"Error: Can't allocate Memory\n");
286                         exit(1);
287                 }
288                 memcpy(parms.dest_addr.gen,dtmp->ai_addr,dtmp->ai_addrlen);
289         }
290         freeaddrinfo(dtmp);
291
292         /*Get a meaningful source address*/
293         if(src!=NULL){
294                 /*Use Commandline arg*/
295
296                 /*Convert arg to address*/
297                 if((err=getaddrinfo(src,NULL,&hint,&stmp))!=0){
298                         dbgprintf(0,"Error: Source Address %s is invalid (%s)\n", src, gai_strerror(err));
299                         exit(1);
300                 }
301                 if(stmp==NULL){
302                         dbgprintf(0,"Error: Unknown Host %s\n", dst);
303                         exit(1);
304                 }
305
306                 /*Compare to interface addresses*/
307                 getifaddrs(&temp);
308                 cur=temp;
309                 while(cur!=NULL){
310                         if(cur->ifa_addr==NULL || cur->ifa_addr->sa_family!=stmp->ai_family){
311                                 /*Not matching ipv4/ipv6 of dest*/
312                                 cur=cur->ifa_next;
313                                 continue;
314                         }
315                         if(stmp->ai_family==AF_INET){
316                                 iv41=(struct sockaddr_in*)stmp->ai_addr;
317                                 iv42=(struct sockaddr_in*)cur->ifa_addr;
318                                 if(memcmp(&iv41->sin_addr,&iv42->sin_addr, sizeof(iv41->sin_addr))==0){
319                                         parms.src_addr.gen=malloc(sizeof(struct sockaddr_storage));
320                                         if(parms.src_addr.gen==NULL){
321                                                 dbgprintf(0,"Error: Can't allocate Memory\n");
322                                                 exit(1);
323                                         }
324                                         parms.src_addr.gen->sa_family=parms.ip_type;
325                                         memcpy(parms.src_addr.gen,cur->ifa_addr,addrlen);
326                                         break;
327                                 }
328                         }else{
329                                 iv61=(struct sockaddr_in6*)stmp->ai_addr;
330                                 iv62=(struct sockaddr_in6*)cur->ifa_addr;
331                                 if(memcmp(&iv61->sin6_addr,&iv62->sin6_addr, sizeof(iv61->sin6_addr))==0){
332                                         parms.src_addr.gen=malloc(sizeof(struct sockaddr_storage));
333                                         if(parms.src_addr.gen==NULL){
334                                                 dbgprintf(0,"Error: Can't allocate Memory\n");
335                                                 exit(1);
336                                         }
337                                         parms.src_addr.gen->sa_family=parms.ip_type;
338                                         memcpy(parms.src_addr.gen,cur->ifa_addr,addrlen);
339                                         break;
340                                 }
341                         }
342                         cur=cur->ifa_next;
343                 }
344                 if(parms.src_addr.gen==NULL){
345                         if(parms.ip_type==AF_INET){
346                                 iv41=(struct sockaddr_in*)stmp->ai_addr;
347                                 dbgprintf(0,"Error: Source Address %s does not belong to any interface!\n",
348                                         inet_ntop(parms.ip_type, (void*)&iv41->sin_addr, pbuf, 1000));
349                         }else{
350                                 iv61=(struct sockaddr_in6*)stmp->ai_addr;
351                                 dbgprintf(0,"Error: Source Address %s does not belong to any interface!\n",
352                                         inet_ntop(parms.ip_type, (void*)&iv61->sin6_addr, pbuf, 1000));
353                         }
354                         exit(1);
355                 }
356                 freeifaddrs(temp);
357                 freeaddrinfo(stmp);
358         }
359
360         /*Create socket to auto respond for open connections and reserve a source port*/
361         parms.dccp_socket=socket(parms.ip_type,SOCK_DCCP, IPPROTO_DCCP);
362         if(parms.dccp_socket<0){
363                 dbgprintf(0, "Error: Failed opening DCCP Socket (%s)\n",strerror(errno));
364                 exit(1);
365         }
366         fcntl(parms.dccp_socket, F_SETFL, O_NONBLOCK);
367
368
369         if(parms.src_addr.gen==NULL){
370                 /*Auto-detect source address*/
371                 parms.src_addr.gen=malloc(sizeof(struct sockaddr_storage));
372                 if(parms.src_addr.gen==NULL){
373                         dbgprintf(0,"Error: Can't allocate Memory\n");
374                         exit(1);
375                 }
376                 memset(parms.src_addr.gen,0,sizeof(struct sockaddr_storage));
377                 parms.src_addr.gen->sa_family=parms.ip_type;
378         }else{
379                 /*Bind to the given source address*/
380                 if(bind(parms.dccp_socket,parms.src_addr.gen,sizeof(struct sockaddr_storage))<0){
381                         dbgprintf(0, "Error: Failed bind() on DCCP socket (%s)\n",strerror(errno));
382                         exit(1);
383                 }
384         }
385
386         /*Connect socket to get source address/port*/
387         if(parms.ip_type==AF_INET){
388                 parms.dest_addr.ipv4->sin_port=htons(parms.dest_port);
389         }else{
390                 parms.dest_addr.ipv6->sin6_port=htons(parms.dest_port);
391         }
392         if(connect(parms.dccp_socket,parms.dest_addr.gen,sizeof(struct sockaddr_storage))<0){
393                 if(errno!=EINPROGRESS){
394                         dbgprintf(0, "Error: Failed connect() on DCCP socket (%s)\n",strerror(errno));
395                         exit(1);
396                 }
397         }
398
399         /*Get source address and port number!*/
400         addrlen=sizeof(struct sockaddr_storage);
401         if(getsockname(parms.dccp_socket,parms.src_addr.gen,(socklen_t*)&addrlen)<0){
402                 dbgprintf(0, "Error: Failed getsockname() on DCCP socket (%s)\n",strerror(errno));
403                 exit(1);
404         }
405         if(parms.ip_type==AF_INET){
406                 parms.src_port=ntohs(parms.src_addr.ipv4->sin_port);
407                 parms.dest_addr.ipv4->sin_port=0;
408         }else{
409                 parms.src_port=ntohs(parms.src_addr.ipv6->sin6_port);
410                 parms.dest_addr.ipv6->sin6_port=0;
411         }
412         return;
413 }
414
415 /*Preform the ping functionality*/
416 void doping(){
417         int rs, is4,is6,ds;
418         int done=0;
419         int addrlen;
420         int slen=1500;
421         unsigned char sbuffer[slen];
422         fd_set sel;
423         struct timeval timeout;
424         struct timeval t,delay, add;
425         char pbuf[1000];
426         int request_seq=1;
427         int packet_seq;
428
429         /*Open Sockets*/
430         rs=socket(parms.ip_type, SOCK_RAW ,IPPROTO_RAW);
431         if(rs<0){
432                 dbgprintf(0, "Error opening raw socket\n");
433                 exit(1);
434         }
435         ds=socket(parms.ip_type, SOCK_RAW ,IPPROTO_DCCP);
436         if(ds<0){
437                 dbgprintf(0, "Error opening raw DCCP socket\n");
438                 exit(1);
439         }
440         is4=socket(parms.ip_type,SOCK_RAW,IPPROTO_ICMP);
441         if(is4<0){
442                 dbgprintf(0,"Error opening raw ICMPv4 socket\n");
443                 exit(1);
444         }
445         is6=socket(parms.ip_type,SOCK_RAW,IPPROTO_ICMPV6);
446         if(is6<0){
447                 dbgprintf(0,"Error opening raw ICMPv6 socket\n");
448                 exit(1);
449         }
450
451
452         /*Build DCCP packet*/
453         packet_seq=rand();
454         buildRequestPacket(sbuffer,&slen,packet_seq);
455         if(parms.ip_type==AF_INET){
456                 addrlen=sizeof(struct sockaddr_in);
457         }else{
458                 addrlen=sizeof(struct sockaddr_in6);
459         }
460
461         /*Start Message*/
462         if(parms.ip_type==AF_INET){
463                 printf("PINGING %s on DCCP port %i\n",
464                                 inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv4->sin_addr, pbuf, 1000),
465                                 parms.dest_port);
466         }else{
467                 printf("PINGING %s on DCCP port %i\n",
468                                 inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv6->sin6_addr, pbuf, 1000),
469                                 parms.dest_port);
470         }
471
472         while(!done){
473                 /*Send Ping*/
474                 if(sendto(rs, &sbuffer, slen, MSG_DONTWAIT,(struct sockaddr*)parms.dest_addr.gen,addrlen)<0){
475                         if(errno!=EINTR){
476                                 dbgprintf(0,"Error: sendto() failed (%s)\n",strerror(errno));
477                         }
478                 }
479                 if(parms.count==0){done=1; break;}
480
481                 if (logPacket(request_seq,packet_seq)<0){
482                         dbgprintf(0,"Error: Couldn't record request!\n");
483                 }
484                 if(parms.ip_type==AF_INET){
485                         dbgprintf(1, "Sending DCCP Request to %s\n",
486                                         inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv4->sin_addr, pbuf, 1000));
487                 }else{
488                         dbgprintf(1, "Sending DCCP Request to %s\n",
489                                         inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv6->sin6_addr, pbuf, 1000));
490                 }
491
492                 /*Use select to wait on packets or until interval has passed*/
493                 add.tv_sec=parms.interval/1000;
494                 add.tv_usec=(parms.interval%1000)*1000;
495                 gettimeofday(&t,NULL);
496                 timeradd(&t,&add,&delay);
497                 while(timercmp(&t,&delay,<)){
498                         /*Prepare for select*/
499                         FD_ZERO(&sel);
500                         FD_SET(ds,&sel);
501                         FD_SET(is4,&sel);
502                         FD_SET(is6,&sel);
503                         timersub(&delay,&t,&timeout);
504
505                         /*Do select call*/
506                         if(select(MAX(ds+1,MAX(is4+1,is6+1)),&sel, NULL,NULL,&timeout)<0){
507                                 if(errno!=EINTR){
508                                         dbgprintf(0,"Select() error (%s)\n",strerror(errno));
509                                 }
510                         }
511                         if(parms.count==0){done=1;break;}
512
513                         if(FD_ISSET(ds,&sel)){
514                                 /*Data on the DCCP socket*/
515                                 handleDCCPpacket(ds,rs);
516
517                         }
518                         if(FD_ISSET(is4,&sel) && parms.ip_type==AF_INET){
519                                 /*Data on the ICMPv4 socket*/
520                                 handleICMP4packet(is4);
521                         }
522                         if(FD_ISSET(is6,&sel) && parms.ip_type==AF_INET6){
523                                 /*Data on the ICMPv6 socket*/
524                                 handleICMP6packet(is6);
525                         }
526                         gettimeofday(&t,NULL);
527                 }
528
529                 /*Update count*/
530                 if(parms.count>-1){
531                         parms.count--;
532                 }
533                 request_seq++;
534                 packet_seq=rand();
535                 updateRequestPacket(sbuffer,&slen, packet_seq);
536         }
537
538         close(rs);
539         close(is4);
540         close(is6);
541         close(ds);
542 }
543
544 void handleDCCPpacket(int rcv_socket, int send_socket){
545         int rlen=1500;
546         unsigned char rbuffer[rlen];
547         ipaddr_ptr_t rcv_addr;
548         socklen_t rcv_addr_len;
549         struct dccp_hdr *dhdr;
550         struct dccp_hdr_reset *dhdr_re;
551         struct dccp_hdr_response *dhdr_rp;
552         struct dccp_hdr_ack_bits *dhdr_sync;
553         unsigned char* ptr;
554         struct iphdr* iph;
555
556         /*Memory for socket address*/
557         rcv_addr_len=sizeof(struct sockaddr_storage);
558         rcv_addr.gen=malloc(rcv_addr_len);
559         if(rcv_addr.gen==NULL){
560                 dbgprintf(0,"Error: Can't Allocate Memory!\n");
561                 exit(1);
562         }
563
564         /*Receive Packet*/
565         rcv_addr_len=sizeof(struct sockaddr_storage);
566         if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){
567                 if(errno!=EINTR){
568                         dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno));
569                 }
570         }
571         if(rlen<0){
572                 return;
573         }
574
575         if(rcv_addr.gen->sa_family!=parms.ip_type){ //confirm IP type
576                 dbgprintf(1, "DCCP packet on %s. Tossing.\n", (parms.ip_type==AF_INET) ? "IPv4" : "IPv6");
577                 free(rcv_addr.gen);
578                 return;
579         }
580
581         if(rcv_addr.gen->sa_family==AF_INET){
582                 /*IPv4*/
583                 if(memcmp(&rcv_addr.ipv4->sin_addr,&parms.dest_addr.ipv4->sin_addr,
584                                 sizeof(parms.dest_addr.ipv4->sin_addr))!=0){ //not from destination
585                         dbgprintf(1,"DCCP packet from 3rd host\n");
586                         free(rcv_addr.gen);
587                         return;
588                 }
589                 if(rlen < sizeof(struct dccp_hdr)+sizeof(struct iphdr)){ //check packet size
590
591                         dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n");
592                         free(rcv_addr.gen);
593                         return;
594                 }
595                 iph=(struct iphdr*)rbuffer;
596                 ptr=rbuffer+iph->ihl*4;
597         }else{
598                 /*IPv6*/
599                 if(memcmp(&rcv_addr.ipv6->sin6_addr, &parms.dest_addr.ipv6->sin6_addr,
600                                 sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){ //not from destination
601                         dbgprintf(1,"DCCP packet from 3rd host\n");
602                         free(rcv_addr.gen);
603                         return;
604                 }
605                 if(rlen < sizeof(struct dccp_hdr)){ //check packet size
606
607                         dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n");
608                         free(rcv_addr.gen);
609                         return;
610                 }
611                 ptr=rbuffer;
612         }
613
614         /*DCCP checks*/
615         dhdr=(struct dccp_hdr*)ptr;
616         if(dhdr->dccph_sport!=htons(parms.dest_port)){
617                 dbgprintf(1,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport));
618                 free(rcv_addr.gen);
619                 return;
620         }
621         if(dhdr->dccph_dport!=htons(parms.src_port)){
622                 dbgprintf(1,"DCCP packet with wrong Destination Port\n");
623                 free(rcv_addr.gen);
624                 return;
625         }
626
627         /*Pick Response*/
628         if(dhdr->dccph_type==DCCP_PKT_RESET){
629                 if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_reset)){
630                         dbgprintf(1, "Tossing DCCP Reset packet that's small!\n");
631                         return;
632                 }
633                 dhdr_re=(struct dccp_hdr_reset*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
634
635                 /*Log*/
636                 if(dhdr_re->dccph_reset_code==DCCP_RESET_CODE_NO_CONNECTION){
637                         logResponse(&rcv_addr, ntohl(dhdr_re->dccph_reset_ack.dccph_ack_nr_low), RESET);
638                 }else{
639                         logResponse(&rcv_addr, ntohl(dhdr_re->dccph_reset_ack.dccph_ack_nr_low), DCCP_ERROR);
640                 }
641                 /*Nothing else to do*/
642         }
643         if(dhdr->dccph_type==DCCP_PKT_RESPONSE){
644                 if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_response)){
645                         dbgprintf(1, "Tossing DCCP Response packet that's too small!\n");
646                         return;
647                 }
648
649                 /*Log*/
650                 dhdr_rp=(struct dccp_hdr_response*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
651                 logResponse(&rcv_addr,ntohl(dhdr_rp->dccph_resp_ack.dccph_ack_nr_low),RESPONSE);
652
653                 /*DCCP socket opened in getAddresses() will send Reset*/
654         }
655         if(dhdr->dccph_type==DCCP_PKT_SYNC || dhdr->dccph_type==DCCP_PKT_SYNCACK){
656                 if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_ack_bits)){
657                         dbgprintf(1, "Tossing DCCP Sync/SyncAck packet that's too small!\n");
658                         return;
659                 }
660
661                 /*Log*/
662                 dhdr_sync=(struct dccp_hdr_ack_bits*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
663                 logResponse(&rcv_addr,ntohl(dhdr_sync->dccph_ack_nr_low),SYNC);
664
665                 /*DCCP socket opened in getAddresses() will send Reset*/
666         }
667
668         free(rcv_addr.gen);
669 }
670
671 void handleICMP4packet(int rcv_socket){
672         int rlen=1500;
673         unsigned char rbuffer[rlen];
674         ipaddr_ptr_t rcv_addr;
675         socklen_t rcv_addr_len;
676         struct icmphdr *icmp4;
677         struct dccp_hdr *dhdr;
678         struct dccp_hdr_ext *dhdre;
679         struct iphdr* ip4hdr;
680         struct iphdr* iph;
681         int type;
682
683         /*Memory for socket address*/
684         rcv_addr_len=sizeof(struct sockaddr_storage);
685         rcv_addr.gen=malloc(rcv_addr_len);
686         if(rcv_addr.gen==NULL){
687                 dbgprintf(0,"Error: Can't Allocate Memory!\n");
688                 exit(1);
689         }
690
691         /*Receive Packet*/
692         if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){
693                 if(errno!=EINTR){
694                         dbgprintf(0, "Error on receive from ICMPv4 socket (%s)\n",strerror(errno));
695                 }
696         }
697         if(rlen<0){
698                 return;
699         }
700
701         iph=(struct iphdr*)rbuffer;
702
703
704         if(rlen < sizeof(struct icmphdr)+sizeof(struct iphdr)){ //check packet size
705                 dbgprintf(1, "Packet smaller than possible ICMPv4 packet!\n");
706                 free(rcv_addr.gen);
707                 return;
708         }
709
710         icmp4=(struct icmphdr*)(rbuffer+iph->ihl*4);
711         if(icmp4->type!=ICMP_DEST_UNREACH && icmp4->type!=ICMP_TIME_EXCEEDED){ //check icmp types
712                 dbgprintf(1, "Tossing ICMPv4 packet of type %i\n", icmp4->type);
713                 free(rcv_addr.gen);
714                 return;
715         }
716
717         /*Check packet size again*/
718         if(rlen<sizeof(struct icmphdr)+2*sizeof(struct iphdr)+4){
719                 dbgprintf(1, "Tossing ICMPv4 packet that's too small to contain DCCP header!\n");
720                 free(rcv_addr.gen);
721                 return;
722         }
723
724         /*Decode IPv4 header*/
725         ip4hdr=(struct iphdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr));
726         if(memcmp(&parms.src_addr.ipv4->sin_addr,&ip4hdr->saddr,sizeof(parms.src_addr.ipv4->sin_addr))!=0){
727                 /*Source address doesn't match*/
728                 dbgprintf(1,"Tossing ICMPv4 packet because the embedded IPv4 source address isn't us\n");
729                 free(rcv_addr.gen);
730                 return;
731         }
732         if(memcmp(&parms.dest_addr.ipv4->sin_addr,&ip4hdr->daddr,sizeof(parms.dest_addr.ipv4->sin_addr))!=0){
733                 /*Destination address doesn't match*/
734                 dbgprintf(1,"Tossing ICMPv4 packet because the embedded IPv4 destination address isn't our target\n");
735                 free(rcv_addr.gen);
736                 return;
737         }
738         if(ip4hdr->protocol!=IPPROTO_DCCP){
739                 /*Not DCCP!*/
740                 dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n");
741                 free(rcv_addr.gen);
742                 return;
743         }
744
745         /*Decode DCCP header*/
746         dhdr=(struct dccp_hdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)+ip4hdr->ihl*4);
747         if(dhdr->dccph_dport!=htons(parms.dest_port)){
748                 /*DCCP Destination Ports don't match*/
749                 dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP destination port\n");
750                 free(rcv_addr.gen);
751                 return;
752         }
753         if(dhdr->dccph_sport!=htons(parms.src_port)){
754                 /*DCCP Source Ports don't match*/
755                 dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP source port\n");
756                 free(rcv_addr.gen);
757                 return;
758         }
759         dhdre=(struct dccp_hdr_ext*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)+ip4hdr->ihl*4+sizeof(struct dccp_hdr));
760
761         /*Log*/
762         if(icmp4->type==ICMP_DEST_UNREACH){
763                 type=DEST_UNREACHABLE;
764         }
765         if(icmp4->type==ICMP_TIME_EXCEEDED){
766                 type=TTL_EXPIRATION;
767         }
768         if(rlen<sizeof(struct icmphdr)+2*sizeof(struct iphdr)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)){
769                 logResponse(&rcv_addr,-1,type);
770         }else{
771                 logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),type);
772         }
773         free(rcv_addr.gen);
774         return;
775 }
776
777 void handleICMP6packet(int rcv_socket){
778         int rlen=1500;
779         unsigned char rbuffer[rlen];
780         ipaddr_ptr_t rcv_addr;
781         socklen_t rcv_addr_len;
782         struct icmp6_hdr *icmp6;
783         struct ip6_hdr* ip6hdr;
784         struct dccp_hdr *dhdr;
785         struct dccp_hdr_ext *dhdre;
786         int type;
787
788         /*Memory for socket address*/
789         rcv_addr_len=sizeof(struct sockaddr_storage);
790         rcv_addr.gen=malloc(rcv_addr_len);
791         if(rcv_addr.gen==NULL){
792                 dbgprintf(0,"Error: Can't Allocate Memory!\n");
793                 exit(1);
794         }
795
796         /*Receive Packet*/
797         if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){
798                 dbgprintf(0, "Error on receive from ICMPv6 socket (%s)\n",strerror(errno));
799         }
800
801         if(rlen < sizeof(struct icmp6_hdr)){ //check packet size
802                 dbgprintf(1, "Packet smaller than possible ICMPv6 packet!\n");
803                 free(rcv_addr.gen);
804                 return;
805         }
806
807         icmp6=(struct icmp6_hdr*)rbuffer;
808         if(icmp6->icmp6_type!=ICMP6_DST_UNREACH && icmp6->icmp6_type!=ICMP6_PACKET_TOO_BIG
809                         && icmp6->icmp6_type!=ICMP6_TIME_EXCEEDED && icmp6->icmp6_type!=ICMP6_PARAM_PROB){ //check icmp types
810                 dbgprintf(1, "Tossing ICMPv6 packet of type %i\n", icmp6->icmp6_type);
811                 free(rcv_addr.gen);
812                 return;
813         }
814
815         /*Check packet size again*/
816         if(rlen<sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)){
817                 dbgprintf(1, "Tossing ICMPv6 packet that's too small to contain DCCP header!\n");
818                 free(rcv_addr.gen);
819                 return;
820         }
821
822         /*Decode IPv6 header*/
823         ip6hdr=(struct ip6_hdr*)(rbuffer+sizeof(struct icmp6_hdr));
824         if(memcmp(&parms.src_addr.ipv6->sin6_addr,&ip6hdr->ip6_src,sizeof(parms.src_addr.ipv6->sin6_addr))!=0){
825                 dbgprintf(1,"Tossing ICMPv6 packet because the embedded IPv6 source address isn't us\n");
826                 /*Source address doesn't match*/
827                 free(rcv_addr.gen);
828                 return;
829         }
830         if(memcmp(&parms.dest_addr.ipv6->sin6_addr,&ip6hdr->ip6_dst,sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){
831                 /*Destination address doesn't match*/
832                 dbgprintf(1,"Tossing ICMPv6 packet because the embedded IPv6 destination address isn't our target\n");
833                 free(rcv_addr.gen);
834                 return;
835         }
836         if(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt!=IPPROTO_DCCP){
837                 /*Not DCCP!*/
838                 dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n");
839                 free(rcv_addr.gen);
840                 return;
841         }
842
843         /*Decode DCCP header*/
844         dhdr=(struct dccp_hdr*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr));
845         if(dhdr->dccph_dport!=htons(parms.dest_port)){
846                 /*DCCP Destination Ports don't match*/
847                 dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP destination port\n");
848                 free(rcv_addr.gen);
849                 return;
850         }
851         if(dhdr->dccph_sport!=htons(parms.src_port)){
852                 /*DCCP Source Ports don't match*/
853                 dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP source port\n");
854                 free(rcv_addr.gen);
855                 return;
856         }
857         dhdre=(struct dccp_hdr_ext*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr));
858
859         /*Log*/
860         if(icmp6->icmp6_type==ICMP6_DST_UNREACH){
861                 type=DEST_UNREACHABLE;
862         }
863         if(icmp6->icmp6_type==ICMP6_PACKET_TOO_BIG){
864                 type=TOO_BIG;
865         }
866         if(icmp6->icmp6_type==ICMP6_TIME_EXCEEDED){
867                 type=TTL_EXPIRATION;
868         }
869         if(icmp6->icmp6_type==ICMP6_PARAM_PROB){
870                 type=PARAMETER_PROBLEM;
871         }
872         logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),type);
873         free(rcv_addr.gen);
874         return;
875 }
876
877 void buildRequestPacket(unsigned char* buffer, int *len, int seq){
878         struct dccp_hdr *dhdr;
879         struct dccp_hdr_ext *dhdre;
880         struct dccp_hdr_request *dhdrr;
881         struct iphdr* ip4hdr;
882         struct ip6_hdr* ip6hdr;
883
884         int ip_hdr_len;
885         int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request);
886
887         if(*len < dccp_hdr_len+sizeof(struct ip6_hdr)){
888                 dbgprintf(0, "Error: Insufficient buffer space\n");
889                 exit(1);
890         }
891
892         memset(buffer, 0, *len);
893
894         /*IP header*/
895         ip4hdr=NULL;
896         if(parms.ip_type==AF_INET){
897                 ip_hdr_len=sizeof(struct iphdr);
898                 ip4hdr=(struct iphdr*)buffer;
899                 ip4hdr->check=htons(0);
900                 memcpy(&ip4hdr->daddr, &parms.dest_addr.ipv4->sin_addr, sizeof(parms.dest_addr.ipv4->sin_addr));
901                 ip4hdr->frag_off=htons(0);
902                 ip4hdr->id=htons(1);//first
903                 ip4hdr->ihl=5;
904                 ip4hdr->protocol=IPPROTO_DCCP;
905                 memcpy(&ip4hdr->saddr, &parms.src_addr.ipv4->sin_addr, sizeof(parms.src_addr.ipv4->sin_addr));
906                 ip4hdr->tos=0;
907                 ip4hdr->tot_len=htons(ip_hdr_len+dccp_hdr_len);
908                 ip4hdr->ttl=parms.ttl;
909                 ip4hdr->version=4;
910         }else{
911                 ip_hdr_len=sizeof(struct ip6_hdr);
912                 ip6hdr=(struct ip6_hdr*)buffer;
913                 memcpy(&ip6hdr->ip6_dst, &parms.dest_addr.ipv6->sin6_addr, sizeof(parms.dest_addr.ipv6->sin6_addr));
914                 memcpy(&ip6hdr->ip6_src, &parms.src_addr.ipv6->sin6_addr, sizeof(parms.src_addr.ipv6->sin6_addr));
915                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_flow=htonl(6<<28); //version, traffic class, flow label
916                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim=parms.ttl;
917                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt=IPPROTO_DCCP;
918                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen=htons(dccp_hdr_len);
919         }
920
921         /*DCCP header*/
922         dhdr=(struct dccp_hdr*)(buffer+ip_hdr_len);
923         dhdre=(struct dccp_hdr_ext*)(buffer+ip_hdr_len+sizeof(struct dccp_hdr));
924         dhdrr=(struct dccp_hdr_request*)(buffer+ip_hdr_len+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
925         dhdr->dccph_ccval=0;
926         dhdr->dccph_checksum=0;
927         dhdr->dccph_cscov=0;
928         dhdr->dccph_doff=dccp_hdr_len/4;
929         dhdr->dccph_dport=htons(parms.dest_port);
930         dhdr->dccph_reserved=0;
931         dhdr->dccph_sport=htons(parms.src_port);
932         dhdr->dccph_x=1;
933         dhdr->dccph_type=DCCP_PKT_REQUEST;
934         dhdr->dccph_seq2=htonl(0); //Reserved if using 48 bit sequence numbers
935         dhdr->dccph_seq=htonl(0);  //High 16bits of sequence number. Always make 0 for simplicity.
936         dhdre->dccph_seq_low=htonl(seq);
937         dhdrr->dccph_req_service=htonl(DCCP_SERVICE_CODE);
938
939         /*Checksums*/
940         if(parms.ip_type==AF_INET){
941                 dhdr->dccph_checksum=ipv4_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
942                                 (unsigned char*) &parms.dest_addr.ipv4->sin_addr,
943                                 (unsigned char*)&parms.src_addr.ipv4->sin_addr, IPPROTO_DCCP);
944                 ip4hdr->check=ipv4_chksum(buffer,ip_hdr_len);
945         }else{
946                 dhdr->dccph_checksum=ipv6_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
947                                 (unsigned char*) &parms.dest_addr.ipv6->sin6_addr,
948                                 (unsigned char*)&parms.src_addr.ipv6->sin6_addr, IPPROTO_DCCP);
949         }
950         *len=ip_hdr_len+dccp_hdr_len;
951         return;
952 }
953
954 void updateRequestPacket(unsigned char* buffer, int *len, int seq){
955         struct dccp_hdr *dhdr;
956         struct dccp_hdr_ext *dhdre;
957         struct iphdr* ip4hdr;
958
959         int ip_hdr_len;
960         int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request);
961
962         /*IP header*/
963         ip4hdr=NULL;
964         if(parms.ip_type==AF_INET){
965                 ip_hdr_len=sizeof(struct iphdr);
966                 ip4hdr=(struct iphdr*)buffer;
967                 ip4hdr->check=htons(0);
968                 ip4hdr->id=htons(seq);
969         }else{
970                 ip_hdr_len=sizeof(struct ip6_hdr);
971         }
972
973         /*DCCP header*/
974         dhdr=(struct dccp_hdr*)(buffer+ip_hdr_len);
975         dhdre=(struct dccp_hdr_ext*)(buffer+ip_hdr_len+sizeof(struct dccp_hdr));
976         dhdr->dccph_checksum=0;
977         dhdre->dccph_seq_low=htonl(seq);
978
979         /*Checksums*/
980         if(parms.ip_type==AF_INET){
981                 dhdr->dccph_checksum=ipv4_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
982                                 (unsigned char*) &parms.dest_addr.ipv4->sin_addr,
983                                 (unsigned char*)&parms.src_addr.ipv4->sin_addr, IPPROTO_DCCP);
984                 ip4hdr->check=ipv4_chksum(buffer,ip_hdr_len);
985         }else{
986                 dhdr->dccph_checksum=ipv6_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
987                                 (unsigned char*) &parms.dest_addr.ipv6->sin6_addr,
988                                 (unsigned char*)&parms.src_addr.ipv6->sin6_addr, IPPROTO_DCCP);
989         }
990         *len=ip_hdr_len+dccp_hdr_len;
991         return;
992 }
993
994 int logPacket(int req_seq, int packet_seq){
995         struct request *tmp;
996
997         /*Add new request to queue*/
998         tmp=malloc(sizeof(struct request));
999         if(tmp==NULL){
1000                 dbgprintf(0,"Error: Can't allocate Memory!\n");
1001                 exit(1);
1002         }
1003         tmp->next=NULL;
1004         tmp->prev=NULL;
1005         tmp->num_replies=0;
1006         tmp->num_errors=0;
1007         tmp->packet_seq=packet_seq;
1008         tmp->request_seq=req_seq;
1009         tmp->reply_type=UNKNOWN;
1010         gettimeofday(&tmp->sent,NULL);
1011
1012         if(queue.head==NULL){
1013                 queue.head=queue.tail=tmp;
1014         }else{
1015                 queue.head->prev=tmp;
1016                 tmp->next=queue.head;
1017                 queue.head=tmp;
1018         }
1019
1020         /*Update Statistics*/
1021         if(ping_stats.requests_sent==0){
1022                 gettimeofday(&ping_stats.start,NULL);
1023         }
1024         ping_stats.requests_sent++;
1025         return 0;
1026 }
1027
1028 int logResponse(ipaddr_ptr_t *src, int seq, int type){
1029         struct request *cur;
1030         double diff;
1031         char pbuf[1000];
1032
1033         if(queue.tail==NULL){
1034                 dbgprintf(1,"Response received but no requests sent!\n");
1035                 return -1;
1036         }
1037
1038         /*Locate request*/
1039         cur=queue.tail;
1040         while(cur!=NULL){
1041                 if(cur->packet_seq==seq){
1042                         gettimeofday(&cur->reply,NULL);
1043                         if(cur->num_replies>0){
1044                                 printf("Duplicate packet detected! (%i)\n",cur->request_seq);
1045                         }
1046                         if(type<DEST_UNREACHABLE && type!=UNKNOWN){
1047                                 cur->num_replies++;
1048                         }else{
1049                                 cur->num_errors++;
1050                         }
1051                         cur->reply_type=type;
1052                         break;
1053                 }
1054                 cur=cur->prev;
1055         }
1056
1057         if(cur==NULL){
1058                 if(parms.ip_type==AF_INET && seq==-1){
1059                         /*IPv4 didn't include enough of the packet to get sequence numbers!*/
1060                         printf("%s from %s\n",response_label[type],
1061                                                                 inet_ntop(parms.ip_type, (void*)&src->ipv4->sin_addr, pbuf, 1000));
1062                         ping_stats.errors++;
1063                         return 0;
1064                 }else{
1065                         dbgprintf(1,"Response received but no requests sent with sequence number %i!\n", seq);
1066                         return -1;
1067                 }
1068         }
1069
1070         diff=(cur->reply.tv_usec + 1000000*cur->reply.tv_sec) - (cur->sent.tv_usec + 1000000*cur->sent.tv_sec);
1071         diff=diff/1000.0;
1072
1073         /*Print Message*/
1074         if(type<DEST_UNREACHABLE && type!=UNKNOWN){
1075                 if(parms.ip_type==AF_INET){
1076                         printf( "Response from %s : seq=%i  time=%.1fms  status=%s\n",
1077                                         inet_ntop(parms.ip_type, (void*)&src->ipv4->sin_addr, pbuf, 1000),
1078                                         cur->request_seq, diff,response_label[type]);
1079                 }else{
1080                         printf("Response from %s : seq=%i  time=%.1fms  status=%s\n",
1081                                         inet_ntop(parms.ip_type, (void*)&src->ipv6->sin6_addr, pbuf, 1000),
1082                                         cur->request_seq, diff,response_label[type]);
1083                 }
1084         }else{
1085                 if(parms.ip_type==AF_INET){
1086                         printf("%s from %s : seq=%i\n",response_label[type],
1087                                         inet_ntop(parms.ip_type, (void*)&src->ipv4->sin_addr, pbuf, 1000),
1088                                         cur->request_seq);
1089                 }else{
1090                         printf("%s from %s : seq=%i\n",response_label[type],
1091                                         inet_ntop(parms.ip_type, (void*)&src->ipv6->sin6_addr, pbuf, 1000),
1092                                         cur->request_seq);
1093                 }
1094         }
1095
1096         /*Update statistics*/
1097         if(type<DEST_UNREACHABLE && type!=UNKNOWN){
1098                 /*Good Response*/
1099                 if(cur->num_replies==1){
1100                         ping_stats.rtt_avg=((ping_stats.replies_received*ping_stats.rtt_avg)+(diff))/(ping_stats.replies_received+1);
1101                         ping_stats.replies_received++;
1102                 }else{
1103                         ping_stats.errors++;
1104                 }
1105                 if(diff < ping_stats.rtt_min || ping_stats.rtt_min==0){
1106                         ping_stats.rtt_min=diff;
1107                 }
1108                 if(diff > ping_stats.rtt_max){
1109                         ping_stats.rtt_max=diff;
1110                 }
1111         }else{
1112                 /*Error*/
1113                 ping_stats.errors++;
1114         }
1115         gettimeofday(&ping_stats.stop,NULL);
1116         return 0;
1117 }
1118
1119 void clearQueue(){
1120         struct request *cur;
1121         struct request *tmp;
1122
1123         cur=queue.head;
1124         while(cur!=NULL){
1125                 tmp=cur;
1126                 cur=cur->next;
1127                 free(tmp);
1128         }
1129         queue.head=NULL;
1130         queue.tail=NULL;
1131         return;
1132 }
1133
1134 void sigHandler(){
1135         char pbuf[1000];
1136         int diff;
1137         double ploss;
1138
1139         /*Print Stats*/
1140         gettimeofday(&ping_stats.stop,NULL);
1141         if(parms.ip_type==AF_INET){
1142                 printf("-----------%s PING STATISTICS-----------\n",
1143                                 inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv4->sin_addr, pbuf, 1000));
1144         }else if(parms.ip_type==AF_INET6){
1145                 printf("-----------%s PING STATISTICS-----------\n",
1146                                 inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv6->sin6_addr, pbuf, 1000));
1147         }
1148         diff=(ping_stats.stop.tv_usec + 1000000*ping_stats.stop.tv_sec) -
1149                         (ping_stats.start.tv_usec + 1000000*ping_stats.start.tv_sec);
1150         diff=diff/1000.0;
1151         ploss=(1.0*(ping_stats.requests_sent-ping_stats.replies_received)/ping_stats.requests_sent*1.0)*100;
1152         printf("%i packets transmitted, %i received, %i errors, %.2f%% loss, time %ims\n",
1153                         ping_stats.requests_sent,ping_stats.replies_received,ping_stats.errors,
1154                         ploss,diff);
1155         printf("rtt min/avg/max = %.1f/%.1f/%.1f ms\n",
1156                         ping_stats.rtt_min,ping_stats.rtt_avg,ping_stats.rtt_max);
1157
1158
1159         /*Exit Quickly*/
1160         parms.count=0;
1161 }
1162
1163 /*Usage information for program*/
1164 void usage()
1165 {
1166         dbgprintf(0, "dccpping: [-d] [-v] [-h] [-6|-4] [-c count] [-p port] [-i interval]\n");
1167         dbgprintf(0, "          [-t ttl] [-S srcaddress] remote_host\n");
1168         dbgprintf(0, "\n");
1169         dbgprintf(0, "          -d   Debug. May be repeated for aditional verbosity\n");
1170         dbgprintf(0, "          -v   Version information\n");
1171         dbgprintf(0, "          -h   Help\n");
1172         dbgprintf(0, "          -6   Force IPv6 mode\n");
1173         dbgprintf(0, "          -4   Force IPv4 mode\n");
1174         exit(0);
1175 }
1176
1177 void version(){
1178         dbgprintf(0, "dccpping version %.1f\nCopyright (C) 2012 Samuel Jero <sj323707@ohio.edu>\n", DCCPPING_VERSION);
1179         dbgprintf(0, "This program comes with ABSOLUTELY NO WARRANTY.\n");
1180         dbgprintf(0, "This is free software, and you are welcome to\nredistribute it under certain conditions.\n");
1181         exit(0);
1182 }
1183
1184 /*Program will probably be run setuid, so be extra careful*/
1185 void sanitize_environment()
1186 {
1187 #if defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE)
1188         clearenv();
1189 #else
1190         extern char **environ;
1191         environ = NULL;
1192 #endif
1193 }
1194
1195 /*Debug Printf*/
1196 void dbgprintf(int level, const char *fmt, ...)
1197 {
1198     va_list args;
1199     if(debug>=level){
1200         va_start(args, fmt);
1201         vfprintf(stderr, fmt, args);
1202         va_end(args);
1203     }
1204 }