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