透明代理(NAT)

        透明代理的实现目前Linuxn内核提供两种实现的方式:NAT和TPROXY。Nat 方式其实就是内内核通过地址转换实现的;而 TPROXY 是内核通过对设置的数据包打标记,然后通过策略路由将打标记的数据包重定向到本地监听进程上。此次我们借助iptables的nat表的规则对数据包进行重定向。具体配置及步骤如下。

试验环境

          将试验环境的配置如下:

名称 IP地址 网关设置
客户端 192.168.200.184 192.168.200.111
代理服务器 192.168.200.111 192.168.200.1(内网真实网关IP)
服务器 172.16.9.66

        环境网络结构图如下:

透明代理(NAT)_第1张图片

 试验步骤

        1、需要添加iptables规则,将经过代理服务器的数据包重定向到本地代理监听进程上去;具体添加规则命令如下:     

        1、在nat表上新建名为MY_TCP自定义链
                 iptables -t nat -N MY_TCP

        2、将MY_TCP加入到PREROUTING链后
                iptables -t nat -A PREROUTING -d 172.16.9.66 -j MY_TCP

        3、将特定数据包转到6666端口
                iptables -t nat -A MY_TCP -p tcp --dport 12345 -j REDIRECT --to-ports 2223

        2、试验过程的客户端跟服务器用TCP工具创建一个客户端跟服务端。透明代理端需写简单的服务端代码,代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define PORT 2223		//端口号
#define BACKLOG 5	//最大监听数
 
int main()
{
	int iSocketFD = 0;  //socket句柄
	int iRecvLen = 0;   //接收成功后的返回值
	int new_fd = 0; 	//建立连接后的句柄
	char buf[4096] = {0}; //
	int n = 0;
	int ret = 0;
	struct sockaddr_in stLocalAddr = {0}; //本地地址信息结构图,下面有具体的属性赋值
	struct sockaddr_in stRemoteAddr = {0}; //对方地址信息
	socklen_t socklen = 0;  
 
	iSocketFD = socket(AF_INET, SOCK_STREAM, 0); //建立socket
	if(0 > iSocketFD)
	{
		printf("创建socket失败!\n");
		return 0;
	}	
 
	stLocalAddr.sin_family = AF_INET;  /*该属性表示接收本机或其他机器传输*/
	stLocalAddr.sin_port = htons(PORT); /*端口号*/
	stLocalAddr.sin_addr.s_addr=htonl(INADDR_ANY); /*IP,括号内容表示本机IP*/
 
	//绑定地址结构体和socket
	if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
	{
		printf("绑定失败!\n");
		return 0;
	}
 
	//开启监听 ,第二个参数是最大监听数
	if(0 > listen(iSocketFD, BACKLOG))
	{
		printf("监听失败!\n");
		return 0;
	}
 
	printf("iSocketFD: %d\n", iSocketFD);	
	//在这里阻塞知道接收到消息,参数分别是socket句柄,接收到的地址信息以及大小
	while(1)
	{
		new_fd = accept(iSocketFD, (void *)&stRemoteAddr, &socklen);
		printf("new_fd: %d\n", new_fd);	
		if(0 > new_fd)
		{
			printf("接收失败!\n");
			return 0;
		}else{
			printf("接收成功!\n");
			n = sizeof(struct sockaddr_in);
			ret = getsockopt(new_fd, SOL_IP, SO_ORIGINAL_DST, &stRemoteAddr, &n);
			if(0 != ret)
			{
				printf ("error getting original destination address.\n");
				close (new_fd);
				return -1;
			}
			stRemoteAddr.sin_family = AF_INET; 
			printf("original destination address %u:%hu\n", ntohl(stRemoteAddr.sin_addr.s_addr), ntohs(stRemoteAddr.sin_port));	
			//发送内容,参数分别是连接句柄,内容,大小,其他信息(设为0即可) 
			recv(new_fd, buf, sizeof(buf), 0);
			printf("从客户端上接收到的信息是:%s\n", buf);
			//send(new_fd, "这是代理服务器接收成功后发回的信息!", sizeof("这是代理服务器接收成功后发回的信息!"), 0);
 
			/* 连接服务器*/
			int iSockClientFD = 0;
			iSockClientFD = socket(AF_INET, SOCK_STREAM, 0);
			if(0 > iSockClientFD)					
			{
				printf("代理向服务器建立连接失败!\n");
				return 0;
			}
			if(0 > connect(iSockClientFD, (void *)&stRemoteAddr, sizeof(stRemoteAddr)))
			{
				printf("代理向服务器建立连接失败!\n");
				return 0;
			}
			send(iSockClientFD, buf, sizeof(buf), 0);//向服务器发送消息
			recv(iSockClientFD, buf, sizeof(buf), 0);//接收来自服务器的消息
			printf("从服务器端收到的消息:%s\n", buf);//打印接收到的来自服务器的消息
			send(new_fd, buf, sizeof(buf), 0);//向客户端发送消息		
			sleep(5);	
		}
	}
	close(new_fd);
	close(iSocketFD);
 
	return 0;
}

使用结果截图如下:

        1、代理服务器配置规则如下:

透明代理(NAT)_第2张图片

         2、客户端、服务器试验截图如下:

透明代理(NAT)_第3张图片

        3、代理服务器的代理监听程序打印如下:

透明代理(NAT)_第4张图片

你可能感兴趣的:(服务器,透明代理,iptables)