sock5 UDP代理通信及dante-1.4.0 实现篇

1:数据通信框图

sock5 UDP代理通信及dante-1.4.0 实现篇_第1张图片

上面是数据的流向,是双向的。此处主要是PC的数据进过router设备,之后到达proxy server,由proxy server转发之后到达UDPserver端。特定PC(特定IP及port)的数据进行WLAN设备的sock5客服端处理,直接将数据发送给UDP server。其中对于PC来说不用做任何的处理(sock5相关的协议),在此router设备完成了与sock5proxy 认证协商,链路建立,数据包头的添加与去除工作。

2: 实现细节说明

A:router设备完成与proxy的协商及获取proxy的动态port及IP。

      此处是需要根据通信协议与sock5服务交互完成动态port和IP的获取。

B:将第A步获取到的port及IP和UDPserver端的IP及port传递给内核。

      通过proc文件将应用层获取的port及IP传递给linux内核。

C:添加iptable规则将PC的目的地址更改为A中获取到的port及IP。在此之前PC的数据不能经过WLAN系统发送出去。对来特定源IP的PC的数据包做DNAT使其目的更改为:A中的port及IP。

D:在内核发送函数中添加sock5UDP包头(包括:UDPserver的port及IP)。

      其数据包头格式如下:

    +----+------+------+----------+----------+----------+

    |RSV| FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |

    +----+------+-----+-----------+------------+----------+

    |2   |  1     |    1   |Variable  |    2         | Variable |

    +----+------+------+----------+----------+----------+

其中:

o  RSV  保留字段,填0。

       o  FRAG    当前分片序号,我们没有分片,填0。

       o  ATYP    地址类型,和前面的几个一样。IPV4填 1 。

       o  DST.ADDR  UDP包最终的目的地址。即udp server端的IP地址

       o  DST.PORT   UDP包最终的目的端口。即udp server端的port。

       o  DATA       原始的UDP包的数据。

按照上面格式发出的UDP包中的DATA部分会被代理服务器转发到包头中填入的最终目的地址。

D:在内核接受函数中移除sock5UDP包头(包括:UDPserver的port及IP)。

3:实现代码

A :router上面代理服务器动态port及IP的获取及iptables规则的配置。

sock5 UDP代理通信及dante-1.4.0 实现篇_第2张图片


