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