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