/*
 ============================================================================
 Name        : doproxyDNAT.c
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define SOCKET_ERROR -1
#define closesocket close

#define PROXY_PORT  			1080
#define PROXY_IPADDR 			"192.168.100.10"

#define UDP_SERVER_PORT			  6666
#define UDP_SERVER_IPADDR 		 "10.10.98.2"

#define UDP_CLIENT_PORT			  5555
#define UDP_CLIENT_IPADDR 		 "192.168.100.20"

#define ZF5_BUFFER_SIZE1 255
#define ZF5_BUFFER_SIZE2 1024
#define ZF5_BUFFER_SIZE3 8192
#define USER_NAME 				"comba"
#define USER_PASSWORD			"comba123"

static char *proxyReplyIp=NULL;
static int proxyReplyPort=0;
static void sigHandler(int sig)
{
	char cmdbuf[500];
	memset(cmdbuf,0,500);
 //   if ((sig == SIGINT ) || (sig == SIGKILL ) )
    {
		//删除建立的规则
		sprintf(cmdbuf,"iptables -t nat -D PREROUTING -s 192.168.1.0/24 -p udp -j DNAT --to %s:%d",proxyReplyIp,proxyReplyPort);
		printf("%s\n",cmdbuf);
		system(cmdbuf);
		exit(0);
    }
}
int main(void)
{
		 int nRet=0;
		 int len=0;
		 int s_sock5_tcp=socket(AF_INET,SOCK_STREAM,0);
		 if( s_sock5_tcp < 0 )
		 {
			 return -1;
		 }
		 else
		 {
			 printf("create tcp socket ok\n");
		 }

		 struct timeval tv;
		 tv.tv_sec=10;
		 tv.tv_usec=0;
		 if(setsockopt(s_sock5_tcp,SOL_SOCKET,SO_RCVTIMEO,(char *)&tv,sizeof(struct timeval))==-1)
		 {
			  close(s_sock5_tcp);
			  return -1;
		 }
		 else
		 {
			 printf("setsockopt  ok\n");
		 }
		 struct sockaddr_in sa_1;
		 sa_1.sin_family=AF_INET;
		 sa_1.sin_addr.s_addr=inet_addr(PROXY_IPADDR);
		 sa_1.sin_port=htons(PROXY_PORT);
		 if(sa_1.sin_addr.s_addr==INADDR_NONE)
		 {
			 perror("proxy server ip\n");
		 }
		 if(connect(s_sock5_tcp,(struct sockaddr *)&sa_1,sizeof(struct sockaddr_in))==-1)
		 {
			 close(s_sock5_tcp);
			 printf("connect  proxy server fail  \n");
			 return -1;
		 }
		 else
		 {
			 printf("connect proxy server  ok\n");
		 }
		 char sz_buf[ZF5_BUFFER_SIZE2+2];
		 memset(sz_buf,0,ZF5_BUFFER_SIZE2);
		 int authTYpe=0;
	if(authTYpe == 0)
	{
		 sz_buf[len++]=0x05;
		 sz_buf[len++]=0x01;
		 sz_buf[len++]=0x00;
	}
	else
	{
		 sz_buf[len++]=0x05;
		 sz_buf[len++]=0x02;
		 sz_buf[len++]=0x00;
		 sz_buf[len++]=0x02;
	}

	printf("-----------------\n");
		 if(send(s_sock5_tcp,sz_buf,len,0)==-1)
		 {
			 close(s_sock5_tcp);
			 printf("send error");
			 return -1;
		 }
		 else
		 {
			 printf("---333-----\n");
		 }
	#if 0
			int		nfds=0;
			fd_set		readfds;
			struct timeval	timeout;

			FD_ZERO(&readfds);
			FD_SET(s_sock5_tcp, &readfds);
			timeout.tv_sec = 10;
			timeout.tv_usec = 0;
			nfds = s_sock5_tcp + 1;

			nfds = select(nfds, &readfds, NULL, NULL, &timeout);
			if (nfds > 0)
			{

			}
			char resNego[2];
			memset(resNego,0,2);
			int nRcvd=0,nCount=0;
		 	while(1)
		 	{
		 		if(FD_ISSET(s_sock5_tcp,&readfds))
		 		{
		 			//接收sock[0]发送来的数据
		 			do
		 			{
		 				nRet = recv(s_sock5_tcp, (char*)resNego+nRcvd, 2-nRcvd,0);
		 				if(nRet==SOCKET_ERROR)
		 				{
		 					perror("recv error ");
		 				}
		 				nRcvd += nRet;
		 			}
		 			while((nRcvd!=2)&&(++nCount<1000));
		 			if(nRcvd==2)
					{
		 				break;
					}
		 		}
		 		if(nCount++>=2000)
		 		{
		 			peeor("recv ");
		 		}
		 	}
		 	if(resNego[0]!=0x05 || (resNego[1]!=0x00 && resNego[1]!=0x02))
		 	{
		 		perror("");
		 	}
	#endif

		 memset(sz_buf,0,ZF5_BUFFER_SIZE2);
		 if(recv(s_sock5_tcp,sz_buf,ZF5_BUFFER_SIZE2,0)==-1)
		 {
			close(s_sock5_tcp);
			printf("--line--- %d \n",__LINE__);
			return -1;
		 }
	/*
	 *
	           +----+------+----------+------+----------+
	           |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
	           +----+------+----------+------+----------+
	           | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
	           +----+------+----------+------+----------+
	 * */
		 if(sz_buf[0]==0x05&&sz_buf[1]==0x02)//auth with password
		 {
			  int sndlen=0;
			  memset(sz_buf,0,ZF5_BUFFER_SIZE2);
			  sz_buf[sndlen++]=0x01;

			  sz_buf[sndlen++]=strlen(USER_NAME);
			  memcpy((void *)&(sz_buf[sndlen]),(void *)USER_NAME,strlen(USER_NAME));
			  sndlen+=strlen(USER_NAME);

			  sz_buf[sndlen++]=strlen(USER_PASSWORD);
			  memcpy((void *)&(sz_buf[sndlen]),(void *)USER_PASSWORD,strlen(USER_PASSWORD));
			  sndlen+=strlen(USER_PASSWORD);

			  if(send(s_sock5_tcp,sz_buf,sndlen,0)==SOCKET_ERROR)
			  {
				   closesocket(s_sock5_tcp);
				   printf("--line--- %d \n",__LINE__);
				   return -1;
			  }
	/*
			check username and password
			The server verifies the supplied UNAME and PASSWD, and sends the following response:

			                        +----+--------+
			                        |VER | STATUS |
			                        +----+--------+
			                        | 1  |   1    |
			                        +----+--------+

			   A STATUS field of X'00' indicates success. If the server returns a `failure' (STATUS value other than X'00') status, it MUST close the
			   connection.
	* */
			  memset(sz_buf,0,ZF5_BUFFER_SIZE2);
			  if(recv(s_sock5_tcp,sz_buf,ZF5_BUFFER_SIZE2,0)==SOCKET_ERROR)
			  {
				   closesocket(s_sock5_tcp);
				   printf("--line--- %d \n",__LINE__);
				   return -1;
			  }
			  if(sz_buf[0]!=0x01||sz_buf[1]!=0x00)
			  {
				   closesocket(s_sock5_tcp);
				   printf("--line--- %d \n",__LINE__);
				   return -1;
			  }
		 }
		 if(sz_buf[0]==0x05&&sz_buf[1]==0x00)//auth no password
		 {
			 printf("auth no password ok");
		 }

		 //前面是认证过程,接着是链路的链路的建立过程
		 /*
		 	  客户端会用通过认证的这个TCP连接发送UDP穿透请求,信令格式如下:
		     +----+-----+-------+------+----------+----------+
		     |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
		     +----+-----+-------+------+----------+----------+
		     | 1  |  1  | X'00' |  1   | Variable |    2     |
		     +----+-----+-------+------+----------+----------+

		     client的本地地址即端口,这个很重要,要填客户端想发送/接收UDP包的本地端口
		Where:
		o  VER    protocol version: X'05'
		o  CMD
		o  CONNECT X'01'
		o  BIND X'02'
		o  UDP ASSOCIATE X'03'
		o  RSV    RESERVED
		o  ATYP   address type of following address
		o  IP V4 address: 		X'01'
		o  DOMAINNAME:		 X'03'
		o  IP V6 address: 	X'04'
		o  DST.ADDR       desired destination address
		o  DST.PORT desired destination port in network octet
		order client的本地地址即端口
		 */
		 	 memset(sz_buf,0,ZF5_BUFFER_SIZE2);
		 	 sz_buf[0]=0x05;
		 	 sz_buf[1]=0x03;
		 	 sz_buf[2]=0x00;
		 	 sz_buf[3]=0x01;

			 printf("---7777777777-----\n");
			 int nAddr = inet_addr( UDP_CLIENT_IPADDR );
			 short nPort = htons( (short)UDP_CLIENT_PORT );

			 memcpy( &sz_buf[4], (void *)&nAddr, 4 );			 //client的本地地址即端口
			 memcpy( &sz_buf[8], (void *)&nPort, 2 );		 //client的本地地址即端口
		 	 if(send(s_sock5_tcp,sz_buf,10,0)==SOCKET_ERROR)
		 	 {
		 		  closesocket(s_sock5_tcp);
		 		 printf("--line--- %d \n",__LINE__);
		 		  return -1;
		 	 }
		 	 memset(sz_buf,0,ZF5_BUFFER_SIZE2);
		 	 if(recv(s_sock5_tcp,sz_buf,ZF5_BUFFER_SIZE2,0)==SOCKET_ERROR)
		 	 {
		 		  closesocket(s_sock5_tcp);
		 		  printf("--line--- %d \n",__LINE__);
		 		  return -1;
		 	 }
		 	 if(sz_buf[0]!=0x05||sz_buf[1]!=0x00)
		 	 {
		 		  closesocket(s_sock5_tcp);
		 		  printf("--line--- %d \n",__LINE__);
		 		  return -1;
		 	 }
		 	 else
		 	 {
		 		 printf("receive response  ok --line--- %d \n",__LINE__);
		 	 }
		 	 /*
		 	// 接收回应。
		 	/**
		 	+----+-----+-------+------+----------+----------+
		 	|VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
		 	+----+-----+-------+------+----------+----------+
		 	| 1  |  1  | X'00' |  1   | Variable |    2     |
		 	+----+-----+-------+------+----------+----------+

		 	Where:

		 	o  VER    protocol version: X'05'
		 	o  REP    Reply field:
		 	o  X'00' succeeded
		 	o  X'01' general SOCKS server failure
		 	o  X'02' connection not allowed by ruleset
		 	o  X'03' Network unreachable
		 	o  X'04' Host unreachable
		 	o  X'05' Connection refused
		 	o  X'06' TTL expired
		 	o  X'07' Command not supported
		 	o  X'08' Address type not supported
		 	o  X'09' to X'FF' unassigned
		 	o  RSV    RESERVED
		 	o  ATYP   address type of following address
						o  IP V4 address: 		X'01'
						o  DOMAINNAME:		    X'03'
						o  IP V6 address: 	    X'04'
		 o  BND.ADDR   此UDP穿透通道对应的代理服务器地址。
		 o  BND.PORT    此UDP穿透通道对应的代理服务器端口。
		 至此,UDP穿透通道已经被建起来了,客户端只要按标准格式将UDP包发往上述地址端口,UDP包就会被代理服务器转发出去。
		 	 	m_strIPProxyReply = inet_ntoa( *(IN_ADDR*)(&abyUdpAssociateBuf[4]) );
		 	m_sPortProxyReply = ntohs( *(short*)( &abyUdpAssociateBuf[8] ) );
		 */

		 	 if(sz_buf[3]==0x01)
		 	 {
		 		printf("ip\n");
		 		struct sockaddr_in sockaddr;
		 		char cmdbuf[500];
		 		memset(cmdbuf,0,sizeof(cmdbuf));

		 		proxyReplyIp = inet_ntoa( *(struct in_addr *)(&sz_buf[4]) );
		 		proxyReplyPort = ntohs( *(short*)( &sz_buf[8] ) );
		 		int nProxyIp = inet_addr( proxyReplyIp );
		 		sockaddr.sin_family = AF_INET;
		 		sockaddr.sin_addr.s_addr = nProxyIp;
		 		sockaddr.sin_port = htons( proxyReplyPort);
		 		printf("ip:%s port:%d\n",proxyReplyIp,proxyReplyPort);

		 		//添加iptables规则,使目的地址即192.168.1.0/24为源Ip的数据包的目的地址都改为:代理服务器的IP地址及port.
		 		//sprintf(cmdbuf,"iptables -t nat -A PREROUTING -s 192.168.1.0/24 -p udp --sport 5555 -j DNAT --to %s:%d",proxyReplyIp,proxyReplyPort);
		 		sprintf(cmdbuf,"iptables -t nat -A PREROUTING -s 192.168.1.0/24 -p udp  -j DNAT --to %s:%d",proxyReplyIp,proxyReplyPort);
		 		printf("%s\n",cmdbuf);
		 		system(cmdbuf);

		 		sprintf(cmdbuf,"echo %d  > /proc/sock5_udp/sock5_proxy_port",proxyReplyPort);
		 		printf("%s\n",cmdbuf);
		 		system(cmdbuf);

		 		system("echo 1 > /proc/sock5_udp/sock5_udp_link_status");
		 		printf("echo 1 > /proc/sock5_udp/sock5_udp_link_status\n");

		 		//----------------------------------------------------------------------------
		 	    struct sigaction sa;
		 	    sa.sa_handler = sigHandler;
		 	    sigemptyset(&sa.sa_mask);
		 	    sa.sa_flags = 0;
		 	    sigaction(SIGALRM, &sa, NULL);
		 	    sigaction(SIGHUP, &sa, NULL);
		 	    sigaction(SIGTERM, &sa, NULL);
		 	    sigaction(SIGINT, &sa, NULL);
		 	    sigaction(SIGKILL, &sa, NULL);

			 	 while(1)
			 	 {
			 		sleep(1);
			 	 }

		 	 }
		 	 else if(sz_buf[3]==0x03)
		 	 {
		 		 	 printf("domain \n");
		 	 }
		 	 else
		 	 {
		 		  closesocket(s_sock5_tcp);
		 		  printf("haha--------------------\n");
		 		  return -1;
		 	 }
}

