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