浏览代码

unify udpraw linux and mp branch

wangyu 5 年之前
父节点
当前提交
5a51248cb0
共有 8 个文件被更改,包括 1310 次插入7 次删除
  1. 268 1
      client.cpp
  2. 136 0
      common.cpp
  3. 54 2
      common.h
  4. 18 0
      main.cpp
  5. 190 1
      misc.cpp
  6. 607 3
      network.cpp
  7. 34 0
      network.h
  8. 3 0
      server.cpp

+ 268 - 1
client.cpp

@@ -7,6 +7,18 @@
 #include "encrypt.h"
 #include "fd_manager.h"
 
+#ifdef UDP2RAW_MP
+u32_t detect_interval=1500;
+u64_t laste_detect_time=0;
+
+int use_udp_for_detection=0;
+int use_tcp_for_detection=1;
+
+
+extern pcap_t *pcap_handle;
+
+extern int pcap_captured_full_len;
+#endif
 
 int client_on_timer(conn_info_t &conn_info) //for client. called when a timer is ready in epoll
 {
@@ -20,6 +32,75 @@ int client_on_timer(conn_info_t &conn_info) //for client. called when a timer is
 
 	mylog(log_trace,"<client_on_timer,send_info.ts_ack= %u>\n",send_info.ts_ack);
 
+#ifdef UDP2RAW_MP
+	//mylog(log_debug,"pcap cnt :%d\n",pcap_cnt);
+	if(send_with_pcap&&!pcap_header_captured)
+	{
+
+		if(get_current_time()-laste_detect_time>detect_interval)
+		{
+			laste_detect_time=get_current_time();
+		}
+		else
+		{
+			return 0;
+		}
+/*
+		struct sockaddr_in remote_addr_in={0};
+
+		socklen_t slen = sizeof(sockaddr_in);
+		int port=get_true_random_number()%65534+1;
+		remote_addr_in.sin_family = AF_INET;
+		remote_addr_in.sin_port = htons(port);
+		remote_addr_in.sin_addr.s_addr = remote_ip_uint32;*/
+		int port=get_true_random_number()%65534+1;
+		address_t tmp_addr=remote_addr;
+		tmp_addr.set_port(port);
+
+		if(use_udp_for_detection)
+		{
+			int new_udp_fd=socket(tmp_addr.get_type(), SOCK_DGRAM, IPPROTO_UDP);
+			if(new_udp_fd<0)
+			{
+				mylog(log_warn,"create new_udp_fd error\n");
+				return -1;
+			}
+			setnonblocking(new_udp_fd);
+			u64_t tmp=get_true_random_number();
+
+			int ret=sendto(new_udp_fd,(char*)(&tmp),sizeof(tmp),0,(struct sockaddr *)&tmp_addr.inner,tmp_addr.get_len());
+			if(ret==-1)
+			{
+				mylog(log_warn,"sendto() failed\n");
+			}
+			sock_close(new_udp_fd);
+		}
+
+		if(use_tcp_for_detection)
+		{
+			static int last_tcp_fd=-1;
+
+			int new_tcp_fd=socket(tmp_addr.get_type(), SOCK_STREAM, IPPROTO_TCP);
+			if(new_tcp_fd<0)
+			{
+				mylog(log_warn,"create new_tcp_fd error\n");
+				return -1;
+			}
+			setnonblocking(new_tcp_fd);
+			connect(new_tcp_fd,(struct sockaddr *)&tmp_addr.inner,tmp_addr.get_len());
+			if(last_tcp_fd!=-1)
+				sock_close(last_tcp_fd);
+			last_tcp_fd=new_tcp_fd;
+			//close(new_tcp_fd);
+		}
+
+
+
+		mylog(log_info,"waiting for a use-able packet to be captured\n");
+
+		return 0;
+	}
+#endif
 	if(raw_info.disabled)
 	{
 		conn_info.state.client_current_state=client_idle;
@@ -387,7 +468,10 @@ int client_on_raw_recv(conn_info_t &conn_info) //called when raw fd received a p
 	raw_info_t &raw_info=conn_info.raw_info;
 
 	mylog(log_trace,"<client_on_raw_recv,send_info.ts_ack= %u>\n",send_info.ts_ack);
+
+#ifdef UDP2RAW_LINUX
 	if(pre_recv_raw_packet()<0) return -1;
+#endif
 
 	if(conn_info.state.client_current_state==client_idle )
 	{
@@ -583,10 +667,71 @@ void udp_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
 }
 void raw_recv_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
 {
-	//assert(0==1);
+	if(is_udp2raw_mp)assert(0==1);
 	conn_info_t & conn_info= *((conn_info_t*)watcher->data);
 	client_on_raw_recv(conn_info);
 }
+#ifdef UDP2RAW_MP
+void async_cb(struct ev_loop *loop, struct ev_async *watcher, int revents)
+{
+	conn_info_t & conn_info= *((conn_info_t*)watcher->data);
+
+	if(send_with_pcap&&!pcap_header_captured)
+	{
+		int empty=0;char *p;int len;
+		pthread_mutex_lock(&queue_mutex);
+		empty=my_queue.empty();
+		if(!empty)
+		{
+			my_queue.peek_front(p,len);
+			my_queue.pop_front();
+		}
+		pthread_mutex_unlock(&queue_mutex);
+		if(empty) return;
+
+		pcap_header_captured=1;
+		assert(pcap_link_header_len!=-1);
+		memcpy(pcap_header_buf,p,max_data_len);
+
+		log_bare(log_info,"link level header captured:\n");
+		unsigned char *tmp=(unsigned char*)pcap_header_buf;
+		pcap_captured_full_len=len;
+		for(int i=0;i<pcap_link_header_len;i++)
+		log_bare(log_info,"<%x>",(u32_t)tmp[i]);
+
+		log_bare(log_info,"\n");
+		return ;
+	}
+
+	//mylog(log_info,"async_cb called\n");
+	while(1)
+	{
+		int empty=0;char *p;int len;
+		pthread_mutex_lock(&queue_mutex);
+		empty=my_queue.empty();
+		if(!empty)
+		{
+			my_queue.peek_front(p,len);
+			my_queue.pop_front();
+		}
+		pthread_mutex_unlock(&queue_mutex);
+
+		if(empty) break;
+		if(g_fix_gro==0&&len>max_data_len)
+		{
+		    mylog(log_warn,"huge packet %d > %d, dropped\n",len,max_data_len);
+		    break;
+		}
+
+		int new_len=len-pcap_link_header_len;
+		memcpy(g_packet_buf,p+pcap_link_header_len,new_len);
+		g_packet_buf_len=new_len;
+		assert(g_packet_buf_cnt==0);
+		g_packet_buf_cnt++;
+		client_on_raw_recv(conn_info);
+	}
+}
+#endif
 void clear_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
 {
 	conn_info_t & conn_info= *((conn_info_t*)watcher->data);
@@ -632,6 +777,7 @@ int client_event_loop()
 	packet_info_t &send_info=conn_info.raw_info.send_info;
 	packet_info_t &recv_info=conn_info.raw_info.recv_info;
 
+#ifdef UDP2RAW_LINUX
 	if(lower_level)
 	{
 		if(lower_level_manual)
@@ -707,6 +853,116 @@ int client_event_loop()
 		}
 
 	}
+#endif
+	
+#ifdef UDP2RAW_MP
+
+	address_t tmp_addr;
+	if(get_src_adress2(tmp_addr,remote_addr)!=0)
+	{
+		mylog(log_error,"get_src_adress() failed\n");
+		myexit(-1);
+	}
+	if(strcmp(dev,"")==0)
+	{
+		mylog(log_info,"--dev have not been set, trying to detect automatically, avaliable deives:\n");
+
+		mylog(log_info,"avaliable deives(device name: ip address ; description):\n");
+
+		char errbuf[PCAP_ERRBUF_SIZE];
+
+		int found=0;
+
+		pcap_if_t *interfaces,*d;
+		if(pcap_findalldevs(&interfaces,errbuf)==-1)
+		{
+			mylog(log_fatal,"error in pcap_findalldevs(),%s\n",errbuf);
+			myexit(-1);
+		}
+
+		for(pcap_if_t *d=interfaces; d!=NULL; d=d->next) {
+			log_bare(log_warn,"%s:", d->name);
+			int cnt=0;
+			for(pcap_addr_t *a=d->addresses; a!=NULL; a=a->next) {
+				if(a->addr==NULL)
+				{
+					log_bare(log_debug," [a->addr==NULL]");
+					continue;
+				}
+				if(a->addr->sa_family == AF_INET||a->addr->sa_family == AF_INET6)
+				{
+					cnt++;
+
+					if(a->addr->sa_family ==AF_INET)
+					{
+						char s[max_addr_len];
+						inet_ntop(AF_INET, &((struct sockaddr_in*)a->addr)->sin_addr, s,max_addr_len);
+						log_bare(log_warn," [%s]", s);
+
+						if(a->addr->sa_family==raw_ip_version)
+						{
+							if(((struct sockaddr_in*)a->addr)->sin_addr.s_addr ==tmp_addr.inner.ipv4.sin_addr.s_addr)
+							{
+								found++;
+								strcpy(dev,d->name);
+							}
+						}
+					}
+					else
+					{
+						assert(a->addr->sa_family ==AF_INET6);
+
+						char s[max_addr_len];
+						inet_ntop(AF_INET6, &((struct sockaddr_in6*)a->addr)->sin6_addr, s,max_addr_len);
+						log_bare(log_warn," [%s]", s);
+
+						if(a->addr->sa_family==raw_ip_version)
+						{
+							if(  memcmp( &((struct sockaddr_in6*)a->addr)->sin6_addr,&tmp_addr.inner.ipv6.sin6_addr,sizeof(struct in6_addr))==0 )
+							{
+								found++;
+								strcpy(dev,d->name);
+							}
+						}
+					}
+				}
+				else
+				{
+					log_bare(log_debug," [unknow:%d]",int(a->addr->sa_family));
+				}
+			}
+			if(cnt==0) log_bare(log_warn," [no ip found]");
+			if(d->description==0)
+			{
+				log_bare(log_warn,"; (no description avaliable)");
+			}
+			else
+			{
+				log_bare(log_warn,"; %s", d->description);
+			}
+			log_bare(log_warn,"\n");
+		}
+
+		if(found==0)
+		{
+			mylog(log_fatal,"no matched device found for ip: [%s]\n",tmp_addr.get_ip());
+			myexit(-1);
+		}
+		else if(found==1)
+		{
+			mylog(log_info,"using device:[%s], ip: [%s]\n",dev,tmp_addr.get_ip());
+		}
+		else
+		{
+			mylog(log_fatal,"more than one devices found for ip: [%s] , you need to use --dev manually\n",tmp_addr.get_ip());
+			myexit(-1);
+		}
+	}
+	else
+	{
+		mylog(log_info,"--dev has been manually set, using device:[%s]\n",dev);
+	}
+#endif
 
 	send_info.src_port=0;
 	memset(&send_info.new_src_ip,0,sizeof(send_info.new_src_ip));
@@ -766,11 +1022,22 @@ int client_event_loop()
 	//	myexit(-1);
 	//}
 
+#ifdef UDP2RAW_LINUX
 	struct ev_io raw_recv_watcher;
 
 	raw_recv_watcher.data=&conn_info;
     ev_io_init(&raw_recv_watcher, raw_recv_cb, raw_recv_fd, EV_READ);
     ev_io_start(loop, &raw_recv_watcher);
+#endif
+
+#ifdef UDP2RAW_MP
+	g_default_loop=loop;
+	async_watcher.data=&conn_info;
+	ev_async_init(&async_watcher,async_cb);
+	ev_async_start(loop,&async_watcher);
+
+	init_raw_socket();//must be put after dev detection
+#endif
 
 	//set_timer(epollfd,timer_fd);
 	struct ev_timer clear_timer;

+ 136 - 0
common.cpp

@@ -345,6 +345,57 @@ int my_ip_t::from_str(char * str)
 	}
 	return 0;
 }*/