B:驱动层socke5 udp包头的添加与处理

router上面打印驱动层信息

sock5 UDP代理通信及dante-1.4.0 实现篇_第3张图片

今天测试的时候,花了半天的时间,就是不能正常通信,最后分析原因:首先看看proxy server eth1上面的数据包(在下面),当时也不知道怎么整,源port为:5555。自己没有添加iptables规则更改源port为5555.。下面的iptable规则是后来添加的:可能跟后面的数据包对不上,原理是一样的。

/proc/sock5_udp # iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DNAT       udp  --  192.168.1.0/24       anywhere            udp spt:7777 to:192.168.100.10:55061 

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
SNAT       udp  --  anywhere             anywhere            udp spt:7777 to:192.168.100.20:5555 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
/proc/sock5_udp # ls
sock5_proxy_port       sock5_udp_server_ip
sock5_udp_link_status  sock5_udp_server_port
/proc/sock5_udp # cat sock5_proxy_port
55061
/proc/sock5_udp # cat sock5_udp_server_ip
10.10.98.2
/proc/sock5_udp # cat sock5_udp_server_port
9999
/proc/sock5_udp # cat sock5_udp_link_status


router eth1上面抓包:

sock5 UDP代理通信及dante-1.4.0 实现篇_第4张图片

proxy server eth0上面抓包,主要查看数据包的长度为11和10

