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