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