sock5 UDP代理通信及dante-1.4.0 实现篇_第5张图片

proxy server eth1上面抓包,主要查看数据包的长度为21和20,可以看看UDP包头之后就是10个自己的sock5的头。

sock5 UDP代理通信及dante-1.4.0 实现篇_第6张图片

在udp server 端的数据为:

sock5 UDP代理通信及dante-1.4.0 实现篇_第7张图片

PC端的数据为:

sock5 UDP代理通信及dante-1.4.0 实现篇_第8张图片


加添包头处理:

int sock5_udp_hard_start(struct sk_buff *skb, struct net_device *dev)
{
 		unsigned char * sock5_header_data;

		struct udp_sock5_header *sock5_header=NULL;
	    struct iphdr *iph; 
  		struct udp_hdr *udph;
  		struct ethhdr *macHeader;
  		int macHeaderLen = ETH_HLEN;
  		int ipHeaderLen = 0 ;
  		
  		macHeader= (struct ethhdr *)(skb->data);
  		if(0x8100==macHeader->h_proto)
		{
  			macHeaderLen+=4; //vlan len
		}
  		iph=(struct iphdr *)(skb->data+macHeaderLen);
  		ipHeaderLen=iph->ihl<<2;//IP_HEAD_LEN
  		
			if(IPPROTO_UDP == iph->protocol)
			{	
				if(sock5_udp_link_status == 1)
				{
					udph = (struct udp_hdr *)(skb->data + macHeaderLen + ipHeaderLen);
					if(udph->dest ==sock5_proxy_port)
					{ 
			#if DEBUG_SOCK5_UDP
						if(skb->len > SOCK5_UDP_MAX_SKB_LEN)
						{
							printk("ERROR data len too large ..................\n");
						}
						else
						{
							if ((skb->data - skb->head) < SOCK5_ADD_UDP_HREAD_LEN)
						    {
						    	pskb_expand_head(skb, skb->data - skb->head + SOCK5_ADD_UDP_HREAD_LEN, 0, GFP_ATOMIC);
									printk("---------pskb_expand_head-------------\n");
							}
					    	skb_push(skb, SOCK5_ADD_UDP_HREAD_LEN);
					    	memcpy(skb->data, skb->data + SOCK5_ADD_UDP_HREAD_LEN,  macHeaderLen + ipHeaderLen + UDP_HEAD_LEN);
							
						#if 1
	  						sock5_header_data = (unsigned char *)skb->data + ETH_HLEN + IP_HEAD_LEN + UDP_HEAD_LEN;       //

							sock5_header_data[0]=0x00;
							sock5_header_data[1]=0x00;
							sock5_header_data[2]=0x00;
							sock5_header_data[3]=0x01;
							memcpy(&sock5_header_data[4],(void *)&udp_server_ipaddr,4);
							memcpy(&sock5_header_data[8],(void *)&udp_server_port,  2);
						#endif
							//new udp header
							udph = (struct udp_hdr *)(skb->data + macHeaderLen + ipHeaderLen);
							udph->len = htons(skb->len - macHeaderLen - ipHeaderLen);
							udph->check = 0;
							//new ip header
							iph=(struct iphdr *)(skb->data	+ macHeaderLen);
						  	iph->tot_len    =   htons(skb->len - macHeaderLen);    //
						  	ip_send_check(iph); 			  
							print_ip_buffer(skb, (char *)"sock5_udp_hard_start", __LINE__);


						}

			#endif 			
					}	
					
				}		
			}
			#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))
			    return  athr_gmac_hard_start(skb,dev);
			#else
			    return  ag934x_hard_start(skb,dev);
			#endif

}