+#ifdef UDP2RAW_MP
+
+int init_ws()
+{
+#if defined(__MINGW32__)
+	WORD wVersionRequested;
+	WSADATA wsaData;
+	int err;
+
+	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
+	wVersionRequested = MAKEWORD(2, 2);
+
+	err = WSAStartup(wVersionRequested, &wsaData);
+	if (err != 0) {
+		/* Tell the user that we could not find a usable */
+		/* Winsock DLL.                                  */
+		printf("WSAStartup failed with error: %d\n", err);
+		exit(-1);
+	}
+
+	/* Confirm that the WinSock DLL supports 2.2.*/
+	/* Note that if the DLL supports versions greater    */
+	/* than 2.2 in addition to 2.2, it will still return */
+	/* 2.2 in wVersion since that is the version we      */
+	/* requested.                                        */
+
+	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
+		/* Tell the user that we could not find a usable */
+		/* WinSock DLL.                                  */
+		printf("Could not find a usable version of Winsock.dll\n");
+		WSACleanup();
+		exit(-1);
+	}
+	else
+	{
+		printf("The Winsock 2.2 dll was found okay");
+	}
+
+	int tmp[]={0,100,200,300,500,800,1000,2000,3000,4000,-1};
+	int succ=0;
+	for(int i=1;tmp[i]!=-1;i++)
+	{
+		if(_setmaxstdio(100)==-1) break;
+		else succ=i;
+	}
+	printf(", _setmaxstdio() was set to %d\n",tmp[succ]);
+#endif
+return 0;
+}
+
+#endif
 
 #if defined(__MINGW32__)
 int inet_pton(int af, const char *src, void *dst)
@@ -492,6 +543,8 @@ void init_random_number_fd()
 	}
 	setnonblocking(random_number_fd);
 }*/
+
+#if !defined(__MINGW32__)
 struct random_fd_t
 {
 	int random_number_fd;
@@ -511,8 +564,60 @@ struct random_fd_t
 		return random_number_fd;
 	}
 }random_fd;
+#else
+struct my_random_t
+{
+    std::random_device rd;
+    std::mt19937 gen;
+    std::uniform_int_distribution<u64_t> dis64;
+    std::uniform_int_distribution<u32_t> dis32;
+
+    std::uniform_int_distribution<unsigned char> dis8;
+
+    my_random_t()
+	{
+    	//std::mt19937 gen_tmp(rd());  //random device is broken on mingw
+	timespec tmp_time;
+	clock_gettime(CLOCK_MONOTONIC, &tmp_time);
+	long  long  a=((u64_t)tmp_time.tv_sec)*1000000000llu+((u64_t)tmp_time.tv_nsec);
+    	std::mt19937 gen_tmp(a);
+    	gen=gen_tmp;
+    	gen.discard(700000);  //magic
+	}
+    u64_t gen64()
+    {
+    	return dis64(gen);
+    }
+    u32_t gen32()
+    {
+    	return dis32(gen);
+    }
+
+    unsigned char gen8()
+    {
+    	return dis8(gen);
+    }
+	/*int random_number_fd;
+	random_fd_t()
+	{
+			random_number_fd=open("/dev/urandom",O_RDONLY);
+			if(random_number_fd==-1)
+			{
+				mylog(log_fatal,"error open /dev/urandom\n");
+				myexit(-1);
+			}
+			setnonblocking(random_number_fd);
+	}
+	int get_fd()
+	{
+		return random_number_fd;
+	}*/
+}my_random;
+#endif
+
 u64_t get_true_random_number_64()
 {
+#if !defined(__MINGW32__)
 	u64_t ret;
 	int size=read(random_fd.get_fd(),&ret,sizeof(ret));
 	if(size!=sizeof(ret))
@@ -521,9 +626,13 @@ u64_t get_true_random_number_64()
 		myexit(-1);
 	}
 	return ret;
+#else
+	return my_random.gen64();  //fake random number
+#endif
 }
 u32_t get_true_random_number()
 {
+#if !defined(__MINGW32__)
 	u32_t ret;
 	int size=read(random_fd.get_fd(),&ret,sizeof(ret));
 	if(size!=sizeof(ret))
@@ -532,6 +641,9 @@ u32_t get_true_random_number()
 		myexit(-1);
 	}
 	return ret;
