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