#include "checksums.h"
-/*Use the DCCP source port to multiplex DCCP Ping streams by PID*/
-#define DCCP_SERVICE_CODE 0x50455246
+#define DEFAULT_SERVICE_CODE 1885957735
#define DEFAULT_PORT 33434
-#define DCCPPING_VERSION 1.0
+
+#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*/
struct sockaddr_in6 *ipv6;
} ipaddr_ptr_t;
-/*Possible Responses to a Request*/
-enum responses{
+/*Possible Responses*/
+enum response_type{
UNKNOWN=0,
- RESET,
- RESPONSE,
- SYNC,
- DEST_UNREACHABLE,
- TTL_EXPIRATION,
- TOO_BIG,
- PARAMETER_PROBLEM,
- DCCP_ERROR
+ 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"
+};
+
+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"
};
-/*Output strings corresponding to enum responses*/
-static const 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)",
-"Protocol Error (DCCP Reset)"
+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 request_seq;
int num_errors;
struct timeval sent;
struct timeval reply;
- enum responses reply_type;
+ enum response_type reply_type;
struct request *next;
struct request *prev;
};
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;
};
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*/
};
void buildRequestPacket(unsigned char* buffer, int *len, int seq);
void updateRequestPacket(unsigned char* buffer, int *len, int seq);
int logPacket(int req_seq, int packet_seq);
-int logResponse(ipaddr_ptr_t *src, int seq, int type);
+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[])
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.dccp_socket=-1;
parms.no_resolve=0;
parms.hostname=NULL;
+ parms.service_code=DEFAULT_SERVICE_CODE;
sanitize_environment();
- while ((c = getopt(argc, argv, "64vhnc:p:i:dt:S:")) != -1) {
+ while ((c = getopt(argc, argv, "64vVhnc:p:i:t:S:s:")) != -1) {
switch (c) {
case '6':
parms.ip_type=AF_INET6;
exit(1);
}
break;
- case 'd':
+ case 'v':
debug++;
break;
case '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':
+ case 'V':
version();
break;
case 'h':
struct sockaddr_in* iv42;
int addrlen;
int err;
+ int opt;
/*Lookup destination Address*/
memset(&hint,0,sizeof(struct addrinfo));
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){
if (logPacket(request_seq,packet_seq)<0){
dbgprintf(0,"Error: Couldn't record request!\n");
}
- if(parms.ip_type==AF_INET){
- dbgprintf(1, "Sending DCCP Request to %s\n",
- addr2str(&parms.dest_addr,0));
- }else{
- dbgprintf(1, "Sending DCCP Request to %s\n",
- addr2str(&parms.dest_addr,0));
- }
+ 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=parms.interval/1000;
updateRequestPacket(sbuffer,&slen, packet_seq);
}
+ printStats();
+
close(rs);
close(is4);
close(is6);
}
if(rcv_addr.gen->sa_family!=parms.ip_type){ //confirm IP type
- dbgprintf(1, "DCCP packet on %s. Tossing.\n", (parms.ip_type==AF_INET) ? "IPv4" : "IPv6");
+ dbgprintf(2, "DCCP packet on %s. Tossing.\n", (parms.ip_type==AF_INET) ? "IPv4" : "IPv6");
free(rcv_addr.gen);
return;
}
/*IPv4*/
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(1,"DCCP packet from 3rd host\n");
+ 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;
}
/*IPv6*/
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(1,"DCCP packet from 3rd host\n");
+ 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;
}
/*DCCP checks*/
dhdr=(struct dccp_hdr*)ptr;
if(dhdr->dccph_sport!=htons(parms.dest_port)){
- dbgprintf(1,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport));
+ dbgprintf(2,"DCCP packet with wrong Source Port (%i)\n", ntohs(dhdr->dccph_sport));
free(rcv_addr.gen);
return;
}
if(dhdr->dccph_dport!=htons(parms.src_port)){
- dbgprintf(1,"DCCP packet with wrong Destination Port\n");
+ dbgprintf(2,"DCCP packet with wrong Destination Port\n");
free(rcv_addr.gen);
return;
}
/*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, "Tossing DCCP Reset packet that's small!\n");
+ 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));
/*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), RESET);
- }else{
- logResponse(&rcv_addr, ntohl(dhdr_re->dccph_reset_ack.dccph_ack_nr_low), DCCP_ERROR);
+ 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, "Tossing DCCP Response packet that's too small!\n");
+ 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);
+ 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, "Tossing DCCP Sync/SyncAck packet that's too small!\n");
+ 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);
+ logResponse(&rcv_addr,ntohl(dhdr_sync->dccph_ack_nr_low),DCCP_SYNC,0,0);
/*DCCP socket opened in getAddresses() will send Reset*/
}
struct dccp_hdr_ext *dhdre;
struct iphdr* ip4hdr;
struct iphdr* iph;
- int type;
/*Memory for socket address*/
rcv_addr_len=sizeof(struct sockaddr_storage);
if(rlen < sizeof(struct icmphdr)+sizeof(struct iphdr)){ //check packet size
- dbgprintf(1, "Packet smaller than possible ICMPv4 packet!\n");
+ dbgprintf(2, "Packet smaller than possible ICMPv4 packet!\n");
free(rcv_addr.gen);
return;
}
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(rlen<sizeof(struct icmphdr)+2*sizeof(struct iphdr)+4){
- dbgprintf(1, "Tossing ICMPv4 packet that's too small to contain DCCP header!\n");
+ dbgprintf(2, "Tossing ICMPv4 packet that's too small to contain DCCP header!\n");
free(rcv_addr.gen);
return;
}
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(1,"Tossing ICMPv4 packet because the embedded IPv4 source address isn't us\n");
+ dbgprintf(2,"Tossing ICMPv4 packet because the embedded IPv4 source address isn't us\n");
free(rcv_addr.gen);
return;
}
if(memcmp(&parms.dest_addr.ipv4->sin_addr,&ip4hdr->daddr,sizeof(parms.dest_addr.ipv4->sin_addr))!=0){
/*Destination address doesn't match*/
- dbgprintf(1,"Tossing ICMPv4 packet because the embedded IPv4 destination address isn't our target\n");
+ 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(1,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n");
+ dbgprintf(2,"Tossing ICMPv4 packet because the embedded packet isn't DCCP\n");
free(rcv_addr.gen);
return;
}
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(1,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP destination port\n");
+ 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(parms.src_port)){
/*DCCP Source Ports don't match*/
- dbgprintf(1,"Tossing ICMPv4 packet because the embedded packet doesn't have our DCCP source port\n");
+ 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+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(rlen<sizeof(struct icmphdr)+2*sizeof(struct iphdr)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)){
- logResponse(&rcv_addr,-1,type);
+ logResponse(&rcv_addr,-1,ICMPv4,icmp4->type,icmp4->code);
}else{
- logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),type);
+ logResponse(&rcv_addr,ntohl(dhdre->dccph_seq_low),ICMPv4,icmp4->type,icmp4->code);
}
free(rcv_addr.gen);
return;
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);
}
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;
}
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(rlen<sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr)+sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)){
- dbgprintf(1, "Tossing ICMPv6 packet that's too small to contain DCCP header!\n");
+ dbgprintf(2, "Tossing ICMPv6 packet that's too small to contain DCCP header!\n");
free(rcv_addr.gen);
return;
}
/*Decode IPv6 header*/
ip6hdr=(struct ip6_hdr*)(rbuffer+sizeof(struct icmp6_hdr));
if(memcmp(&parms.src_addr.ipv6->sin6_addr,&ip6hdr->ip6_src,sizeof(parms.src_addr.ipv6->sin6_addr))!=0){
- dbgprintf(1,"Tossing ICMPv6 packet because the embedded IPv6 source address isn't us\n");
+ 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(&parms.dest_addr.ipv6->sin6_addr,&ip6hdr->ip6_dst,sizeof(parms.dest_addr.ipv6->sin6_addr))!=0){
/*Destination address doesn't match*/
- dbgprintf(1,"Tossing ICMPv6 packet because the embedded IPv6 destination address isn't our target\n");
+ 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(1,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n");
+ dbgprintf(2,"Tossing ICMPv6 packet because the embedded packet isn't DCCP\n");
free(rcv_addr.gen);
return;
}
dhdr=(struct dccp_hdr*)(rbuffer+sizeof(struct icmp6_hdr)+sizeof(struct ip6_hdr));
if(dhdr->dccph_dport!=htons(parms.dest_port)){
/*DCCP Destination Ports don't match*/
- dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP destination port\n");
+ 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(parms.src_port)){
/*DCCP Source Ports don't match*/
- dbgprintf(1,"Tossing ICMPv6 packet because the embedded packet doesn't have our DCCP source port\n");
+ 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;
}
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(DCCP_SERVICE_CODE);
+ dhdrr->dccph_req_service=htonl(parms.service_code);
/*Checksums*/
if(parms.ip_type==AF_INET){
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;
+ 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;
}
while(cur!=NULL){
if(cur->packet_seq==seq){
gettimeofday(&cur->reply,NULL);
- if(cur->num_replies>0){
- printf("Duplicate packet detected! (%i)\n",cur->request_seq);
- }
- if(type<DEST_UNREACHABLE && type!=UNKNOWN){
+ if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
cur->num_replies++;
}else{
cur->num_errors++;
if(cur==NULL){
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",response_label[type],addr2str(src,0));
+ printf("%s from %s\n",get_error_string(type,v1,v2),addr2str(src,0));
ping_stats.errors++;
return 0;
}else{
- dbgprintf(1,"Response received but no requests sent with sequence number %i!\n", seq);
+ 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(type<DEST_UNREACHABLE && type!=UNKNOWN){
- printf( "Response from %s : seq=%i time=%.1fms status=%s\n",
- addr2str(src,0),cur->request_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{
+ printf( "Response from %s : seq=%i time=%.1fms status=%s\n",
+ addr2str(src,0),cur->request_seq, diff/1000.0,response_good[type]);
+ }
}else{
- printf("%s from %s : seq=%i\n",response_label[type],addr2str(src,0),cur->request_seq);
+
+ printf("%s from %s : seq=%i\n",get_error_string(type,v1,v2),addr2str(src,0),cur->request_seq);
}
/*Update statistics*/
- if(type<DEST_UNREACHABLE && type!=UNKNOWN){
+ if((type==DCCP_RESET && v1==3) || type==DCCP_RESPONSE || type==DCCP_SYNC){
/*Good Response*/
if(cur->num_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;
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;
}
void sigHandler(){
- int diff;
- double ploss;
+ /*Exit Quickly*/
+ parms.count=0;
+}
- /*Print Stats*/
- gettimeofday(&ping_stats.stop,NULL);
- printf("-----------%s PING STATISTICS-----------\n",parms.hostname);
+void printStats(){
+ int diff;
+ double ploss, rtt_avg, rtt_avg2, rtt_mdev;
+ /*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;
- ploss=(1.0*(ping_stats.requests_sent-ping_stats.replies_received)/ping_stats.requests_sent*1.0)*100;
- printf("%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);
- printf("rtt min/avg/max = %.1f/%.1f/%.1f ms\n",
- ping_stats.rtt_min,ping_stats.rtt_avg,ping_stats.rtt_max);
+ /*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;
+ 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*/
- parms.count=0;
}
char* addr2str(ipaddr_ptr_t *res, int nores){
}
if((ret=getnameinfo(res->gen, size,
addr2str_buf, sizeof (addr2str_buf), 0, 0, NI_NUMERICHOST))<0){
- dbgprintf(0,"Error! %s\n",gai_strerror(ret));
+ dbgprintf(0,"Error: getnameinfo() returned %s\n",gai_strerror(ret));
}
if (parms.no_resolve||nores){
/*Usage information for program*/
void usage()
{
- dbgprintf(0, "dccpping: [-d] [-v] [-h] [-n] [-6|-4] [-c count] [-p port] [-i interval]\n");
- dbgprintf(0, " [-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, " -d Debug. May be repeated for aditional verbosity\n");
- dbgprintf(0, " -v Version information\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");
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;
+}