+#else
+	return my_random.gen32();  //fake random number
+#endif
 }
 u32_t get_true_random_number_nz() //nz for non-zero
 {
@@ -694,6 +806,13 @@ int set_buf_size(int fd,int socket_buf_size)
 {
 	if(force_socket_buf)
 	{
+		if(is_udp2raw_mp)
+		{
+		mylog(log_fatal,"force_socket_buf not supported in this verion\n");
+		myexit(-1);
+		}
+		//assert(0==1);
+#ifdef UDP2RAW_LINUX
 		if(setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0)
 		{
 			mylog(log_fatal,"SO_SNDBUFFORCE fail  socket_buf_size=%d  errno=%s\n",socket_buf_size,strerror(errno));
@@ -704,6 +823,8 @@ int set_buf_size(int fd,int socket_buf_size)
 			mylog(log_fatal,"SO_RCVBUFFORCE fail  socket_buf_size=%d  errno=%s\n",socket_buf_size,strerror(errno));
 			myexit(1);
 		}
+#endif
+
 	}
 	else
 	{
@@ -846,6 +967,7 @@ void myexit(int a)
 {
     if(enable_log_color)
    	printf("%s\n",RESET);
+#ifdef UDP2RAW_LINUX
     if(keep_thread_running)
     {
 		if(pthread_cancel(keep_thread))
@@ -858,6 +980,7 @@ void myexit(int a)
 		}
     }
 	clear_iptables_rule();
+#endif
 	exit(a);
 }
 
@@ -927,6 +1050,12 @@ int read_file(const char * file,string &output)
 	return 0;
 }
 int run_command(string command0,char * &output,int flag) {
+if(is_udp2raw_mp)
+{
+    mylog(log_fatal,"run_command not supported in this version\n");
+    myexit(-1);
+}
+#ifdef UDP2RAW_LINUX
     FILE *in;
 
 
@@ -980,6 +1109,7 @@ int run_command(string command0,char * &output,int flag) {
     	return -4;
     }
 
+#endif
     return 0;
 
 }
@@ -1100,6 +1230,7 @@ vector<string> parse_conf_line(const string& s0)
 
 int create_fifo(char * file)
 {
+#ifdef  UDP2RAW_LINUX
 	if(mkfifo (file, 0666)!=0)
 	{
 		if(errno==EEXIST)
@@ -1133,6 +1264,11 @@ int create_fifo(char * file)
 
 	setnonblocking(fifo_fd);
 	return fifo_fd;
+#else
+        mylog(log_fatal,"--fifo not supported in this version\n");
+        myexit(-1);
+	return 0;
+#endif
 }
 
 /*

+ 54 - 2
common.h

@@ -28,7 +28,7 @@
 #include <pthread.h>
 
 #if defined(UDP2RAW_MP)
-
+const int is_udp2raw_mp=1;
 #if !defined(__CYGWIN__) && !defined(__MINGW32__)
 #include <pcap.h>
 #else
@@ -40,8 +40,10 @@
 #include <libnet.h>
 #endif
 
-#else
 
+#else
+#define UDP2RAW_LINUX
+const int is_udp2raw_mp=0;
 //#include <linux/if_ether.h>
 #include <linux/filter.h>
 #include <linux/if_packet.h>
@@ -53,7 +55,11 @@
 
 #endif
 
+#if !defined(NO_LIBEV_EMBED)
 #include <my_ev.h>
+#else
+#include "ev.h"
+#endif
 
 #if defined(__MINGW32__)
 #include <winsock2.h>
@@ -355,6 +361,52 @@ const int buf_len=max_data_len+400;
 
 //const int max_address_len=512;
 
+#ifdef UDP2RAW_MP
+const int queue_len=200;
+
+struct queue_t
+{
+	char data[queue_len][huge_buf_len];
+	int data_len[queue_len];
+
+	int head=0;
+	int tail=0;
+	void clear()
+	{
+		head=tail=0;
+	}
+	int empty()
+	{
+		if(head==tail) return 1;
+		else return 0;
+	}
+	int full()
+	{
+		if( (tail+1)%queue_len==head  ) return 1;
+		else return 0;
+	}
+	void peek_front(char * & p,int &len)
+	{
+		assert(!empty());
+		p=data[head];
+		len=data_len[head];
+	}
+	void pop_front()
+	{
+		assert(!empty());
+		head++;head%=queue_len;
+	}
+	void push_back(char * p,int len)
+	{
+		assert(!full());
+		memcpy(data[tail],p,len);
+		data_len[tail]=len;
+		tail++;tail%=queue_len;
+	}
+};
+
+int init_ws();
+#endif
 u64_t get_current_time();
 u64_t pack_u64(u32_t a,u32_t b);
 

+ 18 - 0
main.cpp

@@ -33,6 +33,10 @@ int main(int argc, char *argv[])
 	assert(sizeof(unsigned int)==4);
 	assert(sizeof(unsigned long long)==8);
 
+#ifdef UDP2RAW_MP
+	init_ws();
+#endif
+
 	dup2(1, 2);//redirect stderr to stdout
 #if defined(__MINGW32__)
     enable_log_color=0;
@@ -59,11 +63,17 @@ int main(int argc, char *argv[])
 	}
 	else
 	{
+#ifdef UDP2RAW_LINUX
 		signal(SIGINT, signal_handler);
 		signal(SIGHUP, signal_handler);
 		signal(SIGKILL, signal_handler);
 		signal(SIGTERM, signal_handler);
 		signal(SIGQUIT, signal_handler);
+#else
+		mylog(log_fatal,"server mode not supported in multi-platform version\n");
+		myexit(-1);	
+#endif
+	      
 	}
 #if !defined(__MINGW32__)
 	if(geteuid() != 0)
@@ -87,7 +97,10 @@ int main(int argc, char *argv[])
 	my_init_keys(key_string,program_mode==client_mode?1:0);
 
 	iptables_rule();
+	
+#ifdef UDP2RAW_LINUX
 	init_raw_socket();
+#endif
 
 	if(program_mode==client_mode)
 	{
@@ -95,7 +108,12 @@ int main(int argc, char *argv[])
 	}
 	else
 	{
+#ifdef UDP2RAW_LINUX
 		server_event_loop();
+#else
+		mylog(log_fatal,"server mode not supported in multi-platform version\n");
+		myexit(-1);
+#endif
 	}
 
 	return 0;

+ 190 - 1
misc.cpp

@@ -47,8 +47,10 @@ my_id_t const_id=0;//an id used for connection recovery,its generated randomly,i
 
 int udp_fd=-1;  //for client only. client use this fd to listen and handle udp connection
 int bind_fd=-1; //bind only,never send or recv.  its just a dummy fd for bind,so that other program wont occupy the same port
+#ifdef UDP2RAW_LINUX
 int epollfd=-1; //fd for epoll
 int timer_fd=-1;   //the general timer fd for client and server.for server this is not the only timer find,every connection has a timer fd.
+#endif
 int fail_time_counter=0;//determine if the max_fail_time is reached
 int epoll_trigger_counter=0;//for debug only
 int debug_flag=0;//for debug only
@@ -70,12 +72,14 @@ char fifo_file[1000]="";
 
 int clear_iptables=0;
 int wait_xtables_lock=0;
+#ifdef UDP2RAW_LINUX
 string iptables_command0="iptables/ip6tables ";
 string iptables_command="";
 string iptables_pattern="";
 int iptables_rule_added=0;
 int iptables_rule_keeped=0;
 int iptables_rule_keep_index=0;
+#endif
 
 program_mode_t program_mode=unset_mode;//0 unset; 1client 2server
 raw_mode_t raw_mode=mode_faketcp;
@@ -94,6 +98,7 @@ int socket_buf_size=1024*1024;
 
 
 //char lower_level_arg[1000];
+#ifdef UDP2RAW_LINUX
 int process_lower_level_arg()//handle --lower-level option
 {
 	lower_level=1;
@@ -122,6 +127,7 @@ int process_lower_level_arg()//handle --lower-level option
 	}
 	return 0;
 }
+#endif
 void print_help()
 {
 	char git_version_buf[100]={0};
@@ -131,12 +137,18 @@ void print_help()
 	printf("build date:%s %s\n",__DATE__,__TIME__);
 	printf("repository: https://github.com/wangyu-/udp2raw-tunnel\n");
 	printf("\n");
+#ifdef UDP2RAW_MP
+#ifdef NO_LIBNET
+	printf("libnet is disabled at compile time\n");
+	printf("\n");
+#endif
+#endif
 	printf("usage:\n");
 	printf("    run as client : ./this_program -c -l local_listen_ip:local_port -r server_address:server_port  [options]\n");
 	printf("    run as server : ./this_program -s -l server_listen_ip:server_port -r remote_address:remote_port  [options]\n");
 	printf("\n");
 	printf("common options,these options must be same on both side:\n");
-	printf("    --raw-mode            <string>        avaliable values:faketcp(default),udp,icmp\n");
+	printf("    --raw-mode            <string>        avaliable values:faketcp(default),udp,icmp and easy-faketcp\n");
 	printf("    -k,--key              <string>        password to gen symetric key,default:\"secret key\"\n");
 	printf("    --cipher-mode         <string>        avaliable values:aes128cfb,aes128cbc(default),xor,none\n");
 	printf("    --auth-mode           <string>        avaliable values:hmac_sha1,md5(default),crc32,simple,none\n");
@@ -166,7 +178,9 @@ void print_help()
 	printf("    --disable-bpf                         disable the kernel space filter,most time its not necessary\n");
 	printf("                                          unless you suspect there is a bug\n");
 //	printf("\n");
+#ifdef UDP2RAW_LINUX
 	printf("    --dev                 <string>        bind raw socket to a device, not necessary but improves performance\n");
+#endif
 	printf("    --sock-buf            <number>        buf size for socket,>=10 and <=10240,unit:kbyte,default:1024\n");
 	printf("    --force-sock-buf                      bypass system limitation while setting sock-buf\n");
 	printf("    --seq-mode            <number>        seq increase mode for faketcp:\n");
@@ -299,6 +313,10 @@ void process_arg(int argc, char *argv[])  //process all options
 		{"dev", required_argument,    0, 1},
 		{"dns-resolve", no_argument,    0, 1},
 		{"easy-tcp", no_argument,    0, 1},
+#ifdef UDP2RAW_MP
+		{"pcap-send", no_argument,    0, 1},
+		{"no-pcap-mutex", no_argument,    0, 1},
+#endif
         {"fix-gro", no_argument,    0, 1},
 		{NULL, 0, 0, 0}
 	  };
@@ -468,6 +486,11 @@ void process_arg(int argc, char *argv[])  //process all options
 		case 'h':
 			break;
 		case 'a':
+if(is_udp2raw_mp)
+{
+			mylog(log_fatal,"-a not supported in this version, check -g or --raw-mode easyfaketcp\n");
+			myexit(-1);
+}
 			auto_add_iptables_rule=1;
 			break;
 		case 'g':
@@ -481,6 +504,12 @@ void process_arg(int argc, char *argv[])  //process all options
 			mylog(log_debug,"option_index: %d\n",option_index);
 			if(strcmp(long_options[option_index].name,"clear")==0)
 			{
+if(is_udp2raw_mp)
+{
+				mylog(log_fatal,"--clear not supported in this version\n");
+				myexit(-1);
+}
+
 				clear_iptables=1;
 			}
 			else if(strcmp(long_options[option_index].name,"source-ip")==0)
@@ -590,20 +619,44 @@ void process_arg(int argc, char *argv[])  //process all options
 			}
 			else if(strcmp(long_options[option_index].name,"lower-level")==0)
 			{
+if(is_udp2raw_mp)
+{
+				mylog(log_fatal,"--lower-level not supported in this version\n");
+				myexit(-1);
+}
+
+#ifdef UDP2RAW_LINUX
 				process_lower_level_arg();
+#endif
+				//process_lower_level_arg();
 				//lower_level=1;
 				//strcpy(lower_level_arg,optarg);
 			}
 			else if(strcmp(long_options[option_index].name,"simple-rule")==0)
 			{
+if(is_udp2raw_mp)
+{
+				mylog(log_fatal,"--simple-rule not supported in this version\n");
+				myexit(-1);
+}
 				simple_rule=1;
 			}
 			else if(strcmp(long_options[option_index].name,"keep-rule")==0)
 			{
+if(is_udp2raw_mp)
+{
+				mylog(log_fatal,"--keep-rule not supported in this version\n");
+				myexit(-1);
+}
 				keep_rule=1;
 			}
 			else if(strcmp(long_options[option_index].name,"gen-add")==0)
 			{
+if(is_udp2raw_mp)
+{
+				mylog(log_fatal,"--gen-add not supported in this version\n");
+				myexit(-1);
+}
 				generate_iptables_rule_add=1;
 			}
 			else if(strcmp(long_options[option_index].name,"disable-color")==0)
@@ -636,6 +689,11 @@ void process_arg(int argc, char *argv[])  //process all options
 			}
 			else if(strcmp(long_options[option_index].name,"force-sock-buf")==0)
 			{
+if(is_udp2raw_mp)
+{
+				mylog(log_fatal,"--force-sock-buf not supported in this version\n");
+				myexit(-1);
+}
 				force_socket_buf=1;
 			}
 			else if(strcmp(long_options[option_index].name,"retry-on-error")==0)
@@ -692,6 +750,11 @@ void process_arg(int argc, char *argv[])  //process all options
 			}
 			else if(strcmp(long_options[option_index].name,"fifo")==0)
 			{
+if(is_udp2raw_mp)
+{
+				mylog(log_fatal,"--fifo not supported in this version\n");
+				myexit(-1);
+}
 				sscanf(optarg,"%s",fifo_file);
 
 				mylog(log_info,"fifo_file =%s \n",fifo_file);
@@ -742,6 +805,18 @@ void process_arg(int argc, char *argv[])  //process all options
 				enable_dns_resolve=1;
 				mylog(log_info,"dns-resolve enabled\n");
 			}
+#ifdef UDP2RAW_MP
+			else if(strcmp(long_options[option_index].name,"pcap-send")==0)
+			{
+				send_with_pcap=1;
+				mylog(log_info,"--pcap-send enabled, now pcap will be used for sending packet instead of libnet\n");
+			}
+			else if(strcmp(long_options[option_index].name,"no-pcap-mutex")==0)
+			{
+				use_pcap_mutex=0;
+				mylog(log_warn,"--no-pcap-mutex enabled, we will assume the underlying pcap calls are threadsafe\n");
+			}
+#endif
 			else if(strcmp(long_options[option_index].name,"easy-tcp")==0)
 			{
 				use_tcp_dummy_socket=1;
@@ -904,6 +979,7 @@ void pre_process_arg(int argc, char *argv[])//mainly for load conf file
 	process_arg(new_argc,new_argv_char);
 
 }
+#ifdef UDP2RAW_LINUX
 void *run_keep(void *none)  //called in a new thread for --keep-rule option
 {
 
@@ -1092,6 +1168,7 @@ void iptables_rule()  // handles -a -g --gen-add  --keep-rule --clear --wait-loc
 		mylog(log_warn," -a has not been set, make sure you have added the needed iptables rules manually\n");
 	}
 }
+#endif
 
 int unit_test()
 {
@@ -1151,6 +1228,7 @@ int unit_test()
 	return 0;
 }
 
+#ifdef UDP2RAW_LINUX
 int set_timer(int epollfd,int &timer_fd)//put a timer_fd into epoll,general function,used both in client and server
 {
 	int ret;
@@ -1379,6 +1457,117 @@ int clear_iptables_rule()
 	}
 	return 0;
 }
+#endif
+
+#ifdef UDP2RAW_MP
+void iptables_rule()  // handles -a -g --gen-add  --keep-rule --clear --wait-lock
+{
+
+	if(generate_iptables_rule)
+	{
+		if(raw_mode==mode_faketcp && use_tcp_dummy_socket==1)
+		{
+			mylog(log_fatal, "failed,-g doesnt work with easy-faketcp mode\n");
+			myexit(-1);
+		}
+		if(raw_mode==mode_udp)
+		{
+			mylog(log_warn, "It not necessary to use iptables/firewall rule in udp mode\n");
+		}
+		log_bare(log_warn,"for linux, use:\n");
+		if(raw_ip_version==AF_INET)
+		{
+			if(raw_mode==mode_faketcp)
+				printf("iptables -I INPUT -s %s -p tcp -m tcp --sport %d -j DROP\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_udp)
+				printf("iptables -I INPUT -s %s -p udp -m udp --sport %d -j DROP\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_icmp)
+				printf("iptables -I INPUT -s %s -p icmp --icmp-type 0 -j DROP\n",remote_addr.get_ip());
+			printf("\n");
+		}
+		else
+		{
+			assert(raw_ip_version==AF_INET6);
+			if(raw_mode==mode_faketcp)
+				printf("ip6tables -I INPUT -s %s -p tcp -m tcp --sport %d -j DROP\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_udp)
+				printf("ip6tables -I INPUT -s %s -p udp -m udp --sport %d -j DROP\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_icmp)
+				printf("ip6tables -I INPUT -s %s -p -p icmpv6 --icmpv6-type 129 -j DROP\n",remote_addr.get_ip());
+			printf("\n");
+		}
+
+		log_bare(log_warn,"for mac/bsd use:\n");
+		if(raw_ip_version==AF_INET)
+		{
+			if(raw_mode==mode_faketcp)
+				printf("echo 'block drop inet proto tcp from %s port %d to any' > ./1.conf\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_udp)
+				printf("echo 'block drop inet proto udp from %s port %d to any' > ./1.conf\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_icmp)
+				printf("echo 'block drop inet proto icmp from %s to any' > ./1.conf\n",remote_addr.get_ip());
+		}
+		else
+		{
+			assert(raw_ip_version==AF_INET6);
+			if(raw_mode==mode_faketcp)
+				printf("echo 'block drop inet6 proto tcp from %s port %d to any' > ./1.conf\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_udp)
+				printf("echo 'block drop inet6 proto udp from %s port %d to any' > ./1.conf\n",remote_addr.get_ip(),remote_addr.get_port());
+			if(raw_mode==mode_icmp)
+				printf("echo 'block drop inet6 proto icmp6 from %s to any' > ./1.conf\n",remote_addr.get_ip());
+		}
+		printf("pfctl -f ./1.conf\n");
+		printf("pfctl -e\n");
+		printf("\n");
+
+		log_bare(log_warn,"for windows vista and above use:\n");
+		if(raw_ip_version==AF_INET)
+		{
+			if(raw_mode==mode_faketcp)
+			{
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=TCP dir=in remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=TCP dir=out remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+			}
+			if(raw_mode==mode_udp)
+			{
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=UDP dir=in remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=UDP dir=out remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+			}
+
+			if(raw_mode==mode_icmp)
+			{
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=ICMPV4 dir=in remoteip=%s action=block\n",remote_addr.get_ip());
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=ICMPV4 dir=out remoteip=%s action=block\n",remote_addr.get_ip());
+			}
+		}
+		else
+		{
+			assert(raw_ip_version==AF_INET6);
+			if(raw_mode==mode_faketcp)
+			{
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=TCP dir=in remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=TCP dir=out remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+			}
+			if(raw_mode==mode_udp)
+			{
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=UDP dir=in remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=UDP dir=out remoteip=%s remoteport=%d action=block\n",remote_addr.get_ip(),remote_addr.get_port());
+			}
+
+			if(raw_mode==mode_icmp)
+			{
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=ICMPV6 dir=in remoteip=%s action=block\n",remote_addr.get_ip());
+				printf("netsh advfirewall firewall add rule name=udp2raw protocol=ICMPV6 dir=out remoteip=%s action=block\n",remote_addr.get_ip());
+			}
+		}
+
+		myexit(0);
+
+	}
+
+}
+#endif
 
 void  signal_handler(int sig)
 {

+ 607 - 3
network.cpp

@@ -34,9 +34,11 @@ char if_name[100]="";
 char dev[100]="";
 
 unsigned short g_ip_id_counter=0;
-
+#ifdef UDP2RAW_LINUX
 unsigned char dest_hw_addr[sizeof(sockaddr_ll::sll_addr)]=
     {0xff,0xff,0xff,0xff,0xff,0xff,0,0};
+#endif
+
 //{0x00,0x23,0x45,0x67,0x89,0xb9};
 
 const u32_t receive_window_lower_bound=40960;
@@ -47,6 +49,7 @@ char g_packet_buf[huge_buf_len]; //looks dirty but works well
 int g_packet_buf_len=-1;
 int g_packet_buf_cnt=0;
 
+#ifdef UDP2RAW_LINUX
 union
 {
 	sockaddr_ll ll;
@@ -54,6 +57,43 @@ union
 	sockaddr_in6 ipv6;
 }g_sockaddr;
 socklen_t g_sockaddr_len = -1;
+#endif
+
+#ifdef UDP2RAW_MP
+
+#ifndef NO_LIBNET
+libnet_t *libnet_handle;
+libnet_ptag_t g_ptag=0;
+int send_with_pcap=0;
+#else
+int send_with_pcap=1;
+#endif
+
+int pcap_header_captured=0;
+int pcap_header_buf[buf_len];
+int pcap_captured_full_len=-1;
+
+pcap_t *pcap_handle;
+int pcap_link_header_len=-1;
+//int pcap_cnt=0;
+queue_t my_queue;
+
+pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t pcap_mutex = PTHREAD_MUTEX_INITIALIZER;
+int use_pcap_mutex=1;
+
+ev_async async_watcher;
+
+struct ev_loop* g_default_loop;
+
+pthread_t pcap_recv_thread;
+
+struct bpf_program g_filter;
+long long g_filter_compile_cnt=0;
+
+#endif
+
+#ifdef UDP2RAW_LINUX
 
 struct sock_filter code_tcp_old[] = {
 		{ 0x28, 0, 0, 0x0000000c },//0
@@ -218,6 +258,7 @@ tcpdump -i eth1  ip and icmp -dd
 (010) ret      #0
 
  */
+#endif
 
 packet_info_t::packet_info_t()
 {
@@ -255,8 +296,94 @@ packet_info_t::packet_info_t()
 	}
 
 }
+#ifdef UDP2RAW_MP
+void my_packet_handler(
+    u_char *args,
+    const struct pcap_pkthdr *packet_header,
+    const u_char *pkt_data
+)
+{
+	/*printf("<%d %d>\n",(int)packet_header->caplen,(int)packet_header->len );
+	for(int i=0;i<sizeof(pcap_pkthdr);i++)
+	{
+		char *p=(char *) packet_header;
+		printf("<%x>",int( p[i] ));
+	}
+	printf("\n");*/
+	//mylog(log_debug,"received a packet!\n");
+	assert(packet_header->caplen <= packet_header->len);
+	assert(packet_header->caplen <= max_data_len);
+	//if(packet_header->caplen > max_data_len) return ;
+	if(g_fix_gro==0&&packet_header->caplen<packet_header->len) return;
 
+	if((int)packet_header->caplen<pcap_link_header_len) return;
+	//mylog(log_debug,"and its vaild!\n");
 
+	pthread_mutex_lock(&queue_mutex);
+	if(!my_queue.full())
+		my_queue.push_back((char *)pkt_data,(int)(packet_header->caplen));
+	pthread_mutex_unlock(&queue_mutex);
+
+	//pcap_cnt++;
+
+	ev_async_send (g_default_loop,&async_watcher);
+    return;
+}
+
+void *pcap_recv_thread_entry(void *none)
+{
+	struct pcap_pkthdr *packet_header;
+	const u_char *pkt_data;
+
+	while(1)
+	{
+		if(use_pcap_mutex) pthread_mutex_lock(&pcap_mutex);
+		int ret=pcap_loop(pcap_handle, -1, my_packet_handler, NULL); //use -1 instead of 0 as cnt, since 0 is undefined in old versions
+		if(use_pcap_mutex) pthread_mutex_unlock(&pcap_mutex);
+		if(ret==-1)
+			mylog(log_warn,"pcap_loop exited with value %d\n",ret);
+		else
+		{
+			mylog(log_debug,"pcap_loop exited with value %d\n",ret);
+		}
+		ev_sleep(1.0);
+		//myexit(-1);
+	}
+	/*
+	while(1)
+	{
+		//printf("!!!\n");
+		pthread_mutex_lock(&pcap_mutex);
+		int ret=pcap_next_ex(pcap_handle,&packet_header,&pkt_data);
+		pthread_mutex_unlock(&pcap_mutex);
+
+		switch (ret)
+		{
+			case 0:
+				continue;
+			case 1:
+
+				break;
+
+			case -1:
+				mylog(log_fatal,"pcap_next_ex error [%s]\n",pcap_geterr(pcap_handle));
+				myexit(-1);
+				break;
+			case -2:
+				assert(0==1);//
+				break;
+			default:
+				assert(0==1);//
+		}
+	}
+	myexit(-1);*/
+	return 0;
+}
+
+extern void async_cb(struct ev_loop *loop, struct ev_async *watcher, int revents);
+#endif
+
+#ifdef UDP2RAW_LINUX
 int init_raw_socket()
 {
 	assert(raw_ip_version==AF_INET||raw_ip_version==AF_INET6);
@@ -381,6 +508,226 @@ int init_raw_socket()
 
 	return 0;
 }
+#endif
+#ifdef UDP2RAW_MP
+int init_raw_socket()
+{
+
+#ifndef NO_LIBNET
+	char libnet_errbuf[LIBNET_ERRBUF_SIZE];
+
+	if(raw_ip_version==AF_INET)
+	{
+		libnet_handle = libnet_init(LIBNET_RAW4, dev, libnet_errbuf);
+	}
+	else
+	{
+		assert(raw_ip_version==AF_INET6);
+		libnet_handle = libnet_init(LIBNET_RAW6, dev, libnet_errbuf);
+	}
+
+	if(libnet_handle==0)
+	{
+		mylog(log_fatal,"libnet_init failed bc of [%s]\n",libnet_errbuf);
+		myexit(-1);
+	}
+	g_ptag=0;
+    libnet_clear_packet(libnet_handle);
+#endif
+
+	char pcap_errbuf[PCAP_ERRBUF_SIZE];
+
+	//pcap_handle=pcap_open_live(dev,max_data_len,0,1000,pcap_errbuf);
+
+	pcap_handle = pcap_create( dev, pcap_errbuf );
+
+
+	if(pcap_handle==0)
+	{
+		mylog(log_fatal,"pcap_create failed bc of [%s]\n",pcap_errbuf);
+		myexit(-1);
+	}
+
+	assert( pcap_set_snaplen(pcap_handle, huge_data_len) ==0);
+	assert( pcap_set_promisc(pcap_handle, 0) ==0);
+	assert( pcap_set_timeout(pcap_handle, 1) ==0);
+	assert( pcap_set_immediate_mode(pcap_handle,1) ==0);
+
+	int ret = pcap_activate( pcap_handle );
+	if( ret < 0 )
+	{
+		 printf("pcap_activate failed  %s\n", pcap_geterr(pcap_handle));
+		 myexit(-1);
+	}
+
+	if(send_with_pcap)
+	{
+		ret=pcap_setdirection(pcap_handle,PCAP_D_INOUT);//must be used after being actived
+		if(ret!=0) mylog(log_debug,"pcap_setdirection(pcap_handle,PCAP_D_INOUT) failed with value %d, %s\n",ret,pcap_geterr(pcap_handle));
+	}
+	else
+	{
+		ret=pcap_setdirection(pcap_handle,PCAP_D_IN);
+		if(ret!=0) mylog(log_debug,"pcap_setdirection(pcap_handle,PCAP_D_IN) failed with value %d, %s\n",ret,pcap_geterr(pcap_handle));
+	}
+
+
+	ret=pcap_datalink(pcap_handle);
+
+	if(ret==DLT_EN10MB)
+	{
+		pcap_link_header_len=14;
+	}
+	else if(ret==DLT_NULL)
+	{
+		pcap_link_header_len=4;
+	}
+	else if(ret==DLT_LINUX_SLL)
+	{
+		pcap_link_header_len=16;
+	}
+	else
+	{
+		mylog(log_fatal,"unknown pcap link type : %d\n",ret);
+		myexit(-1);
+	}
+
+	char filter_exp[1000];
+
+	address_t tmp_addr;
+	if(get_src_adress2(tmp_addr,remote_addr)!=0)
+	{
+		mylog(log_error,"get_src_adress() failed, maybe you dont have internet\n");
+		myexit(-1);
+	}
+
+	string src=tmp_addr.get_ip();
+	string dst=remote_addr.get_ip();
+	if(raw_ip_version==AF_INET)
+	{
+		//sprintf(filter_exp,"ip and src %s and dst %s and (tcp or udp or icmp)",my_ntoa(source_ip_uint32),dst.c_str());
+		sprintf(filter_exp,"ip and src %s and dst %s and (tcp or udp or icmp)",src.c_str(),dst.c_str());
+	}
+	else
+	{
+		assert(raw_ip_version==AF_INET6);
+		sprintf(filter_exp,"ip6 and src %s and dst %s and (tcp or udp or icmp6)",src.c_str(),dst.c_str());
+
+	}
+
+	 if (pcap_compile(pcap_handle, &g_filter, filter_exp, 0, PCAP_NETMASK_UNKNOWN ) == -1) {
+		 printf("Bad filter - %s\n", pcap_geterr(pcap_handle));
+		 myexit(-1);
+	 }
+	 g_filter_compile_cnt++;
+
+
+	 if (pcap_setfilter(pcap_handle, &g_filter) == -1) {
+		 printf("Error setting filter - %s\n", pcap_geterr(pcap_handle));
+		 myexit(-1);
+	 }
+
+///////////////////////////////////////////////////////////////new thread created here
+		if(pthread_create(&pcap_recv_thread, NULL, pcap_recv_thread_entry, 0)) {
+			mylog(log_fatal, "Error creating thread\n");
+			myexit(-1);
+		}
+////////////////////////////////////////////////////////////////////////////////
+
+
+	g_ip_id_counter=get_true_random_number()%65535;
+
+	/*
+	if(lower_level==0)
+	{
+		raw_send_fd = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
+
+	    if(raw_send_fd == -1) {
+	    	mylog(log_fatal,"Failed to create raw_send_fd\n");
+	        //perror("Failed to create raw_send_fd");
+	        myexit(1);
+	    }
+
+	    int one = 1;
+	    const int *val = &one;
+	    if (setsockopt (raw_send_fd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) {
+	    	mylog(log_fatal,"Error setting IP_HDRINCL %d\n",errno);
+	        //perror("Error setting IP_HDRINCL");
+	        myexit(2);
+	    }
+
+
+	}
+	else
+	{
+		raw_send_fd = socket(PF_PACKET , SOCK_DGRAM , htons(ETH_P_IP));
+
+	    if(raw_send_fd == -1) {
+	    	mylog(log_fatal,"Failed to create raw_send_fd\n");
+	        //perror("Failed to create raw_send_fd");
+	        myexit(1);
+	    }
+		//init_ifindex(if_name);
+
+	}
+
+	if(force_socket_buf)
+	{
+		if(setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0)
+		{
+			mylog(log_fatal,"SO_SNDBUFFORCE fail  socket_buf_size=%d  errno=%s\n",socket_buf_size,strerror(errno));
+			myexit(1);
+		}
+	}
+	else
+	{
+		if(setsockopt(raw_send_fd, SOL_SOCKET, SO_SNDBUF, &socket_buf_size, sizeof(socket_buf_size))<0)
+		{
+			mylog(log_fatal,"SO_SNDBUF fail  socket_buf_size=%d  errno=%s\n",socket_buf_size,strerror(errno));
+			myexit(1);
+		}
+	}
+
+
+
+	//raw_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
+
+	raw_recv_fd= socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+
+    if(raw_recv_fd == -1) {
+    	mylog(log_fatal,"Failed to create raw_recv_fd\n");
+        //perror("");
+        myexit(1);
+    }
+
+	if(force_socket_buf)
+	{
+		if(setsockopt(raw_recv_fd, SOL_SOCKET, SO_RCVBUFFORCE, &socket_buf_size, sizeof(socket_buf_size))<0)
+		{
+			mylog(log_fatal,"SO_RCVBUFFORCE fail  socket_buf_size=%d  errno=%s\n",socket_buf_size,strerror(errno));
+			myexit(1);
+		}
+	}
+	else
+	{
+		if(setsockopt(raw_recv_fd, SOL_SOCKET, SO_RCVBUF, &socket_buf_size, sizeof(socket_buf_size))<0)
+		{
+			mylog(log_fatal,"SO_RCVBUF fail  socket_buf_size=%d  errno=%s\n",socket_buf_size,strerror(errno));
+			myexit(1);
+		}
+	}
+
+    //IP_HDRINCL to tell the kernel that headers are included in the packet
+
+
+
+    setnonblocking(raw_send_fd); //not really necessary
+    setnonblocking(raw_recv_fd);*/
+
+	return 0;
+}
+#endif
+#ifdef UDP2RAW_LINUX
 void init_filter(int port)
 {
 	sock_fprog bpf;
@@ -450,9 +797,160 @@ void init_filter(int port)
 		myexit(-1);
 	}
 }
