From df049b5d7a0c33e5b30bb361dc4143eba499bf3f Mon Sep 17 00:00:00 2001 From: Samuel Jero Date: Sun, 28 Oct 2012 16:40:48 -0400 Subject: [PATCH] Use select to wait for new packets and delay between pings. Separate out processing of DCCP and ICMP packets. Decided to use raw sockets instead of libpcap because it allows me to ignore link layer and means I don't have to use threads. --- Makefile | 2 +- checksums.c | 8 ++ dccpping.c | 319 ++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 278 insertions(+), 51 deletions(-) diff --git a/Makefile b/Makefile index bdc67ff..4feba9a 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ CFLAGS= -O2 -Wall -Werror -g --std=gnu99 # for HP, I'm told that you need: # LDLIBS = -lstr # everybody else (that I know of) just needs: -# LDLIBS = +# LDLIBS = LDLIBS = CC = gcc diff --git a/checksums.c b/checksums.c index a33d0f4..a0bc464 100644 --- a/checksums.c +++ b/checksums.c @@ -9,6 +9,14 @@ Description: IPv4 and IPv6 Checksum code #include #include "checksums.h" +/*Stupid Solaris*/ +#ifndef u_int32_t +#define u_int32_t uint32_t +#endif +#ifndef u_int16_t +#define u_int16_t uint16_t +#endif + //Pseudo Headers for checksums struct ip6_pseudo_hdr{ unsigned char src[IP6_ADDR_LEN]; diff --git a/dccpping.c b/dccpping.c index 608bc9b..d2656f9 100644 --- a/dccpping.c +++ b/dccpping.c @@ -10,24 +10,26 @@ Description: Program to ping hosts using DCCP REQ packets to test for DCCP conne #include #include #include -#include #include -#include +#include +#include #include #include -#include +#include #include #include #include -#include +#include +#include #include -#include +#include #include -#include +#include +#include #include "checksums.h" -extern int errno; +#define MAX(x,y) (x>y ? x : y) typedef union ipaddr{ struct sockaddr *gen; struct sockaddr_in *ipv4; @@ -43,11 +45,15 @@ long interval=1000; /*Default delay between pings in ms*/ int ip_type=AF_UNSPEC; /*IPv4 or IPv6*/ ipaddr_ptr_t dest_addr; ipaddr_ptr_t src_addr; +extern int errno; void getAddresses(char *src, char* dst); void doping(); -void buildPacket(unsigned char* buffer, int *len); +void handleDCCPpacket(int rcv_socket, int send_socket); +void handleICMPpacket(int rcv_socket); +void buildRequestPacket(unsigned char* buffer, int *len); +void updateRequestPacket(unsigned char* buffer, int *len); void dbgprintf(int level, const char *fmt, ...); void sanitize_environment(); void usage(); @@ -99,7 +105,6 @@ int main(int argc, char *argv[]) break; case 'S': src=optarg; - //r = inet_aton(optarg, &src_ip); break; default: usage(); @@ -116,6 +121,10 @@ int main(int argc, char *argv[]) dst=argv[0]; getAddresses(src, dst); + if(src_addr.gen==NULL || dest_addr.gen==NULL){ + dbgprintf(0,"Error: Can't determine source or destination address\n"); + exit(1); + } doping(); @@ -220,41 +229,31 @@ void doping(){ int addrlen; int slen=1500; unsigned char sbuffer[slen]; - unsigned char rbuffer[1000]; + fd_set sel; + struct timeval timeout; + struct timeval t,delay, add; char pbuf[1000]; - struct dccp_hdr *dhdr; - struct sockaddr_storage rcv_addr; - socklen_t rcv_addr_len=sizeof(struct sockaddr_storage); - struct sockaddr_in6 *tmp; - //int opt; - int rlen; - - dbgprintf(0, "In doping()\n"); /*Open Sockets*/ - rs=socket(ip_type, SOCK_RAW | SOCK_NONBLOCK ,IPPROTO_RAW); + rs=socket(ip_type, SOCK_RAW ,IPPROTO_RAW); if(rs<0){ dbgprintf(0, "Error opening raw socket\n"); exit(1); } - ds=socket(ip_type, SOCK_RAW | SOCK_NONBLOCK ,IPPROTO_DCCP); + ds=socket(ip_type, SOCK_RAW ,IPPROTO_DCCP); if(ds<0){ dbgprintf(0, "Error opening raw DCCP socket\n"); exit(1); } - is=socket(ip_type,SOCK_RAW | SOCK_NONBLOCK ,IPPROTO_ICMP); + is=socket(ip_type,SOCK_RAW,IPPROTO_ICMP); if(is<0){ dbgprintf(0,"Error opening raw ICMP socket\n"); exit(1); } - /*opt=((unsigned char*)&dhdr->dccph_checksum) - &sbuffer[0]; - if (setsockopt(ds, IPPROTO_IPV6, IPV6_CHECKSUM, &opt, sizeof(opt)) < 0){ - dbgprintf(0, "Error setting up checksums on raw DCCP socket (%s)\n", strerror(errno)); - exit(1); - }*/ - buildPacket(sbuffer,&slen); + /*Build DCCP packet*/ + buildRequestPacket(sbuffer,&slen); if(ip_type==AF_INET){ addrlen=sizeof(struct sockaddr_in); }else{ @@ -262,41 +261,43 @@ void doping(){ } while(!done){ - + /*Send Ping*/ if(sendto(rs, &sbuffer, slen, MSG_DONTWAIT,(struct sockaddr*)dest_addr.gen,addrlen)<0){ dbgprintf(0,"Error: sendto failed\n"); } - if(ip_type==AF_INET){ dbgprintf(0, "Sending DCCP Request to %s\n",inet_ntop(ip_type, (void*)&dest_addr.ipv4->sin_addr, pbuf, 1000)); }else{ dbgprintf(0, "Sending DCCP Request to %s\n",inet_ntop(ip_type, (void*)&dest_addr.ipv6->sin6_addr, pbuf, 1000)); } - rcv_addr_len=sizeof(struct sockaddr_storage); - if((rlen=recvfrom(ds, &rbuffer, 1000,MSG_DONTWAIT,(struct sockaddr*)&rcv_addr,&rcv_addr_len))<0){ - if(errno!=EAGAIN){ - dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno)); - } - } - if(rlen>0){ - if(rlen< sizeof(struct dccp_hdr)){ - dbgprintf(0,"Received Non-DCCP data!\n"); + /*Use select to wait on packets or until interval has passed*/ + add.tv_sec=interval/1000; + add.tv_usec=(interval%1000)*1000; + gettimeofday(&t,NULL); + timeradd(&t,&add,&delay); + FD_ZERO(&sel); + FD_SET(ds,&sel); + FD_SET(is,&sel); + while(timercmp(&t,&delay,<)){ + timersub(&delay,&t,&timeout); + if(select(MAX(ds+1,is+1),&sel, NULL,NULL,&timeout)<0){ + dbgprintf(0,"Select() error\n"); } - dhdr=(struct dccp_hdr*)rbuffer; - tmp=(struct sockaddr_in6*)&rcv_addr; - dbgprintf(0,"Response from %s (%i)\n", inet_ntop(ip_type, (void*)&tmp->sin6_addr, pbuf, 1000),dhdr->dccph_type); - } - if((rlen=recvfrom(is, &rbuffer, 1000,MSG_DONTWAIT,(struct sockaddr*)&rcv_addr,&rcv_addr_len))<0){ - if(errno!=EAGAIN){ - dbgprintf(0, "Error on receive from ICMP socket (%s)\n",strerror(errno)); + if(FD_ISSET(ds,&sel)){ + /*Data on the DCCP socket*/ + handleDCCPpacket(ds,rs); + } - } - if(rlen>0){ - dbgprintf(0,"Received ICMP data!\n"); + if(FD_ISSET(is,&sel)){ + /*Data on the ICMP socket*/ + handleICMPpacket(is); + } + gettimeofday(&t,NULL); } + /*Update count*/ if(count>-1){ count--; } @@ -304,7 +305,8 @@ void doping(){ done=1; break; } - sleep(interval/1000); + + updateRequestPacket(sbuffer,&slen); } close(rs); @@ -312,7 +314,176 @@ void doping(){ close(ds); } -void buildPacket(unsigned char* buffer, int *len){ +void handleDCCPpacket(int rcv_socket, int send_socket){ + int rlen=1500; + unsigned char rbuffer[rlen]; + char pbuf[1000]; + ipaddr_ptr_t rcv_addr; + socklen_t rcv_addr_len; + struct dccp_hdr *dhdr; + + /*Memory for socket address*/ + rcv_addr_len=sizeof(struct sockaddr_storage); + rcv_addr.gen=malloc(rcv_addr_len); + if(rcv_addr.gen==NULL){ + dbgprintf(0,"Error: Can't Allocate Memory!\n"); + exit(1); + } + + /*Receive Packet*/ + rcv_addr_len=sizeof(struct sockaddr_storage); + if((rlen=recvfrom(rcv_socket, &rbuffer, 1000,0,rcv_addr.gen,&rcv_addr_len))<0){ + dbgprintf(0, "Error on receive from DCCP socket (%s)\n",strerror(errno)); + } + + 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"); + 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"); + free(rcv_addr.gen); + return; + } + + /*Check IP source*/ + 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"); + free(rcv_addr.gen); + return; + } + }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"); + free(rcv_addr.gen); + return; + } + } + + /*DCCP checks*/ + dhdr=(struct dccp_hdr*)rbuffer; + if(dhdr->dccph_sport!=htons(dest_port)){ + dbgprintf(1,"DCCP packet with wrong Source Port\n"); + free(rcv_addr.gen); + return; + } + if(dhdr->dccph_dport!=htons(dest_port)){ + dbgprintf(1,"DCCP packet with wrong Destination Port\n"); + free(rcv_addr.gen); + return; + } + + /*Print Message*/ + if(dhdr->dccph_type==DCCP_PKT_RESET){ + /*Print Message*/ + if(ip_type==AF_INET){ + dbgprintf(0, "Got DCCP RESET from %s\n",inet_ntop(ip_type, (void*)&rcv_addr.ipv4->sin_addr, pbuf, 1000)); + }else{ + dbgprintf(0, "Got DCCP RESET from %s\n",inet_ntop(ip_type, (void*)&rcv_addr.ipv6->sin6_addr, pbuf, 1000)); + } + /*Nothing else to do*/ + } + if(dhdr->dccph_type==DCCP_PKT_RESPONSE){ + /*Print Message*/ + if(ip_type==AF_INET){ + dbgprintf(0, "Got DCCP RESPONSE from %s\n",inet_ntop(ip_type, (void*)&rcv_addr.ipv4->sin_addr, pbuf, 1000)); + }else{ + dbgprintf(0, "Got DCCP RESPONSE from %s\n",inet_ntop(ip_type, (void*)&rcv_addr.ipv6->sin6_addr, pbuf, 1000)); + } + /*Send Close back*/ + } + if(dhdr->dccph_type==DCCP_PKT_SYNC || dhdr->dccph_type==DCCP_PKT_SYNCACK){ + /*Print Message*/ + if(ip_type==AF_INET){ + dbgprintf(0, "Got DCCP SYNC from %s\n",inet_ntop(ip_type, (void*)&rcv_addr.ipv4->sin_addr, pbuf, 1000)); + }else{ + dbgprintf(0, "Got DCCP SYNC from %s\n",inet_ntop(ip_type, (void*)&rcv_addr.ipv6->sin6_addr, pbuf, 1000)); + } + /*Send Reset*/ + } + + free(rcv_addr.gen); +} + +void handleICMPpacket(int rcv_socket){ + int rlen=1500; + unsigned char rbuffer[rlen]; + char pbuf[1000]; + ipaddr_ptr_t rcv_addr; + socklen_t rcv_addr_len; + struct icmphdr *icmp4; + struct icmp6_hdr *icmp6; + + /*Memory for socket address*/ + rcv_addr_len=sizeof(struct sockaddr_storage); + rcv_addr.gen=malloc(rcv_addr_len); + if(rcv_addr.gen==NULL){ + dbgprintf(0,"Error: Can't Allocate Memory!\n"); + exit(1); + } + + /*Receive Packet*/ + if((rlen=recvfrom(rcv_socket, &rbuffer, 1000,0,rcv_addr.gen,&rcv_addr_len))<0){ + dbgprintf(0, "Error on receive from ICMP socket (%s)\n",strerror(errno)); + } + + if(rcv_addr.gen->sa_family!=ip_type){ //confirm IP type + dbgprintf(1, "ICMP packet on %s. Tossing.\n", (ip_type==AF_INET) ? "IPv4" : "IPv6"); + free(rcv_addr.gen); + return; + } + + if(rcv_addr.gen->sa_family==AF_INET){ + /*IPv4*/ + if(rlen < sizeof(struct icmphdr)){ //check packet size + dbgprintf(1, "Packet smaller than possible ICMP packet!\n"); + free(rcv_addr.gen); + return; + } + + icmp4=(struct icmphdr*)rbuffer; + if(icmp4->type!=3 && icmp4->type!=11){ //check icmp types + dbgprintf(1, "Tossing ICMP packet of type %i\n", icmp4->type); + free(rcv_addr.gen); + return; + } + + /*Print Message*/ + dbgprintf(0, "Got ICMPv4 type %i from %s\n", icmp4->type, + inet_ntop(ip_type, (void*)&rcv_addr.ipv4->sin_addr, pbuf, 1000)); + + }else{ + /*IPv6*/ + if(rlen < sizeof(struct icmp6_hdr)){ //check packet size + dbgprintf(1, "Packet smaller than possible ICMP packet!\n"); + free(rcv_addr.gen); + return; + } + + icmp6=(struct icmp6_hdr*)rbuffer; + if(icmp6->icmp6_type!=1 && icmp6->icmp6_type!=2 && icmp6->icmp6_type!=3 + && icmp6->icmp6_type!=4){ //check icmp types + dbgprintf(1, "Tossing ICMP packet of type %i\n", icmp6->icmp6_type); + free(rcv_addr.gen); + return; + } + + /*Print Message*/ + dbgprintf(0, "Got ICMPv6 type %i from %s\n", icmp6->icmp6_type, + inet_ntop(ip_type, (void*)&rcv_addr.ipv6->sin6_addr, pbuf, 1000)); + } + + free(rcv_addr.gen); +} + +void buildRequestPacket(unsigned char* buffer, int *len){ struct dccp_hdr *dhdr; struct dccp_hdr_ext *dhdre; struct dccp_hdr_request *dhdrr; @@ -323,6 +494,11 @@ void buildPacket(unsigned char* buffer, int *len){ int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request); int seq=8; + if(*len < dccp_hdr_len+sizeof(struct ip6_hdr)){ + dbgprintf(0, "Error: Insufficient buffer space\n"); + exit(1); + } + memset(buffer, 0, *len); /*IP header*/ @@ -385,6 +561,49 @@ void buildPacket(unsigned char* buffer, int *len){ return; } +void updateRequestPacket(unsigned char* buffer, int *len){ + struct dccp_hdr *dhdr; + struct dccp_hdr_ext *dhdre; + struct iphdr* ip4hdr; + + int ip_hdr_len; + int dccp_hdr_len=sizeof(struct dccp_hdr)+sizeof(struct dccp_hdr_ext)+sizeof(struct dccp_hdr_request); + int tmp; + + /*IP header*/ + ip4hdr=NULL; + if(ip_type==AF_INET){ + ip_hdr_len=sizeof(struct iphdr); + ip4hdr=(struct iphdr*)buffer; + ip4hdr->check=htons(0); + tmp=ntohs(ip4hdr->id); + ip4hdr->id=htons(tmp+1); + }else{ + ip_hdr_len=sizeof(struct ip6_hdr); + } + + /*DCCP header*/ + dhdr=(struct dccp_hdr*)(buffer+ip_hdr_len); + dhdre=(struct dccp_hdr_ext*)(buffer+ip_hdr_len+sizeof(struct dccp_hdr)); + dhdr->dccph_checksum=0; + tmp=ntohl(dhdre->dccph_seq_low); + dhdre->dccph_seq_low=htonl(tmp+1); + + /*Checksums*/ + if(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); + 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); + } + *len=ip_hdr_len+dccp_hdr_len; + return; +} + /*Usage information for program*/ void usage() { -- 2.39.2