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