+#endif
+
+#ifdef UDP2RAW_MP
+void init_filter(int port)
+{
+	/*
+	sock_fprog bpf;*/
+	if(raw_mode==mode_faketcp||raw_mode==mode_udp)
+	{
+		filter_port=port;
+	}
+
+
+
+	 char filter_exp[1000];
+
+	if(raw_ip_version==AF_INET)
+	{
+		if(raw_mode==mode_faketcp)
+		{
+			sprintf(filter_exp,"ip and tcp and src %s and src port %d and dst port %d",remote_addr.get_ip(),remote_addr.get_port(),port);
+		}
+		else if(raw_mode==mode_udp)
+		{
+			sprintf(filter_exp,"ip and udp and src %s and src port %d and dst port %d",remote_addr.get_ip(),remote_addr.get_port(),port);
+		}
+		else if(raw_mode==mode_icmp)
+		{
+			sprintf(filter_exp,"ip and icmp and src %s",remote_addr.get_ip());
+		}
+		else
+		{
+			mylog(log_fatal,"unknow raw mode\n");
+			myexit(-1);
+		}
+	}
+	else
+	{
+		assert(raw_ip_version==AF_INET6);
+		if(raw_mode==mode_faketcp)
+		{
+			sprintf(filter_exp,"ip6 and tcp and src %s and src port %d and dst port %d",remote_addr.get_ip(),remote_addr.get_port(),port);
+		}
+		else if(raw_mode==mode_udp)
+		{
+			sprintf(filter_exp,"ip6 and udp and src %s and src port %d and dst port %d",remote_addr.get_ip(),remote_addr.get_port(),port);
+		}
+		else if(raw_mode==mode_icmp)
+		{
+			sprintf(filter_exp,"ip6 and icmp6 and src %s",remote_addr.get_ip());
+		}
+		else
+		{
+			mylog(log_fatal,"unknow raw mode\n");
+			myexit(-1);
+		}
+	}
+
+	mylog(log_info,"filter expression is [%s]\n",filter_exp);
+
+	//pthread_mutex_lock(&pcap_mutex);//not sure if mutex is needed here
+
+	long long tmp_cnt=0;
+	if(use_pcap_mutex)
+	{
+		while(pthread_mutex_trylock(&pcap_mutex)!=0)
+		{
+			tmp_cnt++;
+			pcap_breakloop(pcap_handle);
+			if(tmp_cnt==100)
+			{
+				mylog(log_warn,"%lld attempts of pcap_breakloop()\n", tmp_cnt);
+			}
+			if(tmp_cnt%1000==0)
+			{
+				mylog(log_warn,"%lld attempts of pcap_breakloop()\n", tmp_cnt);
+				if(tmp_cnt>5000)
+				{
+					 mylog(log_fatal,"we might have already run into a deadlock\n");
+				}
+			}
+			ev_sleep(0.001);
+		}
+		mylog(log_info,"breakloop() succeed after %lld attempt(s)\n", tmp_cnt);
+	}
+
+	if(1)
+	{
+		int ret=pcap_setdirection(pcap_handle,PCAP_D_IN);
+		if(ret!=0) mylog(log_debug,"pcap_setdirection(pcap_handle,PCAP_D_IN) failed with value %d, %s\n",ret,pcap_geterr(pcap_handle));
+	}
+
+	assert(g_filter_compile_cnt!=0);
+	pcap_freecode(&g_filter);
+
+	 if (pcap_compile(pcap_handle, &g_filter, filter_exp, 0, PCAP_NETMASK_UNKNOWN ) == -1) {
+		 mylog(log_fatal,"Bad filter - %s\n", pcap_geterr(pcap_handle));
+		 myexit(-1);
+	 }
+	 g_filter_compile_cnt++;
+
+	 if (pcap_setfilter(pcap_handle, &g_filter) == -1)
+	 {
+		 mylog(log_fatal,"Error setting filter - %s\n", pcap_geterr(pcap_handle));
+		 myexit(-1);
+	 }
+
+
+	if(use_pcap_mutex) pthread_mutex_unlock(&pcap_mutex);
+	/*
+	if(disable_bpf_filter) return;
+	//if(raw_mode==mode_icmp) return ;
+	//code_tcp[8].k=code_tcp[10].k=port;
+	if(raw_mode==mode_faketcp)
+	{
+		bpf.len = sizeof(code_tcp)/sizeof(code_tcp[0]);
+		code_tcp[code_tcp_port_index].k=port;
+		bpf.filter = code_tcp;
+	}
+	else if(raw_mode==mode_udp)
+	{
+		bpf.len = sizeof(code_udp)/sizeof(code_udp[0]);
+		code_udp[code_udp_port_index].k=port;
+		bpf.filter = code_udp;
+	}
+	else if(raw_mode==mode_icmp)
+	{
+		bpf.len = sizeof(code_icmp)/sizeof(code_icmp[0]);
+		bpf.filter = code_icmp;
+	}
+
+	int dummy;
+
+	int ret=setsockopt(raw_recv_fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy)); //in case i forgot to remove
+	if (ret != 0)
+	{
+		mylog(log_debug,"error remove fiter\n");
+		//perror("filter");
+		//exit(-1);
+	}
+	ret = setsockopt(raw_recv_fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
+	if (ret != 0)
+	{
+		mylog(log_fatal,"error set fiter\n");
+		//perror("filter");
+		myexit(-1);
+	}*/
+}
+#endif
+
 void remove_filter()
 {
 	filter_port=0;
+#ifdef UDP2RAW_LINUX
 	int dummy;
 	int ret=setsockopt(raw_recv_fd, SOL_SOCKET, SO_DETACH_FILTER, &dummy, sizeof(dummy));
 	if (ret != 0)
@@ -461,10 +959,12 @@ void remove_filter()
 		//perror("filter");
 		//exit(-1);
 	}
