implement raw ipv6 recv, refactor peek_raw

This commit is contained in:
wangyu-
2018-07-23 13:52:36 -05:00
parent 80d21e56c7
commit 73daa12db1
6 changed files with 217 additions and 113 deletions

View File

@@ -190,7 +190,7 @@ int init_raw_socket()
g_ip_id_counter=get_true_random_number()%65535;
if(lower_level==0)
{
raw_send_fd = socket(AF_INET , SOCK_RAW , IPPROTO_RAW);// IPPROTO_TCP??
raw_send_fd = socket(raw_ip_version , SOCK_RAW , IPPROTO_RAW);// IPPROTO_TCP??
if(raw_send_fd == -1) {
mylog(log_fatal,"Failed to create raw_send_fd\n");
@@ -606,11 +606,25 @@ int send_raw_packet(raw_info_t &raw_info,const char * packet,int len)
int ret;
if(lower_level==0)
{
struct sockaddr_in sin={0};
sin.sin_family = AF_INET;
//sin.sin_port = htons(info.dst_port); //dont need this
sin.sin_addr.s_addr = send_info.new_dst_ip.v4;
ret = sendto(raw_send_fd, packet, len , 0, (struct sockaddr *) &sin, sizeof (sin));
if(raw_ip_version==AF_INET)
{
struct sockaddr_in sin={0};
sin.sin_family = raw_ip_version;
//sin.sin_port = htons(info.dst_port); //dont need this
sin.sin_addr.s_addr = send_info.new_dst_ip.v4;
ret = sendto(raw_send_fd, packet, len , 0, (struct sockaddr *) &sin, sizeof (sin));
}
else if(raw_ip_version==AF_INET6)
{
struct sockaddr_in6 sin={0};
sin.sin6_family = raw_ip_version;
//sin.sin_port = htons(info.dst_port); //dont need this
sin.sin6_addr = send_info.new_dst_ip.v6;
ret = sendto(raw_send_fd, packet, len , 0, (struct sockaddr *) &sin, sizeof (sin));
}else
{
assert(0==1);
}
}
else
@@ -686,72 +700,7 @@ int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
return send_raw_packet(raw_info,send_raw_ip_buf,ip_tot_len);
}
int peek_raw(packet_info_t &peek_info)
{
//static char peek_raw_buf[buf_len];
assert(g_packet_buf_cnt==1);
//g_packet_buf_cnt--;
char * peek_raw_buf=g_packet_buf;
int recv_len=g_packet_buf_len;
char *ip_begin=peek_raw_buf+link_level_header_len;
//struct sockaddr saddr={0};
//socklen_t saddr_size=sizeof(saddr);
//int recv_len = recvfrom(raw_recv_fd, peek_raw_buf,max_data_len, MSG_PEEK ,&saddr , &saddr_size);//change max_data_len to something smaller,we only need header here
iphdr * iph = (struct iphdr *) (ip_begin);
//mylog(log_info,"recv_len %d\n",recv_len);
if(recv_len<int(sizeof(iphdr)))
{
mylog(log_trace,"failed here %d %d\n",recv_len,int(sizeof(iphdr)));
mylog(log_trace,"%s\n ",strerror(errno));
return -1;
}
peek_info.new_src_ip.v4=iph->saddr;
unsigned short iphdrlen =iph->ihl*4;
char *payload=ip_begin+iphdrlen;
//mylog(log_info,"protocol %d\n",iph->protocol);
switch(raw_mode)
{
case mode_faketcp:
{
if(iph->protocol!=IPPROTO_TCP)
{
mylog(log_trace,"failed here");
return -1;
}
struct tcphdr *tcph=(tcphdr *)payload;
if(recv_len<int( iphdrlen+sizeof(tcphdr) ))
{
mylog(log_trace,"failed here");
return -1;
}
peek_info.src_port=ntohs(tcph->source);
peek_info.syn=tcph->syn;
break;
}
case mode_udp:
{
if(iph->protocol!=IPPROTO_UDP) return -1;
struct udphdr *udph=(udphdr *)payload;
if(recv_len<int(iphdrlen+sizeof(udphdr)))
return -1;
peek_info.src_port=ntohs(udph->source);
break;
}
case mode_icmp:
{
if(iph->protocol!=IPPROTO_ICMP) return -1;
struct icmphdr *icmph=(icmphdr *)payload;
if(recv_len<int( iphdrlen+sizeof(icmphdr) ))
return -1;
peek_info.src_port=ntohs(icmph->id);
break;
}
default:return -1;
}
return 0;
}
int pre_recv_raw_packet()
{
assert(g_packet_buf_cnt==0);
@@ -782,21 +731,29 @@ int discard_raw_packet()
g_packet_buf_cnt--;
return 0;
}
int recv_raw_packet(char * &packet,int &len)
int recv_raw_packet(char * &packet,int &len,int peek)
{
assert(g_packet_buf_cnt==1);
g_packet_buf_cnt--;
if(!peek)
g_packet_buf_cnt--;
if(g_packet_buf_len<int(link_level_header_len))
{
mylog(log_trace,"packet len %d shorter than link_level_header_len %d\n");
mylog(log_trace,"packet len %d shorter than link_level_header_len %d\n",g_packet_buf_len,int(link_level_header_len));
return -1;
}
if(link_level_header_len ==14&&(g_packet_buf[12]!=8||g_packet_buf[13]!=0))
if(link_level_header_len ==14)
{
mylog(log_trace,"not an ipv4 packet!\n");
return -1;
unsigned char a=g_packet_buf[12];
unsigned char b=g_packet_buf[13];
if(! ((a==0x08&&b==0x00) ||(a==0x86&&b==0xdd)) )
{
mylog(log_trace,"not an ipv4 or ipv6 packet!\n");
return -1;
}
}
packet=g_packet_buf+int(link_level_header_len);
len=g_packet_buf_len-int(link_level_header_len);
@@ -808,45 +765,93 @@ int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen)
//static char recv_raw_ip_buf[buf_len];
int raw_packet_len;
if(recv_raw_packet(raw_packet_buf,raw_packet_len)!=0) return -1;
if(recv_raw_packet(raw_packet_buf,raw_packet_len,raw_info.peek)!=0) return -1;
const packet_info_t &send_info=raw_info.send_info;
//const packet_info_t &send_info=raw_info.send_info;
packet_info_t &recv_info=raw_info.recv_info;
iphdr * iph;
ip6_hdr * ip6h;
int flag=0;
//int recv_len = recvfrom(raw_recv_fd, recv_raw_ip_buf, max_data_len+1, flag ,(sockaddr*)&saddr , &saddr_size);
char *ip_begin=raw_packet_buf; //14 is eth net header
iph = (struct iphdr *) (ip_begin);
recv_info.new_src_ip.v4=iph->saddr;
recv_info.new_dst_ip.v4=iph->daddr;
recv_info.protocol=iph->protocol;
if(raw_packet_len<1)
{
mylog(log_trace,"raw_packet_len <1, dropped\n");
return -1;
}
iph = (struct iphdr *) (ip_begin); //just use the iphdr here to get the first 4bit
ip6h= (struct ip6_hdr *) (ip_begin);
if(raw_ip_version==AF_INET)
{
if(iph->version!=4)
{
mylog(log_trace,"expect ipv4 packet, but got something else: %02x\n",iph->version);
return -1;
}
if(raw_packet_len<(int)sizeof(iphdr))
{
mylog(log_trace,"raw_packet_len<sizeof(iphdr)\n");
return -1;
}
}
else
{
assert(raw_ip_version==AF_INET6);
if(iph->version!=6)
{
mylog(log_trace,"expect ipv6 packet, but got something else: %02x\n",iph->version);
return -1;
}
if(raw_packet_len<(int)sizeof(ip6_hdr))
{
mylog(log_trace,"raw_packet_len<sizeof(ip6_hdr)\n");
return -1;
}
}
if(lower_level)
{
memcpy(&recv_info.addr_ll,&g_sockaddr.ll,sizeof(recv_info.addr_ll));
}
if(bind_addr_used && recv_info.new_dst_ip.v4!=bind_addr.inner.ipv4.sin_addr.s_addr)
if(bind_addr_used && !recv_info.new_dst_ip.equal(bind_addr))
{
mylog(log_trace,"bind adress doenst match, dropped\n");
//printf(" bind adress doenst match, dropped\n");
return -1;
}
unsigned short iphdrlen;
int ip_len;
if(raw_ip_version==AF_INET)
{
recv_info.new_src_ip.v4=iph->saddr;
recv_info.new_dst_ip.v4=iph->daddr;
recv_info.protocol=iph->protocol;
iphdrlen =iph->ihl*4;
ip_len=ntohs(iph->tot_len);
}
else
{
//todo flow id
recv_info.new_src_ip.v6=ip6h->ip6_src;
recv_info.new_dst_ip.v6=ip6h->ip6_dst;
iphdrlen=40;
recv_info.protocol=ip6h->ip6_nxt; //todo handle extension headers;
ip_len=ntohs(ip6h->ip6_plen);
}
if (!(iph->ihl > 0 && iph->ihl <=60)) {
mylog(log_trace,"iph ihl error\n");
return -1;
}
int ip_len=ntohs(iph->tot_len);
//if (!(iph->ihl > 0 && iph->ihl <=60)) {
// mylog(log_trace,"iph ihl error\n");
// return -1;
// }
if(raw_packet_len <ip_len)
{
@@ -854,15 +859,23 @@ int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen)
return -1;
}
unsigned short iphdrlen =iph->ihl*4;
if(raw_ip_version==AF_INET)
{
if(raw_info.peek==0)// avoid cal it twice
{
u32_t ip_chk=csum ((unsigned short *) ip_begin, iphdrlen);
u32_t ip_chk=csum ((unsigned short *) ip_begin, iphdrlen);
if(ip_chk!=0)
{
mylog(log_debug,"ip header error %x\n",ip_chk);
return -1;
}
}
}
else
{
if(ip_chk!=0)
{
mylog(log_debug,"ip header error %x\n",ip_chk);
return -1;
}
}
payload=ip_begin+iphdrlen;
@@ -877,7 +890,77 @@ int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen)
return 0;
}
int peek_raw(raw_info_t &raw_info)
{
//static char peek_raw_buf[buf_len];
//assert(g_packet_buf_cnt==1);
//g_packet_buf_cnt--;
//char * peek_raw_buf=g_packet_buf;
//int recv_len=g_packet_buf_len;
//char *ip_begin=peek_raw_buf+link_level_header_len;
//struct sockaddr saddr={0};
//socklen_t saddr_size=sizeof(saddr);
//int recv_len = recvfrom(raw_recv_fd, peek_raw_buf,max_data_len, MSG_PEEK ,&saddr , &saddr_size);//change max_data_len to something smaller,we only need header here
//iphdr * iph = (struct iphdr *) (ip_begin);
//mylog(log_info,"recv_len %d\n",recv_len);
//if(recv_len<int(sizeof(iphdr)))
//{
// mylog(log_trace,"failed here %d %d\n",recv_len,int(sizeof(iphdr)));
// mylog(log_trace,"%s\n ",strerror(errno));
// return -1;
//}
//peek_info.new_src_ip.v4=iph->saddr;
//unsigned short iphdrlen =iph->ihl*4;
//char *payload=ip_begin+iphdrlen;
packet_info_t &recv_info=raw_info.recv_info;
char *payload;int payload_len;
if(recv_raw_ip(raw_info,payload,payload_len)!=0)
return -1;
//mylog(log_info,"protocol %d\n",iph->protocol);
switch(raw_mode)
{
case mode_faketcp:
{
if(recv_info.protocol!=IPPROTO_TCP)
{
mylog(log_trace,"failed here");
return -1;
}
struct tcphdr *tcph=(tcphdr *)payload;
if(payload_len<int(sizeof(tcphdr) ))
{
mylog(log_trace,"failed here");
return -1;
}
recv_info.src_port=ntohs(tcph->source);
recv_info.syn=tcph->syn;
break;
}
case mode_udp:
{
if(recv_info.protocol!=IPPROTO_UDP) return -1;
struct udphdr *udph=(udphdr *)payload;
if(payload_len<int(sizeof(udphdr)))
return -1;
recv_info.src_port=ntohs(udph->source);
break;
}
case mode_icmp:
{
if(recv_info.protocol!=IPPROTO_ICMP) return -1;
struct icmphdr *icmph=(icmphdr *)payload;
if(payload_len<int(sizeof(udphdr)))
return -1;
recv_info.src_port=ntohs(icmph->id);
break;
}
default:return -1;
}
return 0;
}
int send_raw_icmp(raw_info_t &raw_info, const char * payload, int payloadlen)
{
const packet_info_t &send_info=raw_info.send_info;
@@ -1992,7 +2075,7 @@ int recv_raw(raw_info_t &raw_info,char *& payload,int & payloadlen)
}
}*/
/*
int get_src_adress(u32_t &ip,u32_t remote_ip_uint32,int remote_port) //a trick to get src adress for a dest adress,so that we can use the src address in raw socket as source ip
{
struct sockaddr_in remote_addr_in={0};
@@ -2031,7 +2114,7 @@ int get_src_adress(u32_t &ip,u32_t remote_ip_uint32,int remote_port) //a trick
close(new_udp_fd);
return 0;
}
}*/
int get_src_adress2(address_t &output_addr,address_t remote_addr)
{
@@ -2052,7 +2135,7 @@ int get_src_adress2(address_t &output_addr,address_t remote_addr)
return 0;
}
/*
int try_to_list_and_bind(int &fd,u32_t local_ip_uint32,int port) //try to bind to a port,may fail.
{
int old_bind_fd=fd;
@@ -2091,7 +2174,7 @@ int try_to_list_and_bind(int &fd,u32_t local_ip_uint32,int port) //try to bind
}
}
return 0;
}
}*/
int try_to_list_and_bind2(int &fd,address_t address) //try to bind to a port,may fail.
{
int old_bind_fd=fd;
@@ -2131,7 +2214,7 @@ int try_to_list_and_bind2(int &fd,address_t address) //try to bind to a port,ma
}
return 0;
}
/*
int client_bind_to_a_new_port(int &fd,u32_t local_ip_uint32)//find a free port and bind to it.
{
int raw_send_port=10000+get_true_random_number()%(65535-10000);
@@ -2145,7 +2228,7 @@ int client_bind_to_a_new_port(int &fd,u32_t local_ip_uint32)//find a free port a
mylog(log_fatal,"bind port fail\n");
myexit(-1);
return -1;////for compiler check
}
}*/
int client_bind_to_a_new_port2(int &fd,const address_t& address)//find a free port and bind to it.
{