1 /******************************************************************************
2 Author: Samuel Jero <sj323707@ohio.edu>
6 Description: Program to ping hosts using DCCP REQ packets to test for DCCP connectivity.
7 ******************************************************************************/
16 #include <sys/types.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>
29 #include <linux/dccp.h>
30 #include "checksums.h"
33 #define MAX(x,y) (x>y ? x : y)
37 /*Structure for simpler IPv4/IPv6 Address handling*/
40 struct sockaddr_in *ipv4;
41 struct sockaddr_in6 *ipv6;
44 /*Possible Responses to a Request*/
57 /*Output strings corresponding to enum responses*/
58 static const char* response_label[]= {
60 "Closed Port (Reset)",
61 "Open Port (Response)",
63 "Destination Unreachable",
66 "DCCP Not Supported (Parameter Problem)",
67 "Protocol Error (DCCP Reset)"
70 /*Structure to keep track of information about a request*/
78 enum responses reply_type;
83 /*Request Queue head structure*/
89 /*Statistics about the requests and replies sent*/
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*/
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*/
118 void getAddresses(char *src, char* dst);
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);
132 void sanitize_environment();
133 void dbgprintf(int level, const char *fmt, ...);
136 /*Parse commandline options*/
137 int main(int argc, char *argv[])
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;
153 parms.dest_port=33434;
155 parms. interval=1000;
156 parms.ip_type=AF_UNSPEC;
157 parms.dest_addr.gen=NULL;
158 parms.src_addr.gen=NULL;
160 sanitize_environment();
162 while ((c = getopt(argc, argv, "64c:p:i:dt:S:")) != -1) {
165 parms.ip_type=AF_INET6;
168 parms.ip_type=AF_INET;
171 parms.count = atoi(optarg);
173 dbgprintf(0, "Error: count must be positive");
178 parms.dest_port = atoi(optarg);
181 parms.interval = (long)(atof(optarg) * 1000.0);
182 if (parms.interval <= 0) {
183 dbgprintf(0, "Error: Invalid interval\n");
191 parms.ttl = atoi(optarg);
192 if (parms.ttl < 1 || parms.ttl > 255) {
193 dbgprintf(0,"Error: Invalid TTL\n");
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");
219 signal(SIGINT, sigHandler);
222 free(parms.src_addr.gen);
223 free(parms.dest_addr.gen);
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;
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;
241 if((err=getaddrinfo(dst,NULL,&hint,&dtmp))!=0){
242 dbgprintf(0,"Error: Couldn't lookup destination %s (%s)\n", dst, gai_strerror(err));
246 dbgprintf(0,"Error: Unknown Host %s\n", dst);
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");
256 memcpy(parms.dest_addr.gen,dtmp->ai_addr,dtmp->ai_addrlen);
260 /*Get a meaningful source address*/
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));
268 dbgprintf(0,"Error: Unknown Host %s\n", dst);
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");
277 memcpy(parms.src_addr.gen,stmp->ai_addr,stmp->ai_addrlen);
281 /*Guess a good source address*/
285 if(cur->ifa_addr==NULL || cur->ifa_addr->sa_family!=parms.ip_type){
286 /*Not matching ipv4/ipv6 of dest*/
290 if(cur->ifa_flags & IFF_LOOPBACK){ /*Don't use loopback addresses*/
294 if(cur->ifa_addr!=NULL && cur->ifa_addr->sa_family==AF_INET6){
295 iv6=(struct sockaddr_in6*)cur->ifa_addr;
297 if(iv6->sin6_scope_id!=0){ /*Not globally valid address, if ipv6*/
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");
308 parms.src_addr.gen->sa_family=parms.ip_type;
309 memcpy(parms.src_addr.gen,cur->ifa_addr,addrlen);
318 /*Preform the ping functionality*/
324 unsigned char sbuffer[slen];
326 struct timeval timeout;
327 struct timeval t,delay, add;
333 rs=socket(parms.ip_type, SOCK_RAW ,IPPROTO_RAW);
335 dbgprintf(0, "Error opening raw socket\n");
338 ds=socket(parms.ip_type, SOCK_RAW ,IPPROTO_DCCP);
340 dbgprintf(0, "Error opening raw DCCP socket\n");
343 is4=socket(parms.ip_type,SOCK_RAW,IPPROTO_ICMP);
345 dbgprintf(0,"Error opening raw ICMPv4 socket\n");
348 is6=socket(parms.ip_type,SOCK_RAW,IPPROTO_ICMPV6);
350 dbgprintf(0,"Error opening raw ICMPv6 socket\n");
355 /*Build DCCP packet*/
357 buildRequestPacket(sbuffer,&slen,packet_seq);
358 if(parms.ip_type==AF_INET){
359 addrlen=sizeof(struct sockaddr_in);
361 addrlen=sizeof(struct sockaddr_in6);
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),
370 printf("PINGING %s on DCCP port %i\n",
371 inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv6->sin6_addr, pbuf, 1000),
377 if(sendto(rs, &sbuffer, slen, MSG_DONTWAIT,(struct sockaddr*)parms.dest_addr.gen,addrlen)<0){
379 dbgprintf(0,"Error: sendto failed\n");
382 if(parms.count==0){done=1; break;}
384 if (logPacket(request_seq,packet_seq)<0){
385 dbgprintf(0,"Error: Couldn't record request!\n");
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));
391 dbgprintf(1, "Sending DCCP Request to %s\n",
392 inet_ntop(parms.ip_type, (void*)&parms.dest_addr.ipv6->sin6_addr, pbuf, 1000));
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*/
406 timersub(&delay,&t,&timeout);
409 if(select(MAX(ds+1,MAX(is4+1,is6+1)),&sel, NULL,NULL,&timeout)<0){
411 dbgprintf(0,"Select() error (%s)\n",strerror(errno));
414 if(parms.count==0){done=1;break;}
416 if(FD_ISSET(ds,&sel)){
417 /*Data on the DCCP socket*/
418 handleDCCPpacket(ds,rs);
421 if(FD_ISSET(is4,&sel) && parms.ip_type==AF_INET){
422 /*Data on the ICMPv4 socket*/
423 handleICMP4packet(is4);
425 if(FD_ISSET(is6,&sel) && parms.ip_type==AF_INET6){
426 /*Data on the ICMPv6 socket*/
427 handleICMP6packet(is6);
429 gettimeofday(&t,NULL);
438 updateRequestPacket(sbuffer,&slen, packet_seq);
447 void handleDCCPpacket(int rcv_socket, int send_socket){
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;
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");
469 rcv_addr_len=sizeof(struct sockaddr_storage);
470 if((rlen=recvfrom(rcv_socket, &rbuffer, 1000,0,rcv_addr.gen,&rcv_addr_len))<0){
472 dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno));
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");
485 if(rcv_addr.gen->sa_family==AF_INET){
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");
493 if(rlen < sizeof(struct dccp_hdr)+sizeof(struct iphdr)){ //check packet size
495 dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n");
499 iph=(struct iphdr*)rbuffer;
500 ptr=rbuffer+iph->ihl*4;
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");
509 if(rlen < sizeof(struct dccp_hdr)){ //check packet size
511 dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n");
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));
525 if(dhdr->dccph_dport!=htons(parms.dest_port)){
526 dbgprintf(1,"DCCP packet with wrong Destination Port\n");
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");
537 dhdr_re=(struct dccp_hdr_reset*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext));
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);
543 logResponse(&rcv_addr, ntohl(dhdr_re->dccph_reset_ack.dccph_ack_nr_low), DCCP_ERROR);
545 /*Nothing else to do*/
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");
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);
559 sendClose(ntohl(dhdr_rp->dccph_resp_ack.dccph_ack_nr_low),
560 dhdr->dccph_seq, dhdre->dccph_seq_low,send_socket);
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");
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);
574 sendReset(ntohl(dhdr_sync->dccph_ack_nr_low),
575 dhdr->dccph_seq, dhdre->dccph_seq_low,send_socket);
581 void handleICMP4packet(int rcv_socket){
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;
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");
601 if((rlen=recvfrom(rcv_socket, &rbuffer, 1000,0,rcv_addr.gen,&rcv_addr_len))<0){
603 dbgprintf(0, "Error on receive from ICMPv4 socket (%s)\n",strerror(errno));
610 if(rlen < sizeof(struct icmphdr)){ //check packet size
611 dbgprintf(1, "Packet smaller than possible ICMPv4 packet!\n");
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);
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");
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");
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");
644 if(ip4hdr->protocol!=IPPROTO_DCCP){
646 dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n");
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");
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");
665 dhdre=(struct dccp_hdr_ext*)(rbuffer+sizeof(struct icmphdr)+ip4hdr->ihl*4+sizeof(struct dccp_hdr));
668 if(icmp4->type==ICMP_DEST_UNREACH){
669 type=DEST_UNREACHABLE;
671 if(icmp4->type==ICMP_TIME_EXCEEDED){
674 logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),type);
679 void handleICMP6packet(int rcv_socket){
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;
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");
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));
703 if(rlen < sizeof(struct icmp6_hdr)){ //check packet size
704 dbgprintf(1, "Packet smaller than possible ICMPv6 packet!\n");
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);
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");
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*/
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");
738 if(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt!=IPPROTO_DCCP){
740 dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n");
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");
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");
759 dhdre=(struct dccp_hdr_ext*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr));
762 if(icmp6->icmp6_type==ICMP6_DST_UNREACH){
763 type=DEST_UNREACHABLE;
765 if(icmp6->icmp6_type==ICMP6_PACKET_TOO_BIG){
768 if(icmp6->icmp6_type==ICMP6_TIME_EXCEEDED){
771 if(icmp6->icmp6_type==ICMP6_PARAM_PROB){
772 type=PARAMETER_PROBLEM;
774 logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),type);
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;
787 int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request);
789 if(*len < dccp_hdr_len+sizeof(struct ip6_hdr)){
790 dbgprintf(0, "Error: Insufficient buffer space\n");
794 memset(buffer, 0, *len);
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
806 ip4hdr->protocol=IPPROTO_DCCP;
807 memcpy(&ip4hdr->saddr, &parms.src_addr.ipv4->sin_addr, sizeof(parms.src_addr.ipv4->sin_addr));
809 ip4hdr->tot_len=htons(ip_hdr_len+dccp_hdr_len);
810 ip4hdr->ttl=parms.ttl;
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);
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));
828 dhdr->dccph_checksum=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);
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);
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);
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);
852 *len=ip_hdr_len+dccp_hdr_len;
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;
862 int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request);
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);
872 ip_hdr_len=sizeof(struct ip6_hdr);
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);
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);
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);
892 *len=ip_hdr_len+dccp_hdr_len;
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;
907 int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_ack_bits);
909 memset(buffer, 0, 1500);
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
921 ip4hdr->protocol=IPPROTO_DCCP;
922 memcpy(&ip4hdr->saddr, &parms.src_addr.ipv4->sin_addr, sizeof(parms.src_addr.ipv4->sin_addr));
924 ip4hdr->tot_len=htons(ip_hdr_len+dccp_hdr_len);
925 ip4hdr->ttl=parms.ttl;
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);
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));
943 dhdr->dccph_checksum=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);
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;
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);
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);
968 len=ip_hdr_len+dccp_hdr_len;
971 if(parms.ip_type==AF_INET){
972 addrlen=sizeof(struct sockaddr_in);
974 addrlen=sizeof(struct sockaddr_in6);
976 if(sendto(socket, &buffer, len, MSG_DONTWAIT,(struct sockaddr*)parms.dest_addr.gen,addrlen)<0){
978 dbgprintf(0,"Error: sendto failed\n");
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;
995 int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_reset);
997 memset(buffer, 0, 1500);
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
1009 ip4hdr->protocol=IPPROTO_DCCP;
1010 memcpy(&ip4hdr->saddr, &parms.src_addr.ipv4->sin_addr, sizeof(parms.src_addr.ipv4->sin_addr));
1012 ip4hdr->tot_len=htons(ip_hdr_len+dccp_hdr_len);
1013 ip4hdr->ttl=parms.ttl;
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);
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);
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;
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);
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);
1060 len=ip_hdr_len+dccp_hdr_len;
1063 if(parms.ip_type==AF_INET){
1064 addrlen=sizeof(struct sockaddr_in);
1066 addrlen=sizeof(struct sockaddr_in6);
1068 if(sendto(socket, &buffer, len, MSG_DONTWAIT,(struct sockaddr*)parms.dest_addr.gen,addrlen)<0){
1070 dbgprintf(0,"Error: sendto failed\n");
1076 int logPacket(int req_seq, int packet_seq){
1077 struct request *tmp;
1079 /*Add new request to queue*/
1080 tmp=malloc(sizeof(struct request));
1082 dbgprintf(0,"Error: Can't allocate Memory!\n");
1089 tmp->packet_seq=packet_seq;
1090 tmp->request_seq=req_seq;
1091 tmp->reply_type=UNKNOWN;
1092 gettimeofday(&tmp->sent,NULL);
1094 if(queue.head==NULL){
1095 queue.head=queue.tail=tmp;
1097 queue.head->prev=tmp;
1098 tmp->next=queue.head;
1102 /*Update Statistics*/
1103 if(ping_stats.requests_sent==0){
1104 gettimeofday(&ping_stats.start,NULL);
1106 ping_stats.requests_sent++;
1110 int logResponse(ipaddr_ptr_t *src, int seq, int type){
1111 struct request *cur;
1115 if(queue.tail==NULL){
1116 dbgprintf(1,"Response received but no requests sent!\n");
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);
1128 if(type<DEST_UNREACHABLE && type!=UNKNOWN){
1133 cur->reply_type=type;
1140 dbgprintf(1,"Response received but no requests sent with sequence number %i!\n", seq);
1144 diff=(cur->reply.tv_usec + 1000000*cur->reply.tv_sec) - (cur->sent.tv_usec + 1000000*cur->sent.tv_sec);
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]);
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]);
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),
1164 printf("%s from %s : seq=%i\n",response_label[type],
1165 inet_ntop(parms.ip_type, (void*)&src->ipv6->sin6_addr, pbuf, 1000),
1170 /*Update statistics*/
1171 if(type<DEST_UNREACHABLE && type!=UNKNOWN){
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++;
1177 ping_stats.errors++;
1179 if(diff < ping_stats.rtt_min || ping_stats.rtt_min==0){
1180 ping_stats.rtt_min=diff;
1182 if(diff > ping_stats.rtt_max){
1183 ping_stats.rtt_max=diff;
1187 ping_stats.errors++;
1189 gettimeofday(&ping_stats.stop,NULL);
1194 struct request *cur;
1195 struct request *tmp;
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));
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);
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,
1228 printf("rtt min/avg/max = %.1f/%.1f/%.1f ms\n",
1229 ping_stats.rtt_min,ping_stats.rtt_avg,ping_stats.rtt_max);
1236 /*Usage information for program*/
1239 dbgprintf(0, "dccpping: [-d] [-6|-4] [-c count] [-p port] [-i interval] [-t ttl] [-S srcaddress] remote_host\n");
1243 /*Program will probably be run setuid, so be extra careful*/
1244 void sanitize_environment()
1246 #if defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE)
1249 extern char **environ;
1255 void dbgprintf(int level, const char *fmt, ...)
1259 va_start(args, fmt);
1260 vfprintf(stderr, fmt, args);