+#endif
 }
 
 int init_ifindex(const char * if_name,int fd,int &index)
 {
+#ifdef UDP2RAW_LINUX
 	struct ifreq ifr;
 	size_t if_name_len=strlen(if_name);
 	if (if_name_len<sizeof(ifr.ifr_name)) {
@@ -481,8 +981,11 @@ int init_ifindex(const char * if_name,int fd,int &index)
 	}
 	index=ifr.ifr_ifindex;
 	mylog(log_info,"ifname:%s  ifindex:%d\n",if_name,index);
+#endif
 	return 0;
 }
+
+#ifdef UDP2RAW_LINUX
 bool interface_has_arp(const char * interface) {
     struct ifreq ifr;
    // int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
@@ -702,7 +1205,9 @@ int find_lower_level_info(u32_t ip,u32_t &dest_ip,string &if_name,string &hw)
 	dest_ip=ntohl(dest_ip);
 	return 0;
 }
+#endif
 
+#ifdef UDP2RAW_LINUX
 int send_raw_packet(raw_info_t &raw_info,const char * packet,int len)
 {
 	const packet_info_t &send_info=raw_info.send_info;
@@ -753,6 +1258,76 @@ int send_raw_packet(raw_info_t &raw_info,const char * packet,int len)
     }
     return 0;
 }
