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