去除包头处理:

int sock5_udp_header_remove(struct sk_buff *skb)
{

		int macHeaderLen = ETH_HLEN;
  		int headerLen =0;
		int ipHeaderLen = IP_HEAD_LEN ;
		struct udp_hdr *udph=NULL;
		struct ethhdr 	*macHeader=NULL;
		struct iphdr *  iph=NULL;
		macHeader= (struct ethhdr *)(skb->data);
		if(0x8100==macHeader->h_proto)
		{
  			macHeaderLen+=4; //vlan len
		}
		headerLen= macHeaderLen + IP_HEAD_LEN + UDP_HEAD_LEN;
		iph = (struct iphdr *)(skb->data + macHeaderLen); 	
		if(IPPROTO_UDP == iph->protocol)
		{		
			if(sock5_udp_link_status == 1)
			{
			#if DEBUG_SOCK5_UDP
				udph = (struct udp_hdr *)(skb->data + macHeaderLen + ipHeaderLen);
				if(udph->source == sock5_proxy_port)
				{ 
			   		memcpy(skb->data+headerLen, skb->data + headerLen + SOCK5_ADD_UDP_HREAD_LEN, udph->len-SOCK5_ADD_UDP_HREAD_LEN);
					udph->len = htons(skb->len - macHeaderLen - IP_HEAD_LEN - SOCK5_ADD_UDP_HREAD_LEN);
					udph->check = 0;
					skb_trim(skb,skb->len-SOCK5_ADD_UDP_HREAD_LEN);

					iph=(struct iphdr *)(skb->data	+ macHeaderLen);
				  	iph->tot_len    =   htons(skb->len - macHeaderLen);    //
				  	ip_send_check(iph); 
					print_ip_buffer(skb, (char *)"sock5_udp_header_remove", __LINE__);
				}				
			#endif 
			
		   }		
		}
}





你可能感兴趣的:(sock5,udp)