+#endif
+
+#ifdef UDP2RAW_MP
+
+int send_raw_packet(raw_info_t &raw_info,const char * packet,int len)
+{
+	const packet_info_t &send_info=raw_info.send_info;
+	const packet_info_t &recv_info=raw_info.recv_info;
+
+    if(! send_with_pcap)
+    {
+#ifndef NO_LIBNET
+
+		//g_ptag=libnet_build_ipv4(ip_tot_len, iph->tos, ntohs(iph->id), ntohs(iph->frag_off),
+		//	iph->ttl , iph->protocol , iph->check , iph->saddr, iph->daddr,
+		//	(const unsigned char *)payload, payloadlen, libnet_handle, g_ptag);
+
+		//assert(g_ptag!=-1 &&g_ptag!=0);
+
+		//int ret;
+		//ret= libnet_write(libnet_handle);
+
+		//assert(ret!=-1);
+
+
+		//iph->tot_len=htons(ip_tot_len);
+		//iph->check =csum ((unsigned short *) send_raw_ip_buf, iph->ihl*4);
+    	if(raw_ip_version==AF_INET)
+    	{
+    		libnet_write_raw_ipv4(libnet_handle,(const unsigned char *)packet,len);  //todo, this api is marked as internal, maybe we should avoid using it.
+    	}
+    	else
+    	{
+    		assert(raw_ip_version==AF_INET6);
+    		libnet_write_raw_ipv6(libnet_handle,(const unsigned char *)packet,len);
+    	}
+#endif
+    }
+    else
+    {
+    	char buf[buf_len];
+    	assert(pcap_header_captured==1);
+    	assert(pcap_link_header_len!=-1);
+    	memcpy(buf,pcap_header_buf,pcap_link_header_len);
+    	memcpy(buf+pcap_link_header_len,packet,len);
+    	//pthread_mutex_lock(&pcap_mutex); looks like this is not necessary, and it harms performance
+    	int ret=pcap_sendpacket(pcap_handle,(const unsigned char *)buf,len+pcap_link_header_len);
+		if(ret!=0)
+		{
+			mylog(log_fatal,"pcap_sendpcaket failed with vaule %d,%s\n",ret,pcap_geterr(pcap_handle));
+			//pthread_mutex_unlock(&pcap_mutex);
+			myexit(-1);
+		}
+    	//pthread_mutex_unlock(&pcap_mutex);
+		/*
+	unsigned char *p=(unsigned char *)send_raw_ip_buf0;
+	for(int i=0;i<ip_tot_len+pcap_link_header_len;i++)
+		printf("<%02x>",int(p[i]));
+	printf("\n");
+    	assert(pcap_sendpacket(pcap_handle,(const unsigned char *)pcap_header_buf,cap_len)==0);
+	p=(unsigned char *)pcap_header_buf;
+	for(int i=0;i<cap_len;i++)
+		printf("<%02x>",int(p[i]));
+	printf("\n");
+	printf("pcap send!\n");*/
+    }
+    return 0;
+}
+#endif
+
 int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
 {
 	const packet_info_t &send_info=raw_info.send_info;
@@ -796,16 +1371,28 @@ int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
 		iph->daddr = send_info.new_dst_ip.v4;
 
 		ip_tot_len=sizeof (struct my_iphdr)+payloadlen;
+#ifdef UDP2RAW_LINUX
 		if(lower_level)iph->tot_len = htons(ip_tot_len);            //this is not necessary ,kernel will always auto fill this  //http://man7.org/linux/man-pages/man7/raw.7.html
 		else
 			iph->tot_len = 0;
+#endif
+
+#ifdef UDP2RAW_MP
+		iph->tot_len = htons(ip_tot_len);//always fill for mp version
+#endif
 
 		memcpy(send_raw_ip_buf+sizeof(my_iphdr) , payload, payloadlen);
 
+#ifdef UDP2RAW_LINUX
 		if(lower_level) iph->check =
 				csum ((unsigned short *) send_raw_ip_buf, iph->ihl*4); //this is not necessary ,kernel will always auto fill this
 		else
 			iph->check=0;
+#endif
+
+#ifdef UDP2RAW_MP
+		iph->check =csum((unsigned short *) send_raw_ip_buf, iph->ihl*4);//always cal checksum for mp version
+#endif
     }
     else
     {
@@ -831,6 +1418,7 @@ int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen)
 
 int pre_recv_raw_packet()
 {
+#ifdef UDP2RAW_LINUX
 	assert(g_packet_buf_cnt==0);
 
 	g_sockaddr_len=sizeof(g_sockaddr.ll);
@@ -876,6 +1464,7 @@ int pre_recv_raw_packet()
 		return -1;
 	}
 	g_packet_buf_cnt++;
