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

@ -56,6 +56,7 @@
#include <map>
#include <set>
#include <list>
#include <type_traits>
using namespace std;

@ -997,9 +997,11 @@ int server_on_raw_recv_handshake1(conn_info_t &conn_info,char * ip_port,char * d
int server_on_raw_recv_multi() //called when server received an raw packet
{
char dummy_buf[buf_len];
packet_info_t peek_info;
raw_info_t peek_raw_info;
peek_raw_info.peek=1;
packet_info_t &peek_info=peek_raw_info.recv_info;
if(pre_recv_raw_packet()<0) return -1;
if(peek_raw(peek_info)<0)
if(peek_raw(peek_raw_info)<0)
{
discard_raw_packet();
//recv(raw_recv_fd, 0,0, 0 );//
@ -1554,10 +1556,23 @@ int server_event_loop()
int i, j, k;int ret;
if(local_addr.inner.ipv4.sin_addr.s_addr!=0)
if(raw_ip_version==AF_INET)
{
bind_addr_used=1;
bind_addr=local_addr;
if(local_addr.inner.ipv4.sin_addr.s_addr!=0)
{
bind_addr_used=1;
bind_addr.v4=local_addr.inner.ipv4.sin_addr.s_addr;
}
}
else
{
assert(raw_ip_version==AF_INET6);
char zero_arr[16]={0};
if(memcmp(&local_addr.inner.ipv6.sin6_addr,zero_arr,16)!=0)
{
bind_addr_used=1;
bind_addr.v6=local_addr.inner.ipv6.sin6_addr;
}
}
//bind_address_uint32=local_ip_uint32;//only server has bind adress,client sets it to zero

@ -32,7 +32,9 @@ fd_manager_t fd_manager;
//char local_ip[100]="0.0.0.0", remote_ip[100]="255.255.255.255",source_ip[100]="0.0.0.0";//local_ip is for -l option,remote_ip for -r option,source for --source-ip
//u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line.
//int local_port = -1, remote_port=-1,source_port=0;//similiar to local_ip remote_ip,buf for port.source_port=0 indicates --source-port is not enabled
address_t local_addr,remote_addr,source_addr,bind_addr;
address_t local_addr,remote_addr,source_addr;
my_ip_t bind_addr;
int source_port=-1;

4
misc.h

@ -78,7 +78,9 @@ union current_state_t
//extern u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line.
//extern int local_port , remote_port,source_port;//similiar to local_ip remote_ip,buf for port.source_port=0 indicates --source-port is not enabled
extern address_t local_addr,remote_addr,source_addr,bind_addr;
extern address_t local_addr,remote_addr,source_addr;
extern my_ip_t bind_addr;
extern int bind_addr_used;
extern int force_source_ip; //if --source-ip is enabled

@ -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.
{

@ -87,7 +87,8 @@ struct raw_info_t
packet_info_t recv_info;
//int last_send_len;
//int last_recv_len;
bool peek=0;
//bool csum=1;
u32_t reserved_send_seq;
//uint32_t first_seq,first_ack_seq;
int rst_received=0;
@ -120,7 +121,7 @@ int pre_recv_raw_packet();
int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen);
int peek_raw(packet_info_t &peek_info);
int peek_raw(raw_info_t &peek_info);
int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen);