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