+#endif
 	return 0;
 }
 int discard_raw_packet()
@@ -884,6 +1473,7 @@ int discard_raw_packet()
 	g_packet_buf_cnt--;
 	return 0;
 }
+#ifdef UDP2RAW_LINUX
 int recv_raw_packet(char * &packet,int &len,int peek)
 {
 	assert(g_packet_buf_cnt==1);
@@ -912,6 +1502,19 @@ int recv_raw_packet(char * &packet,int &len,int peek)
 	len=g_packet_buf_len-int(link_level_header_len);
 	return 0;
 }
+#endif
+#ifdef UDP2RAW_MP
+int recv_raw_packet(char * &packet,int &len,int peek)
+{
+	assert(g_packet_buf_cnt==1);
+	if(!peek)
+		g_packet_buf_cnt--;
+
+	packet=g_packet_buf;
+	len=g_packet_buf_len;
+	return 0;
+}
+#endif
 int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen)
 {
 	char *raw_packet_buf;
@@ -966,11 +1569,12 @@ int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen)
 			return -1;
 		}
 	}
-
+#ifdef UDP2RAW_LINUX
 	if(lower_level)
 	{
 		memcpy(&recv_info.addr_ll,&g_sockaddr.ll,sizeof(recv_info.addr_ll));
 	}
