]> sjero.net Git - dccpping/blob - dccpping.c
Switch debug to verbose. Version info is now -V. Only display status in verbose mode
[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 'v':
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                 dbgprintf(2, "Sending DCCP Request to %s\n", addr2str(&parms.dest_addr,1));
546
547                 /*Use select to wait on packets or until interval has passed*/
548                 add.tv_sec=parms.interval/1000;
549                 add.tv_usec=(parms.interval%1000)*1000;
550                 gettimeofday(&t,NULL);
551                 timeradd(&t,&add,&delay);
552                 while(timercmp(&t,&delay,<)){
553                         /*Prepare for select*/
554                         FD_ZERO(&sel);
555                         FD_SET(ds,&sel);
556                         FD_SET(is4,&sel);
557                         FD_SET(is6,&sel);
558                         timersub(&delay,&t,&timeout);
559
560                         /*Do select call*/
561                         if(select(MAX(ds+1,MAX(is4+1,is6+1)),&sel, NULL,NULL,&timeout)<0){
562                                 if(errno!=EINTR){
563                                         dbgprintf(0,"Select() error (%s)\n",strerror(errno));
564                                 }
565                         }
566                         if(parms.count==0){done=1;break;}
567
568                         if(FD_ISSET(ds,&sel)){
569                                 /*Data on the DCCP socket*/
570                                 handleDCCPpacket(ds,rs);
571
572                         }
573                         if(FD_ISSET(is4,&sel) && parms.ip_type==AF_INET){
574                                 /*Data on the ICMPv4 socket*/
575                                 handleICMP4packet(is4);
576                         }
577                         if(FD_ISSET(is6,&sel) && parms.ip_type==AF_INET6){
578                                 /*Data on the ICMPv6 socket*/
579                                 handleICMP6packet(is6);
580                         }
581                         gettimeofday(&t,NULL);
582                 }
583
584                 /*Update count*/
585                 if(parms.count>-1){
586                         parms.count--;
587                 }
588                 request_seq++;
589                 packet_seq=rand();
590                 updateRequestPacket(sbuffer,&slen, packet_seq);
591         }
592
593         close(rs);
594         close(is4);
595         close(is6);
596         close(ds);
597 }
598
599 void handleDCCPpacket(int rcv_socket, int send_socket){
600         int rlen=1500;
601         unsigned char rbuffer[rlen];
602         ipaddr_ptr_t rcv_addr;
603         socklen_t rcv_addr_len;
604         struct dccp_hdr *dhdr;
605         struct dccp_hdr_reset *dhdr_re;
606         struct dccp_hdr_response *dhdr_rp;
607         struct dccp_hdr_ack_bits *dhdr_sync;
608         unsigned char* ptr;
609         struct iphdr* iph;
610
611         /*Memory for socket address*/
612         rcv_addr_len=sizeof(struct sockaddr_storage);
613         rcv_addr.gen=malloc(rcv_addr_len);
614         if(rcv_addr.gen==NULL){
615                 dbgprintf(0,"Error: Can't Allocate Memory!\n");
616                 exit(1);
617         }
618
619         /*Receive Packet*/
620         rcv_addr_len=sizeof(struct sockaddr_storage);
621         if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){
622                 if(errno!=EINTR){
623                         dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno));
624                 }
625         }
626         if(rlen<0){
627                 return;
628         }
629
630         if(rcv_addr.gen->sa_family!=parms.ip_type){ //confirm IP type
631                 dbgprintf(2, "DCCP packet on %s. Tossing.\n", (parms.ip_type==AF_INET) ? "IPv4" : "IPv6");
632                 free(rcv_addr.gen);
633                 return;
634         }
635
636         if(rcv_addr.gen->sa_family==AF_INET){
637                 /*IPv4*/
638                 if(memcmp(&rcv_addr.ipv4->sin_addr,&parms.dest_addr.ipv4->sin_addr,
639                                 sizeof(parms.dest_addr.ipv4->sin_addr))!=0){ //not from destination
640                         dbgprintf(2,"DCCP packet from 3rd host\n");
641                         free(rcv_addr.gen);
642                         return;
643                 }
644                 if(rlen < sizeof(struct dccp_hdr)+sizeof(struct iphdr)){ //check packet size
645
646                         dbgprintf(2, "Packet smaller than possible DCCP packet received on DCCP socket\n");
647                         free(rcv_addr.gen);
648                         return;
649                 }
650                 iph=(struct iphdr*)rbuffer;
651                 ptr=rbuffer+iph->ihl*4;
652         }else{
653                 /*IPv6*/
654                 if(memcmp(&rcv_addr.ipv6->sin6_addr, &parms.dest_addr.ipv6->sin6_addr,
655                                 sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){ //not from destination
656                         dbgprintf(2,"DCCP packet from 3rd host\n");
657                         free(rcv_addr.gen);
658                         return;
659                 }
660                 if(rlen < sizeof(struct dccp_hdr)){ //check packet size
661
662                         dbgprintf(2, "Packet smaller than possible DCCP packet received on DCCP socket\n");
663                         free(rcv_addr.gen);
664                         return;
665                 }
666                 ptr=rbuffer;
667         }
668
669         /*DCCP checks*/
670         dhdr=(struct dccp_hdr*)ptr;
671         if(dhdr->dccph_sport!=htons(parms.dest_port)){
672                 dbgprintf(2,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport));
673                 free(rcv_addr.gen);
674                 return;
675         }
676         if(dhdr->dccph_dport!=htons(parms.src_port)){
677                 dbgprintf(2,"DCCP packet with wrong Destination Port\n");
678                 free(rcv_addr.gen);
679                 return;
680         }
681
682         /*Pick Response*/
683         if(dhdr->dccph_type==DCCP_PKT_RESET){
684                 if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_reset)){
685                         dbgprintf(2, "Tossing DCCP Reset packet that's small!\n");
686                         return;
687                 }
688                 dhdr_re=(struct dccp_hdr_reset*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
689
690                 /*Log*/
691                 if(dhdr_re->dccph_reset_code==DCCP_RESET_CODE_NO_CONNECTION){
692                         logResponse(&rcv_addr, ntohl(dhdr_re->dccph_reset_ack.dccph_ack_nr_low), DCCP_RESET,dhdr_re->dccph_reset_code,0);
693                 }
694                 /*Nothing else to do*/
695         }
696         if(dhdr->dccph_type==DCCP_PKT_RESPONSE){
697                 if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_response)){
698                         dbgprintf(2, "Tossing DCCP Response packet that's too small!\n");
699                         return;
700                 }
701
702                 /*Log*/
703                 dhdr_rp=(struct dccp_hdr_response*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
704                 logResponse(&rcv_addr,ntohl(dhdr_rp->dccph_resp_ack.dccph_ack_nr_low),DCCP_RESPONSE,0,0);
705
706                 /*DCCP socket opened in getAddresses() will send Reset*/
707         }
708         if(dhdr->dccph_type==DCCP_PKT_SYNC || dhdr->dccph_type==DCCP_PKT_SYNCACK){
709                 if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_ack_bits)){
710                         dbgprintf(2, "Tossing DCCP Sync/SyncAck packet that's too small!\n");
711                         return;
712                 }
713
714                 /*Log*/
715                 dhdr_sync=(struct dccp_hdr_ack_bits*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
716                 logResponse(&rcv_addr,ntohl(dhdr_sync->dccph_ack_nr_low),DCCP_SYNC,0,0);
717
718                 /*DCCP socket opened in getAddresses() will send Reset*/
719         }
720
721         free(rcv_addr.gen);
722 }
723
724 void handleICMP4packet(int rcv_socket){
725         int rlen=1500;
726         unsigned char rbuffer[rlen];
727         ipaddr_ptr_t rcv_addr;
728         socklen_t rcv_addr_len;
729         struct icmphdr *icmp4;
730         struct dccp_hdr *dhdr;
731         struct dccp_hdr_ext *dhdre;
732         struct iphdr* ip4hdr;
733         struct iphdr* iph;
734
735         /*Memory for socket address*/
736         rcv_addr_len=sizeof(struct sockaddr_storage);
737         rcv_addr.gen=malloc(rcv_addr_len);
738         if(rcv_addr.gen==NULL){
739                 dbgprintf(0,"Error: Can't Allocate Memory!\n");
740                 exit(1);
741         }
742
743         /*Receive Packet*/
744         if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){
745                 if(errno!=EINTR){
746                         dbgprintf(0, "Error on receive from ICMPv4 socket (%s)\n",strerror(errno));
747                 }
748         }
749         if(rlen<0){
750                 return;
751         }
752
753         iph=(struct iphdr*)rbuffer;
754
755
756         if(rlen < sizeof(struct icmphdr)+sizeof(struct iphdr)){ //check packet size
757                 dbgprintf(2, "Packet smaller than possible ICMPv4 packet!\n");
758                 free(rcv_addr.gen);
759                 return;
760         }
761
762         icmp4=(struct icmphdr*)(rbuffer+iph->ihl*4);
763         if(icmp4->type!=ICMP_DEST_UNREACH && icmp4->type!=ICMP_TIME_EXCEEDED){ //check icmp types
764                 dbgprintf(2, "Tossing ICMPv4 packet of type %i\n", icmp4->type);
765                 free(rcv_addr.gen);
766                 return;
767         }
768
769         /*Check packet size again*/
770         if(rlen<sizeof(struct icmphdr)+2*sizeof(struct iphdr)+4){
771                 dbgprintf(2, "Tossing ICMPv4 packet that's too small to contain DCCP header!\n");
772                 free(rcv_addr.gen);
773                 return;
774         }
775
776         /*Decode IPv4 header*/
777         ip4hdr=(struct iphdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr));
778         if(memcmp(&parms.src_addr.ipv4->sin_addr,&ip4hdr->saddr,sizeof(parms.src_addr.ipv4->sin_addr))!=0){
779                 /*Source address doesn't match*/
780                 dbgprintf(2,"Tossing ICMPv4 packet because the embedded IPv4 source address isn't us\n");
781                 free(rcv_addr.gen);
782                 return;
783         }
784         if(memcmp(&parms.dest_addr.ipv4->sin_addr,&ip4hdr->daddr,sizeof(parms.dest_addr.ipv4->sin_addr))!=0){
785                 /*Destination address doesn't match*/
786                 dbgprintf(2,"Tossing ICMPv4 packet because the embedded IPv4 destination address isn't our target\n");
787                 free(rcv_addr.gen);
788                 return;
789         }
790         if(ip4hdr->protocol!=IPPROTO_DCCP){
791                 /*Not DCCP!*/
792                 dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n");
793                 free(rcv_addr.gen);
794                 return;
795         }
796
797         /*Decode DCCP header*/
798         dhdr=(struct dccp_hdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)+ip4hdr->ihl*4);
799         if(dhdr->dccph_dport!=htons(parms.dest_port)){
800                 /*DCCP Destination Ports don't match*/
801                 dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP destination port\n");
802                 free(rcv_addr.gen);
803                 return;
804         }
805         if(dhdr->dccph_sport!=htons(parms.src_port)){
806                 /*DCCP Source Ports don't match*/
807                 dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP source port\n");
808                 free(rcv_addr.gen);
809                 return;
810         }
811         dhdre=(struct dccp_hdr_ext*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)+ip4hdr->ihl*4+sizeof(struct dccp_hdr));
812
813         /*Log*/
814         if(rlen<sizeof(struct icmphdr)+2*sizeof(struct iphdr)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)){
815                 logResponse(&rcv_addr,-1,ICMPv4,icmp4->type,icmp4->code);
816         }else{
817                 logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),ICMPv4,icmp4->type,icmp4->code);
818         }
819         free(rcv_addr.gen);
820         return;
821 }
822
823 void handleICMP6packet(int rcv_socket){
824         int rlen=1500;
825         unsigned char rbuffer[rlen];
826         ipaddr_ptr_t rcv_addr;
827         socklen_t rcv_addr_len;
828         struct icmp6_hdr *icmp6;
829         struct ip6_hdr* ip6hdr;
830         struct dccp_hdr *dhdr;
831         struct dccp_hdr_ext *dhdre;
832
833         /*Memory for socket address*/
834         rcv_addr_len=sizeof(struct sockaddr_storage);
835         rcv_addr.gen=malloc(rcv_addr_len);
836         if(rcv_addr.gen==NULL){
837                 dbgprintf(0,"Error: Can't Allocate Memory!\n");
838                 exit(1);
839         }
840
841         /*Receive Packet*/
842         if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){
843                 dbgprintf(0, "Error on receive from ICMPv6 socket (%s)\n",strerror(errno));
844         }
845
846         if(rlen < sizeof(struct icmp6_hdr)){ //check packet size
847                 dbgprintf(2, "Packet smaller than possible ICMPv6 packet!\n");
848                 free(rcv_addr.gen);
849                 return;
850         }
851
852         icmp6=(struct icmp6_hdr*)rbuffer;
853         if(icmp6->icmp6_type!=ICMP6_DST_UNREACH && icmp6->icmp6_type!=ICMP6_PACKET_TOO_BIG
854                         && icmp6->icmp6_type!=ICMP6_TIME_EXCEEDED && icmp6->icmp6_type!=ICMP6_PARAM_PROB){ //check icmp types
855                 dbgprintf(2, "Tossing ICMPv6 packet of type %i\n", icmp6->icmp6_type);
856                 free(rcv_addr.gen);
857                 return;
858         }
859
860         /*Check packet size again*/
861         if(rlen<sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)){
862                 dbgprintf(2, "Tossing ICMPv6 packet that's too small to contain DCCP header!\n");
863                 free(rcv_addr.gen);
864                 return;
865         }
866
867         /*Decode IPv6 header*/
868         ip6hdr=(struct ip6_hdr*)(rbuffer+sizeof(struct icmp6_hdr));
869         if(memcmp(&parms.src_addr.ipv6->sin6_addr,&ip6hdr->ip6_src,sizeof(parms.src_addr.ipv6->sin6_addr))!=0){
870                 dbgprintf(2,"Tossing ICMPv6 packet because the embedded IPv6 source address isn't us\n");
871                 /*Source address doesn't match*/
872                 free(rcv_addr.gen);
873                 return;
874         }
875         if(memcmp(&parms.dest_addr.ipv6->sin6_addr,&ip6hdr->ip6_dst,sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){
876                 /*Destination address doesn't match*/
877                 dbgprintf(2,"Tossing ICMPv6 packet because the embedded IPv6 destination address isn't our target\n");
878                 free(rcv_addr.gen);
879                 return;
880         }
881         if(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt!=IPPROTO_DCCP){
882                 /*Not DCCP!*/
883                 dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n");
884                 free(rcv_addr.gen);
885                 return;
886         }
887
888         /*Decode DCCP header*/
889         dhdr=(struct dccp_hdr*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr));
890         if(dhdr->dccph_dport!=htons(parms.dest_port)){
891                 /*DCCP Destination Ports don't match*/
892                 dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP destination port\n");
893                 free(rcv_addr.gen);
894                 return;
895         }
896         if(dhdr->dccph_sport!=htons(parms.src_port)){
897                 /*DCCP Source Ports don't match*/
898                 dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP source port\n");
899                 free(rcv_addr.gen);
900                 return;
901         }
902         dhdre=(struct dccp_hdr_ext*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr));
903
904         /*Log*/
905         logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low), ICMPv6, icmp6->icmp6_type,icmp6->icmp6_code);
906         free(rcv_addr.gen);
907         return;
908 }
909
910 void buildRequestPacket(unsigned char* buffer, int *len, int seq){
911         struct dccp_hdr *dhdr;
912         struct dccp_hdr_ext *dhdre;
913         struct dccp_hdr_request *dhdrr;
914         struct iphdr* ip4hdr;
915         struct ip6_hdr* ip6hdr;
916
917         int ip_hdr_len;
918         int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request);
919
920         if(*len < dccp_hdr_len+sizeof(struct ip6_hdr)){
921                 dbgprintf(0, "Error: Insufficient buffer space\n");
922                 exit(1);
923         }
924
925         memset(buffer, 0, *len);
926
927         /*IP header*/
928         ip4hdr=NULL;
929         if(parms.ip_type==AF_INET){
930                 ip_hdr_len=sizeof(struct iphdr);
931                 ip4hdr=(struct iphdr*)buffer;
932                 ip4hdr->check=htons(0);
933                 memcpy(&ip4hdr->daddr, &parms.dest_addr.ipv4->sin_addr, sizeof(parms.dest_addr.ipv4->sin_addr));
934                 ip4hdr->frag_off=htons(0);
935                 ip4hdr->id=htons(1);//first
936                 ip4hdr->ihl=5;
937                 ip4hdr->protocol=IPPROTO_DCCP;
938                 memcpy(&ip4hdr->saddr, &parms.src_addr.ipv4->sin_addr, sizeof(parms.src_addr.ipv4->sin_addr));
939                 ip4hdr->tos=0;
940                 ip4hdr->tot_len=htons(ip_hdr_len+dccp_hdr_len);
941                 ip4hdr->ttl=parms.ttl;
942                 ip4hdr->version=4;
943         }else{
944                 ip_hdr_len=sizeof(struct ip6_hdr);
945                 ip6hdr=(struct ip6_hdr*)buffer;
946                 memcpy(&ip6hdr->ip6_dst, &parms.dest_addr.ipv6->sin6_addr, sizeof(parms.dest_addr.ipv6->sin6_addr));
947                 memcpy(&ip6hdr->ip6_src, &parms.src_addr.ipv6->sin6_addr, sizeof(parms.src_addr.ipv6->sin6_addr));
948                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_flow=htonl(6<<28); //version, traffic class, flow label
949                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim=parms.ttl;
950                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt=IPPROTO_DCCP;
951                 ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen=htons(dccp_hdr_len);
952         }
953
954         /*DCCP header*/
955         dhdr=(struct dccp_hdr*)(buffer+ip_hdr_len);
956         dhdre=(struct dccp_hdr_ext*)(buffer+ip_hdr_len+sizeof(struct dccp_hdr));
957         dhdrr=(struct dccp_hdr_request*)(buffer+ip_hdr_len+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
958         dhdr->dccph_ccval=0;
959         dhdr->dccph_checksum=0;
960         dhdr->dccph_cscov=0;
961         dhdr->dccph_doff=dccp_hdr_len/4;
962         dhdr->dccph_dport=htons(parms.dest_port);
963         dhdr->dccph_reserved=0;
964         dhdr->dccph_sport=htons(parms.src_port);
965         dhdr->dccph_x=1;
966         dhdr->dccph_type=DCCP_PKT_REQUEST;
967         dhdr->dccph_seq2=htonl(0); //Reserved if using 48 bit sequence numbers
968         dhdr->dccph_seq=htonl(0);  //High 16bits of sequence number. Always make 0 for simplicity.
969         dhdre->dccph_seq_low=htonl(seq);
970         dhdrr->dccph_req_service=htonl(DCCP_SERVICE_CODE);
971
972         /*Checksums*/
973         if(parms.ip_type==AF_INET){
974                 dhdr->dccph_checksum=ipv4_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
975                                 (unsigned char*) &parms.dest_addr.ipv4->sin_addr,
976                                 (unsigned char*)&parms.src_addr.ipv4->sin_addr, IPPROTO_DCCP);
977                 ip4hdr->check=ipv4_chksum(buffer,ip_hdr_len);
978         }else{
979                 dhdr->dccph_checksum=ipv6_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
980                                 (unsigned char*) &parms.dest_addr.ipv6->sin6_addr,
981                                 (unsigned char*)&parms.src_addr.ipv6->sin6_addr, IPPROTO_DCCP);
982         }
983         *len=ip_hdr_len+dccp_hdr_len;
984         return;
985 }
986
987 void updateRequestPacket(unsigned char* buffer, int *len, int seq){
988         struct dccp_hdr *dhdr;
989         struct dccp_hdr_ext *dhdre;
990         struct iphdr* ip4hdr;
991
992         int ip_hdr_len;
993         int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request);
994
995         /*IP header*/
996         ip4hdr=NULL;
997         if(parms.ip_type==AF_INET){
998                 ip_hdr_len=sizeof(struct iphdr);
999                 ip4hdr=(struct iphdr*)buffer;
1000                 ip4hdr->check=htons(0);
1001                 ip4hdr->id=htons(seq);
1002         }else{
1003                 ip_hdr_len=sizeof(struct ip6_hdr);
1004         }
1005
1006         /*DCCP header*/
1007         dhdr=(struct dccp_hdr*)(buffer+ip_hdr_len);
1008         dhdre=(struct dccp_hdr_ext*)(buffer+ip_hdr_len+sizeof(struct dccp_hdr));
1009         dhdr->dccph_checksum=0;
1010         dhdre->dccph_seq_low=htonl(seq);
1011
1012         /*Checksums*/
1013         if(parms.ip_type==AF_INET){
1014                 dhdr->dccph_checksum=ipv4_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
1015                                 (unsigned char*) &parms.dest_addr.ipv4->sin_addr,
1016                                 (unsigned char*)&parms.src_addr.ipv4->sin_addr, IPPROTO_DCCP);
1017                 ip4hdr->check=ipv4_chksum(buffer,ip_hdr_len);
1018         }else{
1019                 dhdr->dccph_checksum=ipv6_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len,
1020                                 (unsigned char*) &parms.dest_addr.ipv6->sin6_addr,
1021                                 (unsigned char*)&parms.src_addr.ipv6->sin6_addr, IPPROTO_DCCP);
1022         }
1023         *len=ip_hdr_len+dccp_hdr_len;
1024         return;
1025 }
1026
1027 int logPacket(int req_seq, int packet_seq){
1028         struct request *tmp;
1029
1030         /*Add new request to queue*/
1031         tmp=malloc(sizeof(struct request));
1032         if(tmp==NULL){
1033                 dbgprintf(0,"Error: Can't allocate Memory!\n");
1034                 exit(1);
1035         }
1036         tmp->next=NULL;
1037         tmp->prev=NULL;
1038         tmp->num_replies=0;
1039         tmp->num_errors=0;
1040         tmp->packet_seq=packet_seq;
1041         tmp->request_seq=req_seq;
1042         tmp->reply_type=UNKNOWN;
1043         gettimeofday(&tmp->sent,NULL);
1044
1045         if(queue.head==NULL){
1046                 queue.head=queue.tail=tmp;
1047         }else{
1048                 queue.head->prev=tmp;
1049                 tmp->next=queue.head;
1050                 queue.head=tmp;
1051         }
1052
1053         /*Update Statistics*/
1054         if(ping_stats.requests_sent==0){
1055                 gettimeofday(&ping_stats.start,NULL);
1056         }
1057         ping_stats.requests_sent++;
1058         return 0;
1059 }
1060
1061 int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2){
1062         struct request *cur;
1063         double diff;
1064
1065         if(queue.tail==NULL){
1066                 dbgprintf(2,"Response received but no requests sent!\n");
1067                 return -1;
1068         }
1069
1070         /*Locate request*/
1071         cur=queue.tail;
1072         while(cur!=NULL){
1073                 if(cur->packet_seq==seq){
1074                         gettimeofday(&cur->reply,NULL);
1075                         if(cur->num_replies>0){
1076                                 printf("Duplicate packet detected! (%i)\n",cur->request_seq);
1077                         }
1078                         if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
1079                                 cur->num_replies++;
1080                         }else{
1081                                 cur->num_errors++;
1082                         }
1083                         cur->reply_type=type;
1084                         break;
1085                 }
1086                 cur=cur->prev;
1087         }
1088
1089         if(cur==NULL){
1090                 if(parms.ip_type==AF_INET && seq==-1){
1091                         /*IPv4 didn't include enough of the packet to get sequence numbers!*/
1092                         printf("%s from %s\n",get_error_string(type,v1,v2),addr2str(src,0));
1093                         ping_stats.errors++;
1094                         return 0;
1095                 }else{
1096                         dbgprintf(2,"Response received but no requests sent with sequence number %i!\n", seq);
1097                         return -1;
1098                 }
1099         }
1100
1101         diff=(cur->reply.tv_usec + 1000000*cur->reply.tv_sec) - (cur->sent.tv_usec + 1000000*cur->sent.tv_sec);
1102         diff=diff/1000.0;
1103
1104         /*Print Message*/
1105         if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
1106                 if(debug==0){
1107                         printf( "Response from %s : seq=%i  time=%.1fms\n",addr2str(src,0),cur->request_seq, diff);
1108                 }else{
1109                         printf( "Response from %s : seq=%i  time=%.1fms  status=%s\n",
1110                                         addr2str(src,0),cur->request_seq, diff,response_good[type]);
1111                 }
1112         }else{
1113
1114                 printf("%s from %s : seq=%i\n",get_error_string(type,v1,v2),addr2str(src,0),cur->request_seq);
1115         }
1116
1117         /*Update statistics*/
1118         if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
1119                 /*Good Response*/
1120                 if(cur->num_replies==1){
1121                         ping_stats.rtt_avg=((ping_stats.replies_received*ping_stats.rtt_avg)+(diff))/(ping_stats.replies_received+1);
1122                         ping_stats.replies_received++;
1123                 }else{
1124                         ping_stats.errors++;
1125                 }
1126                 if(diff < ping_stats.rtt_min || ping_stats.rtt_min==0){
1127                         ping_stats.rtt_min=diff;
1128                 }
1129                 if(diff > ping_stats.rtt_max){
1130                         ping_stats.rtt_max=diff;
1131                 }
1132         }else{
1133                 /*Error*/
1134                 ping_stats.errors++;
1135         }
1136         gettimeofday(&ping_stats.stop,NULL);
1137         return 0;
1138 }
1139
1140 const char *get_error_string(int type, int v1, int v2){
1141         const char *label=NULL;
1142         switch(type){
1143                 case DCCP_RESET:
1144                         if(v1>11){label=NULL;break;}
1145                         label=response_dccp_reset[v1];
1146                         break;
1147                 case ICMPv4:
1148                         switch(v1){
1149                                 case 3:
1150                                         if(v2>15){label=NULL;break;}
1151                                         label=response_icmpv4_dest_unreach[v2];
1152                                         break;
1153                                 case 11:
1154                                         if(v2>1){label=NULL;break;}
1155                                         label=response_icmpv4_ttl[v2];
1156                                         break;
1157                                 default:
1158                                         label=NULL;
1159                                         break;
1160                         }
1161                         break;
1162                 case ICMPv6:
1163                         switch(v1){
1164                                 case 1:
1165                                         if(v2>7){label=NULL;break;}
1166                                         label=response_icmpv6_dest_unreach[v2];
1167                                         break;
1168                                 case 2:
1169                                         if(v2>0){label=NULL;break;}
1170                                         label=response_icmpv6_packet_too_big;
1171                                         break;
1172                                 case 3:
1173                                         if(v2>1){label=NULL;break;}
1174                                         label=response_icmpv6_ttl[v2];
1175                                         break;
1176                                 case 4:
1177                                         if(v2>2){label=NULL;break;}
1178                                         label=response_icmpv6_param_prob[v2];
1179                                         break;
1180                                 default:
1181                                         label=NULL;
1182                                         break;
1183                         }
1184                         break;
1185         }
1186         return label;
1187 }
1188
1189 void clearQueue(){
1190         struct request *cur;
1191         struct request *tmp;
1192
1193         cur=queue.head;
1194         while(cur!=NULL){
1195                 tmp=cur;
1196                 cur=cur->next;
1197                 free(tmp);
1198         }
1199         queue.head=NULL;
1200         queue.tail=NULL;
1201         return;
1202 }
1203
1204 void sigHandler(){
1205         int diff;
1206         double ploss;
1207
1208         /*Print Stats*/
1209         gettimeofday(&ping_stats.stop,NULL);
1210         printf("-----------%s PING STATISTICS-----------\n",parms.hostname);
1211
1212         diff=(ping_stats.stop.tv_usec + 1000000*ping_stats.stop.tv_sec) -
1213                         (ping_stats.start.tv_usec + 1000000*ping_stats.start.tv_sec);
1214         diff=diff/1000.0;
1215         ploss=(1.0*(ping_stats.requests_sent-ping_stats.replies_received)/ping_stats.requests_sent*1.0)*100;
1216         printf("%i packets transmitted, %i received, %i errors, %.2f%% loss, time %ims\n",
1217                         ping_stats.requests_sent,ping_stats.replies_received,ping_stats.errors,
1218                         ploss,diff);
1219         printf("rtt min/avg/max = %.1f/%.1f/%.1f ms\n",
1220                         ping_stats.rtt_min,ping_stats.rtt_avg,ping_stats.rtt_max);
1221
1222
1223         /*Exit Quickly*/
1224         parms.count=0;
1225 }
1226
1227 char* addr2str(ipaddr_ptr_t *res, int nores){
1228         int size;
1229         int ret;
1230         if (!res->gen->sa_family)
1231                 return NULL;
1232
1233         if(res->gen->sa_family==AF_INET){
1234                 size=sizeof(struct sockaddr_in);
1235         }else if(res->gen->sa_family==AF_INET6){
1236                 size=sizeof(struct sockaddr_in6);
1237         }else{
1238                 return NULL;
1239         }
1240         if((ret=getnameinfo(res->gen, size,
1241                         addr2str_buf, sizeof (addr2str_buf), 0, 0, NI_NUMERICHOST))<0){
1242                 dbgprintf(0,"Error: getnameinfo() returned %s\n",gai_strerror(ret));
1243         }
1244
1245         if (parms.no_resolve||nores){
1246                 return addr2str_buf;
1247         }else{
1248             addr2nm_buf[0] = '\0';
1249             getnameinfo(res->gen, size,
1250                                 addr2nm_buf, sizeof (addr2nm_buf), 0, 0, NI_IDN);
1251             snprintf(addr2both_buf,1000," %s (%s)", addr2nm_buf[0] ? addr2nm_buf : addr2str_buf, addr2str_buf);
1252             return addr2both_buf;
1253         }
1254         return NULL;
1255 }
1256
1257 /*Usage information for program*/
1258 void usage()
1259 {
1260         dbgprintf(0, "dccpping: [-v] [-V] [-h] [-n] [-6|-4] [-c count] [-p port] [-i interval]\n");
1261         dbgprintf(0, "          [-t ttl] [-S srcaddress] remote_host\n");
1262         dbgprintf(0, "\n");
1263         dbgprintf(0, "          -v   Verbose. May be repeated for aditional verbosity.\n");
1264         dbgprintf(0, "          -V   Version information\n");
1265         dbgprintf(0, "          -h   Help\n");
1266         dbgprintf(0, "          -n   Numeric output only\n");
1267         dbgprintf(0, "          -6   Force IPv6 mode\n");
1268         dbgprintf(0, "          -4   Force IPv4 mode\n");
1269         exit(0);
1270 }
1271
1272 void version(){
1273         dbgprintf(0, "dccpping version %.1f\nCopyright (C) 2012 Samuel Jero <sj323707@ohio.edu>\n", DCCPPING_VERSION);
1274         dbgprintf(0, "This program comes with ABSOLUTELY NO WARRANTY.\n");
1275         dbgprintf(0, "This is free software, and you are welcome to\nredistribute it under certain conditions.\n");
1276         exit(0);
1277 }
1278
1279 /*Program will probably be run setuid, so be extra careful*/
1280 void sanitize_environment()
1281 {
1282 #if defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE)
1283         clearenv();
1284 #else
1285         extern char **environ;
1286         environ = NULL;
1287 #endif
1288 }
1289
1290 /*Debug Printf*/
1291 void dbgprintf(int level, const char *fmt, ...)
1292 {
1293     va_list args;
1294     if(debug>=level){
1295         va_start(args, fmt);
1296         vfprintf(stderr, fmt, args);
1297         va_end(args);
1298     }
1299 }