X-Git-Url: http://sjero.net/git/?p=dccpping;a=blobdiff_plain;f=dccpping.c;h=b71a7e3bb08998aaa0b0be4e00d482e1ae4011a4;hp=53cede84891b37fd3c4eb542e9ff678c638a89b5;hb=HEAD;hpb=0f3f9394e1017cfd5adb67ccd32cee7d2d7657f3 diff --git a/dccpping.c b/dccpping.c index 53cede8..b71a7e3 100644 --- a/dccpping.c +++ b/dccpping.c @@ -1,9 +1,23 @@ /****************************************************************************** -Author: Samuel Jero +Utility to ping hosts using DCCP Request packets to test for DCCP connectivity. + +Copyright (C) 2012 Samuel Jero + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. -Date: 10/2012 +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. -Description: Program to ping hosts using DCCP REQ packets to test for DCCP connectivity. +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Author: Samuel Jero +Date: 11/2012 ******************************************************************************/ #include #include @@ -13,6 +27,7 @@ Description: Program to ping hosts using DCCP REQ packets to test for DCCP conne #include #include #include +#include #include #include #include @@ -30,7 +45,21 @@ Description: Program to ping hosts using DCCP REQ packets to test for DCCP conne #include "checksums.h" +#define DEFAULT_SERVICE_CODE 1885957735 +#define DEFAULT_PORT 33434 + + +#define DCCPPING_VERSION 1.1 #define MAX(x,y) (x>y ? x : y) +extern int errno; +#ifndef NI_IDN +#define NI_IDN 32 +#endif +#ifndef SOL_DCCP +#define SOL_DCCP 269 +#endif + + /*Structure for simpler IPv4/IPv6 Address handling*/ typedef union ipaddr{ struct sockaddr *gen; @@ -38,67 +67,148 @@ typedef union ipaddr{ struct sockaddr_in6 *ipv6; } ipaddr_ptr_t; -enum responses{ +/*Possible Responses*/ +enum response_type{ UNKNOWN=0, - RESET, - RESPONSE, - SYNC, - DEST_UNREACHABLE, - TTL_EXPIRATION, - TOO_BIG, - PARAMETER_PROBLEM + DCCP_RESET, + DCCP_RESPONSE, + DCCP_SYNC, + ICMPv4, + ICMPv6, +}; + +/*Output strings corresponding to Possible Errors*/ +static const char* response_good[] = { + "Unknown", + "Closed Port (Reset)", + "Open Port (Response)", + "Open Port (Sync)", + "ICMPv4", + "ICMPv6" +}; + +static const char* response_dccp_reset[] = { + "Unspecified", + "Closed", + "Aborted", + "No Connection", + "Packet Error", + "Option Error", + "Mandatory Error", + "Connection Refused", + "Bad Service Code", + "Too Busy", + "Bad Init Cookie", + "Aggression Penalty" +}; + +static const char* response_icmpv4_dest_unreach[] = { + "Destination Network Unreachable", + "Destination Host Unreachable", + "Destination Protocol Unreachable", + "Destination Port Unreachable", + "Fragmentation Required", + "Source Routing Failed", + "Destination Network Unknown", + "Destination Host Unknown", + "Source Host Isolated", + "Network Administratively Prohibited", + "Host Administratively Prohibited", + "Network Unreachable for Type of Service", + "Host Unreachable for Type of Service", + "Communication Administratively Prohibited", + "Host Precedence Violation", + "Presedence Cutoff in Effect" +}; + +static const char* response_icmpv4_ttl[] = { + "TTL Expired", + "Fragment Reassembly Failed" }; -char* response_label[]= { -"Unknown", -"Closed Port (Reset)", -"Open Port (Response)", -"Open Port (Sync)", -"Destination Unreachable", -"TTL Expiration", -"Packet Too Big", -"DCCP Not Supported (Parameter Problem)" + +static const char* response_icmpv6_dest_unreach[] = { + "No Route to Destination", + "Communication Administratively Prohibited", + "Beyond Scope of Source Address", + "Address Unreachable", + "Port Unreachable", + "Source Failed Ingress/Eggress Policy", + "Rejected Source Route", + "Error in Source Routing" +}; + +static const char* response_icmpv6_packet_too_big = "Packet Too Big"; + +static const char* response_icmpv6_ttl[] = { + "TTL Expired", + "Fragment Reassembly Failed" +}; + +static const char* response_icmpv6_param_prob[]={ + "Erroneous Header Field", + "Unrecognized Next Header (DCCP not supported)", + "Unrecognized IPv6 Option" }; + + +/*Structure to keep track of information about a request*/ struct request{ - int seq; + int request_seq; + int packet_seq; int num_replies; int num_errors; struct timeval sent; struct timeval reply; - enum responses reply_type; + enum response_type reply_type; struct request *next; struct request *prev; }; +/*Request Queue head structure*/ +struct request_queue{ + struct request *head; + struct request *tail; +}; + +/*Statistics about the requests and replies sent*/ struct stats{ int requests_sent; int replies_received; + int duplicates; int errors; - double rtt_min; - double rtt_avg; - double rtt_max; + long long rtt_min; + long long rtt_sum; + long long rtt_sum2; + long rtt_max; struct timeval start; struct timeval stop; }; -struct request_queue{ - struct request *head; - struct request *tail; +struct params{ + int count; /*Number of pings (-1 is infinity)*/ + int no_resolve; /*1 if we shouldn't resolve IP addresses*/ + int dest_port; /*Destination port*/ + int src_port; /*Source port---used to encode pid*/ + int ttl; /*TTL*/ + long interval; /*Delay between pings in ms*/ + int ip_type; /*IPv4 or IPv6*/ + ipaddr_ptr_t dest_addr; /*Destination Address*/ + ipaddr_ptr_t src_addr; /*Source Address*/ + int dccp_socket; /*DCCP Socket used to grab src addr/port*/ + char* hostname; /*Originally requested hostname*/ + unsigned int service_code;/*DCCP Service Code*/ }; -int debug=0; /*set to 1 to turn on debugging information*/ -int count=-1; /*Default number of pings (-1 is infinity)*/ -int dest_port=33434; /*Default port*/ -int ttl=64; /*Default TTL*/ -long interval=1000; /*Default delay between pings in ms*/ -int ip_type=AF_UNSPEC; /*IPv4 or IPv6*/ -ipaddr_ptr_t dest_addr; /*Destination Address*/ -ipaddr_ptr_t src_addr; /*Source Address*/ -struct request_queue queue; -struct stats ping_stats; -extern int errno; +int debug=0; /*set to 1 to turn on debugging information*/ +struct request_queue queue; /*Queue of requests to track RTT/duplicate information*/ +struct stats ping_stats; /*Ping Statistics*/ +struct params parms; /*Parameters for ping*/ +char addr2str_buf[1000]; /*Buffer for printing addresses*/ +char addr2nm_buf[1000]; /*Buffer for printing addresses*/ +char addr2both_buf[1000]; /*Buffer for printing addresses*/ void getAddresses(char *src, char* dst); @@ -108,14 +218,18 @@ void handleICMP4packet(int rcv_socket); void handleICMP6packet(int rcv_socket); void buildRequestPacket(unsigned char* buffer, int *len, int seq); void updateRequestPacket(unsigned char* buffer, int *len, int seq); -int logPacket(int seq); -int logResponse(ipaddr_ptr_t *src, int seq, int type); +int logPacket(int req_seq, int packet_seq); +int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2); +const char *get_error_string(int type, int v1, int v2); void clearQueue(); void sigHandler(); +void printStats(); +char* addr2str(ipaddr_ptr_t *res, int nores); void usage(); +void version(); void sanitize_environment(); void dbgprintf(int level, const char *fmt, ...); - +static long llsqrt(long long a); /*Parse commandline options*/ int main(int argc, char *argv[]) @@ -123,54 +237,90 @@ int main(int argc, char *argv[]) char c; char *src=NULL; char *dst=NULL; + char *tmp; + + /*Set Defaults*/ queue.head=NULL; queue.tail=NULL; ping_stats.replies_received=0; ping_stats.requests_sent=0; - ping_stats.rtt_avg=0; + ping_stats.rtt_sum=0; + ping_stats.rtt_sum2=0; + ping_stats.duplicates=0; ping_stats.rtt_max=0; ping_stats.rtt_min=0; ping_stats.errors=0; + parms.count=-1; + parms.dest_port=DEFAULT_PORT; + parms.ttl=64; + parms. interval=1000; + parms.ip_type=AF_UNSPEC; + parms.dest_addr.gen=NULL; + parms.src_addr.gen=NULL; + parms.dccp_socket=-1; + parms.no_resolve=0; + parms.hostname=NULL; + parms.service_code=DEFAULT_SERVICE_CODE; sanitize_environment(); - while ((c = getopt(argc, argv, "64c:p:i:dt:S:")) != -1) { + while ((c = getopt(argc, argv, "64vVhnc:p:i:t:S:s:")) != -1) { switch (c) { case '6': - ip_type=AF_INET6; + parms.ip_type=AF_INET6; break; case '4': - ip_type=AF_INET; + parms.ip_type=AF_INET; break; case 'c': - count = atoi(optarg); - if(count<=0){ + parms.count = atoi(optarg); + if(parms.count<=0){ dbgprintf(0, "Error: count must be positive"); exit(1); } break; case 'p': - dest_port = atoi(optarg); + parms.dest_port = atoi(optarg); break; case 'i': - interval = (long)(atof(optarg) * 1000.0); - if (interval <= 0) { - fprintf(stderr, "Invalid interval\n"); + parms.interval = (long)(atof(optarg) * 1000.0); + if (parms.interval <= 0) { + dbgprintf(0, "Error: Invalid interval\n"); exit(1); } break; - case 'd': + case 'v': debug++; break; + case 'n': + parms.no_resolve=1; + break; case 't': - ttl = atoi(optarg); - if (ttl < 1 || ttl > 255) { - fprintf(stderr, "Invalid TTL\n"); + parms.ttl = atoi(optarg); + if (parms.ttl < 1 || parms.ttl > 255) { + dbgprintf(0,"Error: Invalid TTL\n"); + exit(1); + } + break; + case 's': + parms.service_code=strtol(optarg,&tmp,0); + if(*tmp!='\0'){ + dbgprintf(0,"Error: Invalid Service Code\n"); + exit(1); + } + if(parms.service_code<=0){ + dbgprintf(0, "Error: Service Code MUST be positive"); + exit(1); } break; case 'S': src=optarg; break; + case 'V': + version(); + break; + case 'h': + /*Intentional Fall-through*/ default: usage(); break; @@ -184,9 +334,10 @@ int main(int argc, char *argv[]) usage(); } dst=argv[0]; + parms.hostname=argv[0]; getAddresses(src, dst); - if(src_addr.gen==NULL || dest_addr.gen==NULL){ + if(parms.src_addr.gen==NULL || parms.dest_addr.gen==NULL){ dbgprintf(0,"Error: Can't determine source or destination address\n"); exit(1); } @@ -194,8 +345,9 @@ int main(int argc, char *argv[]) signal(SIGINT, sigHandler); doping(); - free(src_addr.gen); - free(dest_addr.gen); + free(parms.src_addr.gen); + free(parms.dest_addr.gen); + close(parms.dccp_socket); clearQueue(); return 0; } @@ -204,13 +356,18 @@ void getAddresses(char *src, char* dst){ struct addrinfo hint; struct addrinfo *dtmp, *stmp; struct ifaddrs *temp, *cur; - struct sockaddr_in6* iv6; + ipaddr_ptr_t ipv; + struct sockaddr_in6* iv61; + struct sockaddr_in6* iv62; + struct sockaddr_in* iv41; + struct sockaddr_in* iv42; int addrlen; int err; + int opt; /*Lookup destination Address*/ memset(&hint,0,sizeof(struct addrinfo)); - hint.ai_family=ip_type; + hint.ai_family=parms.ip_type; hint.ai_flags=AI_V4MAPPED | AI_ADDRCONFIG; if((err=getaddrinfo(dst,NULL,&hint,&dtmp))!=0){ @@ -222,19 +379,22 @@ void getAddresses(char *src, char* dst){ exit(1); }else{ addrlen=dtmp->ai_addrlen; - hint.ai_family=ip_type=dtmp->ai_family; - dest_addr.gen=malloc(dtmp->ai_addrlen); - if(dest_addr.gen==NULL){ + hint.ai_family=parms.ip_type=dtmp->ai_family; + parms.dest_addr.gen=malloc(dtmp->ai_addrlen); + if(parms.dest_addr.gen==NULL){ dbgprintf(0,"Error: Can't allocate Memory\n"); exit(1); } - memcpy(dest_addr.gen,dtmp->ai_addr,dtmp->ai_addrlen); + memcpy(parms.dest_addr.gen,dtmp->ai_addr,dtmp->ai_addrlen); + parms.dest_addr.gen->sa_family=dtmp->ai_family; } freeaddrinfo(dtmp); /*Get a meaningful source address*/ if(src!=NULL){ /*Use Commandline arg*/ + + /*Convert arg to address*/ if((err=getaddrinfo(src,NULL,&hint,&stmp))!=0){ dbgprintf(0,"Error: Source Address %s is invalid (%s)\n", src, gai_strerror(err)); exit(1); @@ -242,49 +402,111 @@ void getAddresses(char *src, char* dst){ if(stmp==NULL){ dbgprintf(0,"Error: Unknown Host %s\n", dst); exit(1); - }else{ - addrlen=stmp->ai_addrlen; - src_addr.gen=malloc(stmp->ai_addrlen); - if(src_addr.gen==NULL){ - dbgprintf(0,"Error: Can't allocate Memory\n"); - exit(1); - } - memcpy(src_addr.gen,stmp->ai_addr,stmp->ai_addrlen); } - freeaddrinfo(stmp); - }else{ - /*Guess a good source address*/ + + /*Compare to interface addresses*/ getifaddrs(&temp); cur=temp; while(cur!=NULL){ - if(cur->ifa_addr==NULL || cur->ifa_addr->sa_family!=ip_type){ /*Not matching ipv4/ipv6 of dest*/ - cur=cur->ifa_next; - continue; - } - if(cur->ifa_flags & IFF_LOOPBACK){ /*Don't use loopback addresses*/ + if(cur->ifa_addr==NULL || cur->ifa_addr->sa_family!=stmp->ai_family){ + /*Not matching ipv4/ipv6 of dest*/ cur=cur->ifa_next; continue; } - if(cur->ifa_addr!=NULL && cur->ifa_addr->sa_family==AF_INET6){ - iv6=(struct sockaddr_in6*)cur->ifa_addr; - - if(iv6->sin6_scope_id!=0){ /*Not globally valid address, if ipv6*/ - cur=cur->ifa_next; - continue; + if(stmp->ai_family==AF_INET){ + iv41=(struct sockaddr_in*)stmp->ai_addr; + iv42=(struct sockaddr_in*)cur->ifa_addr; + if(memcmp(&iv41->sin_addr,&iv42->sin_addr, sizeof(iv41->sin_addr))==0){ + parms.src_addr.gen=malloc(sizeof(struct sockaddr_storage)); + if(parms.src_addr.gen==NULL){ + dbgprintf(0,"Error: Can't allocate Memory\n"); + exit(1); + } + parms.src_addr.gen->sa_family=parms.ip_type; + memcpy(parms.src_addr.gen,cur->ifa_addr,addrlen); + break; + } + }else{ + iv61=(struct sockaddr_in6*)stmp->ai_addr; + iv62=(struct sockaddr_in6*)cur->ifa_addr; + if(memcmp(&iv61->sin6_addr,&iv62->sin6_addr, sizeof(iv61->sin6_addr))==0){ + parms.src_addr.gen=malloc(sizeof(struct sockaddr_storage)); + if(parms.src_addr.gen==NULL){ + dbgprintf(0,"Error: Can't allocate Memory\n"); + exit(1); + } + parms.src_addr.gen->sa_family=parms.ip_type; + memcpy(parms.src_addr.gen,cur->ifa_addr,addrlen); + break; } } - - src_addr.gen=malloc(sizeof(struct sockaddr_storage)); - if(src_addr.gen==NULL){ - dbgprintf(0,"Error: Can't allocate Memory\n"); - exit(1); - } - src_addr.gen->sa_family=ip_type; - memcpy(src_addr.gen,cur->ifa_addr,addrlen); - //break; cur=cur->ifa_next; } + if(parms.src_addr.gen==NULL){ + ipv.gen=(struct sockaddr*)stmp->ai_addr; + dbgprintf(0,"Error: Source Address %s does not belong to any interface!\n",addr2str(&ipv,1)); + exit(1); + } freeifaddrs(temp); + freeaddrinfo(stmp); + } + + /*Create socket to auto respond for open connections and reserve a source port*/ + parms.dccp_socket=socket(parms.ip_type,SOCK_DCCP, IPPROTO_DCCP); + if(parms.dccp_socket<0){ + dbgprintf(0, "Error: Failed opening DCCP Socket (%s)\n",strerror(errno)); + exit(1); + } + fcntl(parms.dccp_socket, F_SETFL, O_NONBLOCK); + + + if(parms.src_addr.gen==NULL){ + /*Auto-detect source address*/ + parms.src_addr.gen=malloc(sizeof(struct sockaddr_storage)); + if(parms.src_addr.gen==NULL){ + dbgprintf(0,"Error: Can't allocate Memory\n"); + exit(1); + } + memset(parms.src_addr.gen,0,sizeof(struct sockaddr_storage)); + parms.src_addr.gen->sa_family=parms.ip_type; + }else{ + /*Bind to the given source address*/ + if(bind(parms.dccp_socket,parms.src_addr.gen,sizeof(struct sockaddr_storage))<0){ + dbgprintf(0, "Error: Failed bind() on DCCP socket (%s)\n",strerror(errno)); + exit(1); + } + } + opt=htonl(parms.service_code); + if(setsockopt(parms.dccp_socket,SOL_DCCP, DCCP_SOCKOPT_SERVICE,&opt,sizeof(opt))<0){ + dbgprintf(0, "Error: Failed setsockopt() on DCCP socket (%s)\n",strerror(errno)); + exit(1); + } + + /*Connect socket to get source address/port*/ + if(parms.ip_type==AF_INET){ + parms.dest_addr.ipv4->sin_port=htons(parms.dest_port); + }else{ + parms.dest_addr.ipv6->sin6_port=htons(parms.dest_port); + } + if(connect(parms.dccp_socket,parms.dest_addr.gen,sizeof(struct sockaddr_storage))<0){ + if(errno!=EINPROGRESS){ + dbgprintf(0, "Error: Failed connect() on DCCP socket (%s)\n",strerror(errno)); + exit(1); + } + } + + /*Get source address and port number!*/ + addrlen=sizeof(struct sockaddr_storage); + if(getsockname(parms.dccp_socket,parms.src_addr.gen,(socklen_t*)&addrlen)<0){ + dbgprintf(0, "Error: Failed getsockname() on DCCP socket (%s)\n",strerror(errno)); + exit(1); + } + if(parms.ip_type==AF_INET){ + parms.src_port=ntohs(parms.src_addr.ipv4->sin_port); + parms.dest_addr.ipv4->sin_port=0; + }else{ + parms.src_port=ntohs(parms.src_addr.ipv6->sin6_port); + parms.dest_addr.ipv6->sin6_port=0; } return; } @@ -299,26 +521,26 @@ void doping(){ fd_set sel; struct timeval timeout; struct timeval t,delay, add; - char pbuf[1000]; - int seq=1; + int request_seq=1; + int packet_seq; /*Open Sockets*/ - rs=socket(ip_type, SOCK_RAW ,IPPROTO_RAW); + rs=socket(parms.ip_type, SOCK_RAW ,IPPROTO_RAW); if(rs<0){ dbgprintf(0, "Error opening raw socket\n"); exit(1); } - ds=socket(ip_type, SOCK_RAW ,IPPROTO_DCCP); + ds=socket(parms.ip_type, SOCK_RAW ,IPPROTO_DCCP); if(ds<0){ dbgprintf(0, "Error opening raw DCCP socket\n"); exit(1); } - is4=socket(ip_type,SOCK_RAW,IPPROTO_ICMP); + is4=socket(parms.ip_type,SOCK_RAW,IPPROTO_ICMP); if(is4<0){ dbgprintf(0,"Error opening raw ICMPv4 socket\n"); exit(1); } - is6=socket(ip_type,SOCK_RAW,IPPROTO_ICMPV6); + is6=socket(parms.ip_type,SOCK_RAW,IPPROTO_ICMPV6); if(is6<0){ dbgprintf(0,"Error opening raw ICMPv6 socket\n"); exit(1); @@ -326,43 +548,34 @@ void doping(){ /*Build DCCP packet*/ - buildRequestPacket(sbuffer,&slen,seq); - if(ip_type==AF_INET){ + packet_seq=rand(); + buildRequestPacket(sbuffer,&slen,packet_seq); + if(parms.ip_type==AF_INET){ addrlen=sizeof(struct sockaddr_in); }else{ addrlen=sizeof(struct sockaddr_in6); } /*Start Message*/ - if(ip_type==AF_INET){ - dbgprintf(0, "PINGING %s on DCCP port %i\n", - inet_ntop(ip_type, (void*)&dest_addr.ipv4->sin_addr, pbuf, 1000),dest_port); - }else{ - dbgprintf(0, "PINGING %s on DCCP port %i\n", - inet_ntop(ip_type, (void*)&dest_addr.ipv6->sin6_addr, pbuf, 1000),dest_port); - } + printf("PINGING %s (%s) on DCCP port %i\n",parms.hostname, addr2str(&parms.dest_addr,1),parms.dest_port); while(!done){ /*Send Ping*/ - if(sendto(rs, &sbuffer, slen, MSG_DONTWAIT,(struct sockaddr*)dest_addr.gen,addrlen)<0){ + if(sendto(rs, &sbuffer, slen, MSG_DONTWAIT,(struct sockaddr*)parms.dest_addr.gen,addrlen)<0){ if(errno!=EINTR){ - dbgprintf(0,"Error: sendto failed\n"); + dbgprintf(0,"Error: sendto() failed (%s)\n",strerror(errno)); } } - if(count==0){done=1; break;} + if(parms.count==0){done=1; break;} - if (logPacket(seq)<0){ + if (logPacket(request_seq,packet_seq)<0){ dbgprintf(0,"Error: Couldn't record request!\n"); } - if(ip_type==AF_INET){ - dbgprintf(1, "Sending DCCP Request to %s\n",inet_ntop(ip_type, (void*)&dest_addr.ipv4->sin_addr, pbuf, 1000)); - }else{ - dbgprintf(1, "Sending DCCP Request to %s\n",inet_ntop(ip_type, (void*)&dest_addr.ipv6->sin6_addr, pbuf, 1000)); - } + dbgprintf(2, "Sending DCCP Request to %s\n", addr2str(&parms.dest_addr,1)); /*Use select to wait on packets or until interval has passed*/ - add.tv_sec=interval/1000; - add.tv_usec=(interval%1000)*1000; + add.tv_sec=parms.interval/1000; + add.tv_usec=(parms.interval%1000)*1000; gettimeofday(&t,NULL); timeradd(&t,&add,&delay); while(timercmp(&t,&delay,<)){ @@ -379,18 +592,18 @@ void doping(){ dbgprintf(0,"Select() error (%s)\n",strerror(errno)); } } - if(count==0){done=1;break;} + if(parms.count==0){done=1;break;} if(FD_ISSET(ds,&sel)){ /*Data on the DCCP socket*/ handleDCCPpacket(ds,rs); } - if(FD_ISSET(is4,&sel) && ip_type==AF_INET){ + if(FD_ISSET(is4,&sel) && parms.ip_type==AF_INET){ /*Data on the ICMPv4 socket*/ handleICMP4packet(is4); } - if(FD_ISSET(is6,&sel) && ip_type==AF_INET6){ + if(FD_ISSET(is6,&sel) && parms.ip_type==AF_INET6){ /*Data on the ICMPv6 socket*/ handleICMP6packet(is6); } @@ -398,13 +611,16 @@ void doping(){ } /*Update count*/ - if(count>-1){ - count--; + if(parms.count>-1){ + parms.count--; } - seq++; - updateRequestPacket(sbuffer,&slen, seq); + request_seq++; + packet_seq=rand(); + updateRequestPacket(sbuffer,&slen, packet_seq); } + printStats(); + close(rs); close(is4); close(is6); @@ -433,7 +649,7 @@ void handleDCCPpacket(int rcv_socket, int send_socket){ /*Receive Packet*/ rcv_addr_len=sizeof(struct sockaddr_storage); - if((rlen=recvfrom(rcv_socket, &rbuffer, 1000,0,rcv_addr.gen,&rcv_addr_len))<0){ + if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){ if(errno!=EINTR){ dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno)); } @@ -442,23 +658,23 @@ void handleDCCPpacket(int rcv_socket, int send_socket){ return; } - if(rcv_addr.gen->sa_family!=ip_type){ //confirm IP type - dbgprintf(1, "DCCP packet on %s. Tossing.\n", (ip_type==AF_INET) ? "IPv4" : "IPv6"); + if(rcv_addr.gen->sa_family!=parms.ip_type){ //confirm IP type + dbgprintf(2, "DCCP packet on %s. Tossing.\n", (parms.ip_type==AF_INET) ? "IPv4" : "IPv6"); free(rcv_addr.gen); return; } if(rcv_addr.gen->sa_family==AF_INET){ /*IPv4*/ - if(memcmp(&rcv_addr.ipv4->sin_addr,&dest_addr.ipv4->sin_addr, - sizeof(dest_addr.ipv4->sin_addr))!=0){ //not from destination - dbgprintf(1,"DCCP packet from 3rd host\n"); + if(memcmp(&rcv_addr.ipv4->sin_addr,&parms.dest_addr.ipv4->sin_addr, + sizeof(parms.dest_addr.ipv4->sin_addr))!=0){ //not from destination + dbgprintf(2,"DCCP packet from 3rd host\n"); free(rcv_addr.gen); return; } if(rlen < sizeof(struct dccp_hdr)+sizeof(struct iphdr)){ //check packet size - dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n"); + dbgprintf(2, "Packet smaller than possible DCCP packet received on DCCP socket\n"); free(rcv_addr.gen); return; } @@ -466,15 +682,15 @@ void handleDCCPpacket(int rcv_socket, int send_socket){ ptr=rbuffer+iph->ihl*4; }else{ /*IPv6*/ - if(memcmp(&rcv_addr.ipv6->sin6_addr, &dest_addr.ipv6->sin6_addr, - sizeof(dest_addr.ipv6->sin6_addr))!=0){ //not from destination - dbgprintf(1,"DCCP packet from 3rd host\n"); + if(memcmp(&rcv_addr.ipv6->sin6_addr, &parms.dest_addr.ipv6->sin6_addr, + sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){ //not from destination + dbgprintf(2,"DCCP packet from 3rd host\n"); free(rcv_addr.gen); return; } if(rlen < sizeof(struct dccp_hdr)){ //check packet size - dbgprintf(1, "Packet smaller than possible DCCP packet received on DCCP socket\n"); + dbgprintf(2, "Packet smaller than possible DCCP packet received on DCCP socket\n"); free(rcv_addr.gen); return; } @@ -483,13 +699,13 @@ void handleDCCPpacket(int rcv_socket, int send_socket){ /*DCCP checks*/ dhdr=(struct dccp_hdr*)ptr; - if(dhdr->dccph_sport!=htons(dest_port)){ - dbgprintf(1,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport)); + if(dhdr->dccph_sport!=htons(parms.dest_port)){ + dbgprintf(2,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport)); free(rcv_addr.gen); return; } - if(dhdr->dccph_dport!=htons(dest_port)){ - dbgprintf(1,"DCCP packet with wrong Destination Port\n"); + if(dhdr->dccph_dport!=htons(parms.src_port)){ + dbgprintf(2,"DCCP packet with wrong Destination Port\n"); free(rcv_addr.gen); return; } @@ -497,30 +713,40 @@ void handleDCCPpacket(int rcv_socket, int send_socket){ /*Pick Response*/ if(dhdr->dccph_type==DCCP_PKT_RESET){ if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_reset)){ - dbgprintf(1, "Error: Reset packet too small!"); + dbgprintf(2, "Tossing DCCP Reset packet that's small!\n"); return; } dhdr_re=(struct dccp_hdr_reset*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)); - logResponse(&rcv_addr, ntohl(dhdr_re->dccph_reset_ack.dccph_ack_nr_low), RESET); + + /*Log*/ + if(dhdr_re->dccph_reset_code==DCCP_RESET_CODE_NO_CONNECTION){ + logResponse(&rcv_addr, ntohl(dhdr_re->dccph_reset_ack.dccph_ack_nr_low), DCCP_RESET,dhdr_re->dccph_reset_code,0); + } /*Nothing else to do*/ } if(dhdr->dccph_type==DCCP_PKT_RESPONSE){ if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_response)){ - dbgprintf(1, "Error: Response packet too small!"); + dbgprintf(2, "Tossing DCCP Response packet that's too small!\n"); return; } + + /*Log*/ dhdr_rp=(struct dccp_hdr_response*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)); - logResponse(&rcv_addr,ntohl(dhdr_rp->dccph_resp_ack.dccph_ack_nr_low),RESPONSE); - /*TODO:Send Close back*/ + logResponse(&rcv_addr,ntohl(dhdr_rp->dccph_resp_ack.dccph_ack_nr_low),DCCP_RESPONSE,0,0); + + /*DCCP socket opened in getAddresses() will send Reset*/ } if(dhdr->dccph_type==DCCP_PKT_SYNC || dhdr->dccph_type==DCCP_PKT_SYNCACK){ if(rlen < (ptr-rbuffer)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_ack_bits)){ - dbgprintf(1, "Error: Response packet too small!"); + dbgprintf(2, "Tossing DCCP Sync/SyncAck packet that's too small!\n"); return; } + + /*Log*/ dhdr_sync=(struct dccp_hdr_ack_bits*)(ptr+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)); - logResponse(&rcv_addr,ntohl(dhdr_sync->dccph_ack_nr_low),SYNC); - /*TODO:Send Reset*/ + logResponse(&rcv_addr,ntohl(dhdr_sync->dccph_ack_nr_low),DCCP_SYNC,0,0); + + /*DCCP socket opened in getAddresses() will send Reset*/ } free(rcv_addr.gen); @@ -535,7 +761,7 @@ void handleICMP4packet(int rcv_socket){ struct dccp_hdr *dhdr; struct dccp_hdr_ext *dhdre; struct iphdr* ip4hdr; - int type; + struct iphdr* iph; /*Memory for socket address*/ rcv_addr_len=sizeof(struct sockaddr_storage); @@ -546,7 +772,7 @@ void handleICMP4packet(int rcv_socket){ } /*Receive Packet*/ - if((rlen=recvfrom(rcv_socket, &rbuffer, 1000,0,rcv_addr.gen,&rcv_addr_len))<0){ + if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){ if(errno!=EINTR){ dbgprintf(0, "Error on receive from ICMPv4 socket (%s)\n",strerror(errno)); } @@ -555,66 +781,72 @@ void handleICMP4packet(int rcv_socket){ return; } - if(rlen < sizeof(struct icmphdr)){ //check packet size - dbgprintf(1, "Packet smaller than possible ICMPv4 packet!\n"); + iph=(struct iphdr*)rbuffer; + + + if(rlen < sizeof(struct icmphdr)+sizeof(struct iphdr)){ //check packet size + dbgprintf(2, "Packet smaller than possible ICMPv4 packet!\n"); free(rcv_addr.gen); return; } - icmp4=(struct icmphdr*)rbuffer; + icmp4=(struct icmphdr*)(rbuffer+iph->ihl*4); if(icmp4->type!=ICMP_DEST_UNREACH && icmp4->type!=ICMP_TIME_EXCEEDED){ //check icmp types - dbgprintf(1, "Tossing ICMPv4 packet of type %i\n", icmp4->type); + dbgprintf(2, "Tossing ICMPv4 packet of type %i\n", icmp4->type); free(rcv_addr.gen); return; } /*Check packet size again*/ - if(rlensin_addr,&ip4hdr->saddr,sizeof(src_addr.ipv4->sin_addr))!=0){ + ip4hdr=(struct iphdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)); + if(memcmp(&parms.src_addr.ipv4->sin_addr,&ip4hdr->saddr,sizeof(parms.src_addr.ipv4->sin_addr))!=0){ /*Source address doesn't match*/ + dbgprintf(2,"Tossing ICMPv4 packet because the embedded IPv4 source address isn't us\n"); free(rcv_addr.gen); return; } - if(memcmp(&dest_addr.ipv4->sin_addr,&ip4hdr->daddr,sizeof(dest_addr.ipv4->sin_addr))!=0){ + if(memcmp(&parms.dest_addr.ipv4->sin_addr,&ip4hdr->daddr,sizeof(parms.dest_addr.ipv4->sin_addr))!=0){ /*Destination address doesn't match*/ + dbgprintf(2,"Tossing ICMPv4 packet because the embedded IPv4 destination address isn't our target\n"); free(rcv_addr.gen); return; } if(ip4hdr->protocol!=IPPROTO_DCCP){ /*Not DCCP!*/ + dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n"); free(rcv_addr.gen); return; } /*Decode DCCP header*/ - dhdr=(struct dccp_hdr*)(rbuffer+sizeof(struct icmphdr)+ip4hdr->ihl*4); - if(dhdr->dccph_dport!=htons(dest_port)){ + dhdr=(struct dccp_hdr*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)+ip4hdr->ihl*4); + if(dhdr->dccph_dport!=htons(parms.dest_port)){ /*DCCP Destination Ports don't match*/ + dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP destination port\n"); free(rcv_addr.gen); return; } - if(dhdr->dccph_sport!=htons(dest_port)){ + if(dhdr->dccph_sport!=htons(parms.src_port)){ /*DCCP Source Ports don't match*/ + dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP source port\n"); free(rcv_addr.gen); return; } - dhdre=(struct dccp_hdr_ext*)(rbuffer+sizeof(struct icmphdr)+ip4hdr->ihl*4+sizeof(struct dccp_hdr)); + dhdre=(struct dccp_hdr_ext*)(rbuffer+iph->ihl*4+sizeof(struct icmphdr)+ip4hdr->ihl*4+sizeof(struct dccp_hdr)); /*Log*/ - if(icmp4->type==ICMP_DEST_UNREACH){ - type=DEST_UNREACHABLE; - } - if(icmp4->type==ICMP_TIME_EXCEEDED){ - type=TTL_EXPIRATION; + if(rlentype,icmp4->code); + }else{ + logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),ICMPv4,icmp4->type,icmp4->code); } - logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),type); free(rcv_addr.gen); return; } @@ -628,7 +860,6 @@ void handleICMP6packet(int rcv_socket){ struct ip6_hdr* ip6hdr; struct dccp_hdr *dhdr; struct dccp_hdr_ext *dhdre; - int type; /*Memory for socket address*/ rcv_addr_len=sizeof(struct sockaddr_storage); @@ -639,12 +870,12 @@ void handleICMP6packet(int rcv_socket){ } /*Receive Packet*/ - if((rlen=recvfrom(rcv_socket, &rbuffer, 1000,0,rcv_addr.gen,&rcv_addr_len))<0){ + if((rlen=recvfrom(rcv_socket, &rbuffer, 1500,0,rcv_addr.gen,&rcv_addr_len))<0){ dbgprintf(0, "Error on receive from ICMPv6 socket (%s)\n",strerror(errno)); } if(rlen < sizeof(struct icmp6_hdr)){ //check packet size - dbgprintf(1, "Packet smaller than possible ICMPv6 packet!\n"); + dbgprintf(2, "Packet smaller than possible ICMPv6 packet!\n"); free(rcv_addr.gen); return; } @@ -652,66 +883,57 @@ void handleICMP6packet(int rcv_socket){ icmp6=(struct icmp6_hdr*)rbuffer; if(icmp6->icmp6_type!=ICMP6_DST_UNREACH && icmp6->icmp6_type!=ICMP6_PACKET_TOO_BIG && icmp6->icmp6_type!=ICMP6_TIME_EXCEEDED && icmp6->icmp6_type!=ICMP6_PARAM_PROB){ //check icmp types - dbgprintf(1, "Tossing ICMPv6 packet of type %i\n", icmp6->icmp6_type); + dbgprintf(2, "Tossing ICMPv6 packet of type %i\n", icmp6->icmp6_type); free(rcv_addr.gen); return; } /*Check packet size again*/ if(rlensin6_addr,&ip6hdr->ip6_src,sizeof(src_addr.ipv6->sin6_addr))!=0){ + if(memcmp(&parms.src_addr.ipv6->sin6_addr,&ip6hdr->ip6_src,sizeof(parms.src_addr.ipv6->sin6_addr))!=0){ + dbgprintf(2,"Tossing ICMPv6 packet because the embedded IPv6 source address isn't us\n"); /*Source address doesn't match*/ free(rcv_addr.gen); return; } - if(memcmp(&dest_addr.ipv6->sin6_addr,&ip6hdr->ip6_dst,sizeof(dest_addr.ipv6->sin6_addr))!=0){ + if(memcmp(&parms.dest_addr.ipv6->sin6_addr,&ip6hdr->ip6_dst,sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){ /*Destination address doesn't match*/ + dbgprintf(2,"Tossing ICMPv6 packet because the embedded IPv6 destination address isn't our target\n"); free(rcv_addr.gen); return; } if(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt!=IPPROTO_DCCP){ /*Not DCCP!*/ + dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n"); free(rcv_addr.gen); return; } /*Decode DCCP header*/ dhdr=(struct dccp_hdr*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)); - if(dhdr->dccph_dport!=htons(dest_port)){ + if(dhdr->dccph_dport!=htons(parms.dest_port)){ /*DCCP Destination Ports don't match*/ + dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP destination port\n"); free(rcv_addr.gen); return; } - if(dhdr->dccph_sport!=htons(dest_port)){ + if(dhdr->dccph_sport!=htons(parms.src_port)){ /*DCCP Source Ports don't match*/ + dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP source port\n"); free(rcv_addr.gen); return; } dhdre=(struct dccp_hdr_ext*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr)); - - /*Log*/ - if(icmp6->icmp6_type==ICMP6_DST_UNREACH){ - type=DEST_UNREACHABLE; - } - if(icmp6->icmp6_type==ICMP6_PACKET_TOO_BIG){ - type=TOO_BIG; - } - if(icmp6->icmp6_type==ICMP6_TIME_EXCEEDED){ - type=TTL_EXPIRATION; - } - if(icmp6->icmp6_type==ICMP6_PARAM_PROB){ - type=PARAMETER_PROBLEM; - } - logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),type); + logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low), ICMPv6, icmp6->icmp6_type,icmp6->icmp6_code); free(rcv_addr.gen); return; } @@ -735,27 +957,27 @@ void buildRequestPacket(unsigned char* buffer, int *len, int seq){ /*IP header*/ ip4hdr=NULL; - if(ip_type==AF_INET){ + if(parms.ip_type==AF_INET){ ip_hdr_len=sizeof(struct iphdr); ip4hdr=(struct iphdr*)buffer; ip4hdr->check=htons(0); - memcpy(&ip4hdr->daddr, &dest_addr.ipv4->sin_addr, sizeof(dest_addr.ipv4->sin_addr)); + memcpy(&ip4hdr->daddr, &parms.dest_addr.ipv4->sin_addr, sizeof(parms.dest_addr.ipv4->sin_addr)); ip4hdr->frag_off=htons(0); ip4hdr->id=htons(1);//first ip4hdr->ihl=5; ip4hdr->protocol=IPPROTO_DCCP; - memcpy(&ip4hdr->saddr, &src_addr.ipv4->sin_addr, sizeof(src_addr.ipv4->sin_addr)); + memcpy(&ip4hdr->saddr, &parms.src_addr.ipv4->sin_addr, sizeof(parms.src_addr.ipv4->sin_addr)); ip4hdr->tos=0; ip4hdr->tot_len=htons(ip_hdr_len+dccp_hdr_len); - ip4hdr->ttl=ttl; + ip4hdr->ttl=parms.ttl; ip4hdr->version=4; }else{ ip_hdr_len=sizeof(struct ip6_hdr); ip6hdr=(struct ip6_hdr*)buffer; - memcpy(&ip6hdr->ip6_dst, &dest_addr.ipv6->sin6_addr, sizeof(dest_addr.ipv6->sin6_addr)); - memcpy(&ip6hdr->ip6_src, &src_addr.ipv6->sin6_addr, sizeof(src_addr.ipv6->sin6_addr)); + memcpy(&ip6hdr->ip6_dst, &parms.dest_addr.ipv6->sin6_addr, sizeof(parms.dest_addr.ipv6->sin6_addr)); + memcpy(&ip6hdr->ip6_src, &parms.src_addr.ipv6->sin6_addr, sizeof(parms.src_addr.ipv6->sin6_addr)); ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_flow=htonl(6<<28); //version, traffic class, flow label - ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim=ttl; + ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim=parms.ttl; ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt=IPPROTO_DCCP; ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen=htons(dccp_hdr_len); } @@ -768,26 +990,26 @@ void buildRequestPacket(unsigned char* buffer, int *len, int seq){ dhdr->dccph_checksum=0; dhdr->dccph_cscov=0; dhdr->dccph_doff=dccp_hdr_len/4; - dhdr->dccph_dport=htons(dest_port); + dhdr->dccph_dport=htons(parms.dest_port); dhdr->dccph_reserved=0; - dhdr->dccph_sport=htons(dest_port); + dhdr->dccph_sport=htons(parms.src_port); dhdr->dccph_x=1; dhdr->dccph_type=DCCP_PKT_REQUEST; dhdr->dccph_seq2=htonl(0); //Reserved if using 48 bit sequence numbers dhdr->dccph_seq=htonl(0); //High 16bits of sequence number. Always make 0 for simplicity. dhdre->dccph_seq_low=htonl(seq); - dhdrr->dccph_req_service= htonl(0x50455246); + dhdrr->dccph_req_service=htonl(parms.service_code); /*Checksums*/ - if(ip_type==AF_INET){ + if(parms.ip_type==AF_INET){ dhdr->dccph_checksum=ipv4_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len, - (unsigned char*) &dest_addr.ipv4->sin_addr, - (unsigned char*)&src_addr.ipv4->sin_addr, IPPROTO_DCCP); + (unsigned char*) &parms.dest_addr.ipv4->sin_addr, + (unsigned char*)&parms.src_addr.ipv4->sin_addr, IPPROTO_DCCP); ip4hdr->check=ipv4_chksum(buffer,ip_hdr_len); }else{ dhdr->dccph_checksum=ipv6_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len, - (unsigned char*) &dest_addr.ipv6->sin6_addr, - (unsigned char*)&src_addr.ipv6->sin6_addr, IPPROTO_DCCP); + (unsigned char*) &parms.dest_addr.ipv6->sin6_addr, + (unsigned char*)&parms.src_addr.ipv6->sin6_addr, IPPROTO_DCCP); } *len=ip_hdr_len+dccp_hdr_len; return; @@ -803,7 +1025,7 @@ void updateRequestPacket(unsigned char* buffer, int *len, int seq){ /*IP header*/ ip4hdr=NULL; - if(ip_type==AF_INET){ + if(parms.ip_type==AF_INET){ ip_hdr_len=sizeof(struct iphdr); ip4hdr=(struct iphdr*)buffer; ip4hdr->check=htons(0); @@ -819,21 +1041,21 @@ void updateRequestPacket(unsigned char* buffer, int *len, int seq){ dhdre->dccph_seq_low=htonl(seq); /*Checksums*/ - if(ip_type==AF_INET){ + if(parms.ip_type==AF_INET){ dhdr->dccph_checksum=ipv4_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len, - (unsigned char*) &dest_addr.ipv4->sin_addr, - (unsigned char*)&src_addr.ipv4->sin_addr, IPPROTO_DCCP); + (unsigned char*) &parms.dest_addr.ipv4->sin_addr, + (unsigned char*)&parms.src_addr.ipv4->sin_addr, IPPROTO_DCCP); ip4hdr->check=ipv4_chksum(buffer,ip_hdr_len); }else{ dhdr->dccph_checksum=ipv6_pseudohdr_chksum((buffer+ip_hdr_len), dccp_hdr_len, - (unsigned char*) &dest_addr.ipv6->sin6_addr, - (unsigned char*)&src_addr.ipv6->sin6_addr, IPPROTO_DCCP); + (unsigned char*) &parms.dest_addr.ipv6->sin6_addr, + (unsigned char*)&parms.src_addr.ipv6->sin6_addr, IPPROTO_DCCP); } *len=ip_hdr_len+dccp_hdr_len; return; } -int logPacket(int seq){ +int logPacket(int req_seq, int packet_seq){ struct request *tmp; /*Add new request to queue*/ @@ -846,7 +1068,8 @@ int logPacket(int seq){ tmp->prev=NULL; tmp->num_replies=0; tmp->num_errors=0; - tmp->seq=seq; + tmp->packet_seq=packet_seq; + tmp->request_seq=req_seq; tmp->reply_type=UNKNOWN; gettimeofday(&tmp->sent,NULL); @@ -866,25 +1089,21 @@ int logPacket(int seq){ return 0; } -int logResponse(ipaddr_ptr_t *src, int seq, int type){ +int logResponse(ipaddr_ptr_t *src, int seq, int type, int v1, int v2){ struct request *cur; - double diff; - char pbuf[1000]; + long long diff; if(queue.tail==NULL){ - dbgprintf(1,"Response received but no requests sent!\n"); + dbgprintf(2,"Response received but no requests sent!\n"); return -1; } /*Locate request*/ cur=queue.tail; while(cur!=NULL){ - if(cur->seq==seq){ + if(cur->packet_seq==seq){ gettimeofday(&cur->reply,NULL); - if(cur->num_replies>0){ - dbgprintf(0,"Duplicate packet detected! (%i)\n", seq); - } - if(typenum_replies++; }else{ cur->num_errors++; @@ -896,44 +1115,42 @@ int logResponse(ipaddr_ptr_t *src, int seq, int type){ } if(cur==NULL){ - dbgprintf(1,"Response received but no requests sent with sequence number %i!\n", seq); - return -1; + if(parms.ip_type==AF_INET && seq==-1){ + /*IPv4 didn't include enough of the packet to get sequence numbers!*/ + printf("%s from %s\n",get_error_string(type,v1,v2),addr2str(src,0)); + ping_stats.errors++; + return 0; + }else{ + dbgprintf(2,"Response received but no requests sent with sequence number %i!\n", seq); + return -1; + } } diff=(cur->reply.tv_usec + 1000000*cur->reply.tv_sec) - (cur->sent.tv_usec + 1000000*cur->sent.tv_sec); - diff=diff/1000.0; /*Print Message*/ - if(typeipv4->sin_addr, pbuf, 1000), - seq, diff,response_label[type]); + if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){ + if(debug==0){ + printf( "Response from %s : seq=%i time=%.1fms\n",addr2str(src,0),cur->request_seq, diff/1000.0); }else{ - dbgprintf(0, "Response from %s : seq=%i time=%.1fms status=%s\n", - inet_ntop(ip_type, (void*)&src->ipv6->sin6_addr, pbuf, 1000), - seq, diff,response_label[type]); + printf( "Response from %s : seq=%i time=%.1fms status=%s\n", + addr2str(src,0),cur->request_seq, diff/1000.0,response_good[type]); } }else{ - if(ip_type==AF_INET){ - dbgprintf(0, "%s from %s : seq=%i\n",response_label[type], - inet_ntop(ip_type, (void*)&src->ipv4->sin_addr, pbuf, 1000), - seq); - }else{ - dbgprintf(0, "%s from %s : seq=%i\n",response_label[type], - inet_ntop(ip_type, (void*)&src->ipv6->sin6_addr, pbuf, 1000), - seq); - } + + printf("%s from %s : seq=%i\n",get_error_string(type,v1,v2),addr2str(src,0),cur->request_seq); } /*Update statistics*/ - if(typenum_replies==1){ - ping_stats.rtt_avg=((ping_stats.replies_received*ping_stats.rtt_avg)+(diff))/(ping_stats.replies_received+1); + ping_stats.rtt_sum+=diff; + ping_stats.rtt_sum2+=(diff*diff); ping_stats.replies_received++; }else{ - ping_stats.errors++; + printf("Duplicate packet detected! (%i)\n",cur->request_seq); + ping_stats.duplicates++; } if(diff < ping_stats.rtt_min || ping_stats.rtt_min==0){ ping_stats.rtt_min=diff; @@ -949,6 +1166,55 @@ int logResponse(ipaddr_ptr_t *src, int seq, int type){ return 0; } +const char *get_error_string(int type, int v1, int v2){ + const char *label=NULL; + switch(type){ + case DCCP_RESET: + if(v1>11){label=NULL;break;} + label=response_dccp_reset[v1]; + break; + case ICMPv4: + switch(v1){ + case 3: + if(v2>15){label=NULL;break;} + label=response_icmpv4_dest_unreach[v2]; + break; + case 11: + if(v2>1){label=NULL;break;} + label=response_icmpv4_ttl[v2]; + break; + default: + label=NULL; + break; + } + break; + case ICMPv6: + switch(v1){ + case 1: + if(v2>7){label=NULL;break;} + label=response_icmpv6_dest_unreach[v2]; + break; + case 2: + if(v2>0){label=NULL;break;} + label=response_icmpv6_packet_too_big; + break; + case 3: + if(v2>1){label=NULL;break;} + label=response_icmpv6_ttl[v2]; + break; + case 4: + if(v2>2){label=NULL;break;} + label=response_icmpv6_param_prob[v2]; + break; + default: + label=NULL; + break; + } + break; + } + return label; +} + void clearQueue(){ struct request *cur; struct request *tmp; @@ -965,37 +1231,97 @@ void clearQueue(){ } void sigHandler(){ - char pbuf[1000]; + /*Exit Quickly*/ + parms.count=0; +} + +void printStats(){ int diff; - double ploss; + double ploss, rtt_avg, rtt_avg2, rtt_mdev; - /*Print Stats*/ - if(ip_type==AF_INET){ - dbgprintf(0,"-----------%s PING STATISTICS-----------\n", - inet_ntop(ip_type, (void*)&dest_addr.ipv4->sin_addr, pbuf, 1000)); - }else if(ip_type==AF_INET6){ - dbgprintf(0,"-----------%s PING STATISTICS-----------\n", - inet_ntop(ip_type, (void*)&dest_addr.ipv6->sin6_addr, pbuf, 1000)); + /*Compute Stats*/ + if(ping_stats.replies_received>0){ + rtt_avg=ping_stats.rtt_sum/(ping_stats.replies_received*1.0); + rtt_avg2=ping_stats.rtt_sum2/(ping_stats.replies_received*1.0); + rtt_mdev=llsqrt(rtt_avg2 - (rtt_avg*rtt_avg)); + }else{ + rtt_avg=0; + rtt_avg2=0; + rtt_mdev=0; } diff=(ping_stats.stop.tv_usec + 1000000*ping_stats.stop.tv_sec) - (ping_stats.start.tv_usec + 1000000*ping_stats.start.tv_sec); diff=diff/1000.0; + + /*Print Stats*/ + gettimeofday(&ping_stats.stop,NULL); + printf("-----------%s PING STATISTICS-----------\n",parms.hostname); ploss=(1.0*(ping_stats.requests_sent-ping_stats.replies_received)/ping_stats.requests_sent*1.0)*100; - dbgprintf(0,"%i packets transmitted, %i received, %i errors, %.2f%% loss, time %ims\n", - ping_stats.requests_sent,ping_stats.replies_received,ping_stats.errors, - ploss,diff); - dbgprintf(0,"rtt min/avg/max = %.1f/%.1f/%.1f ms\n", - ping_stats.rtt_min,ping_stats.rtt_avg,ping_stats.rtt_max); + printf("%i packets transmitted, %i received, ",ping_stats.requests_sent,ping_stats.replies_received); + if(ping_stats.duplicates>0){ + printf("%i duplicates, ",ping_stats.duplicates); + } + if(ping_stats.errors>0){ + printf("%i errors, ",ping_stats.errors); + } + printf("%.2f%% loss, time %ims\n",ploss,diff); + if(ping_stats.replies_received>ping_stats.requests_sent){ + printf("+Somebody is creating packets out of thing air!\n"); + } + printf("rtt min/avg/max/mdev = %.1f/%.1f/%.1f/%.1f ms\n", + ping_stats.rtt_min/1000.0,rtt_avg/1000.0,ping_stats.rtt_max/1000.0,rtt_mdev/1000.0); +} - /*Exit Quickly*/ - count=0; +char* addr2str(ipaddr_ptr_t *res, int nores){ + int size; + int ret; + if (!res->gen->sa_family) + return NULL; + + if(res->gen->sa_family==AF_INET){ + size=sizeof(struct sockaddr_in); + }else if(res->gen->sa_family==AF_INET6){ + size=sizeof(struct sockaddr_in6); + }else{ + return NULL; + } + if((ret=getnameinfo(res->gen, size, + addr2str_buf, sizeof (addr2str_buf), 0, 0, NI_NUMERICHOST))<0){ + dbgprintf(0,"Error: getnameinfo() returned %s\n",gai_strerror(ret)); + } + + if (parms.no_resolve||nores){ + return addr2str_buf; + }else{ + addr2nm_buf[0] = '\0'; + getnameinfo(res->gen, size, + addr2nm_buf, sizeof (addr2nm_buf), 0, 0, NI_IDN); + snprintf(addr2both_buf,1000," %s (%s)", addr2nm_buf[0] ? addr2nm_buf : addr2str_buf, addr2str_buf); + return addr2both_buf; + } + return NULL; } /*Usage information for program*/ void usage() { - dbgprintf(0, "dccpping: [-d] [-6|-4] [-c count] [-p port] [-i interval] [-t ttl] [-S srcaddress] remote_host\n"); + dbgprintf(0, "dccpping: [-v] [-V] [-h] [-n] [-6|-4] [-c count] [-p port] [-i interval]\n"); + dbgprintf(0, " [-t ttl] [-s service_code] [-S srcaddress] remote_host\n"); + dbgprintf(0, "\n"); + dbgprintf(0, " -v Verbose. May be repeated for aditional verbosity.\n"); + dbgprintf(0, " -V Version information\n"); + dbgprintf(0, " -h Help\n"); + dbgprintf(0, " -n Numeric output only\n"); + dbgprintf(0, " -6 Force IPv6 mode\n"); + dbgprintf(0, " -4 Force IPv4 mode\n"); + exit(0); +} + +void version(){ + dbgprintf(0, "dccpping version %.1f\nCopyright (C) 2012 Samuel Jero \n", DCCPPING_VERSION); + dbgprintf(0, "This program comes with ABSOLUTELY NO WARRANTY.\n"); + dbgprintf(0, "This is free software, and you are welcome to\nredistribute it under certain conditions.\n"); exit(0); } @@ -1020,3 +1346,21 @@ void dbgprintf(int level, const char *fmt, ...) va_end(args); } } + +/*Square Root function for longs*/ +/*Borrowed from iputils/ping_common.c*/ +/* http://www.skbuff.net/iputils/ */ +static long llsqrt(long long a) +{ + long long prev = ~((long long)1 << 63); + long long x = a; + + if (x > 0) { + while (x < prev) { + prev = x; + x = (x+(a/x))/2; + } + } + + return (long)x; +}