+#endif
 
 
 
@@ -2535,7 +3139,7 @@ int try_to_list_and_bind2(int &fd,address_t address)  //try to bind to a port,ma
 	temp_bind_addr.sin_port = htons(port);
 	temp_bind_addr.sin_addr.s_addr = local_ip_uint32;*/
 
-	if (bind(fd, (struct sockaddr*)&address.inner, address.get_len()) !=0)
+	if (::bind(fd, (struct sockaddr*)&address.inner, address.get_len()) !=0)
 	{
 		mylog(log_debug,"bind fail\n");
 		return -1;

+ 34 - 0
network.h

@@ -30,6 +30,32 @@ extern int ifindex;
 extern char g_packet_buf[huge_buf_len];
 extern int g_packet_buf_len;
 extern int g_packet_buf_cnt;
+#ifdef UDP2RAW_MP
+extern queue_t my_queue;
+
+extern ev_async async_watcher;
+extern struct ev_loop* g_default_loop;
+
+extern pthread_mutex_t queue_mutex;
+extern int use_pcap_mutex;
+
+extern int pcap_cnt;
+
+extern int pcap_link_header_len;
+
+extern int send_with_pcap;
+extern int pcap_header_captured;
+extern int pcap_header_buf[buf_len];
+
+struct icmphdr
+{
+	uint8_t type;
+	uint8_t code;
+	uint16_t check_sum;
+	uint16_t id;
+	uint16_t seq;
+};
+#endif
 
 struct my_iphdr
   {
@@ -212,7 +238,9 @@ struct packet_info_t  //todo change this to union
 
 	bool has_ts;
 
+#ifdef UDP2RAW_LINUX
 	sockaddr_ll addr_ll;
+#endif
 
 	i32_t data_len;
 
@@ -241,7 +269,13 @@ void init_filter(int port);
 
 void remove_filter();
 
+#ifdef UDP2RAW_LINUX
 int init_ifindex(const char * if_name,int fd,int &index);
+#endif
+
+#ifdef UDP2RAW_MP
+int init_ifindex(const char * if_name,int &index);
+#endif
 
 int find_lower_level_info(u32_t ip,u32_t &dest_ip,string &if_name,string &hw);
 

+ 3 - 0
server.cpp

@@ -5,6 +5,7 @@
  *      Author: root
  */
 
+#ifndef UDP2RAW_MP
 
 #include "common.h"
 #include "network.h"
@@ -911,3 +912,5 @@ int server_event_loop()
 	}
 	return 0;
 }
+
+#endif