• 基于py的网络地址转换(NAT)


    基于 py 的网络地址转换(NAT)

    实验内容

    实验内容一

    SNAT 实验

    • 运行给定网络拓扑(nat_topo.py)

    • 在 n1, h1, h2, h3 上运行相应脚本

      • n1: disable_arp.sh, disable_icmp.sh, disable_ip_forward.sh, disable_ipv6.sh
      • h1-h3: disable_offloading.sh, disable_ipv6.sh
    • 在 n1 上运行 nat 程序: n1# ./nat exp1.conf

    • 在 h3 上运行 HTTP 服务:h3# python ./http_server.py

    • 在 h1, h2 上分别访问 h3 的 HTTP 服务

    实验内容二

    DNAT 实验

    • 运行给定网络拓扑(nat_topo.py)

    • 在 n1, h1, h2, h3 上运行相应脚本

      • n1: disable_arp.sh, disable_icmp.sh, disable_ip_forward.sh, disable_ipv6.sh
      • h1-h3: disable_offloading.sh, disable_ipv6.sh
    • 在 n1 上运行 nat 程序: n1# ./nat exp2.conf

    • 在 h1, h2 上分别运行 HTTP Server: h1/h2# python ./http_server.py

    • 在 h3 上分别请求 h1, h2 页面

    实验内容三

    • 手动构造一个包含两个 nat 的拓扑

      • h1 <-> n1 <-> n2 <-> h2
    • 节点 n1 作为 SNAT, n2 作为 DNAT,主机 h2 提供 HTTP 服务,主机 h1 穿过两个 nat 连接到 h2 并获取相应页面

    设计思路

    配置 config 文件

    int parse_config(const char *filename) 函数

    负责根据 config 文件中读取的每一行字符串,分别配置 external-iface,internal-iface 以及 DNAT Rules。 具体实现如下:

    int parse_config(const char *filename) {
    	FILE * fd = fopen(filename, "r");
    	if (fd == NULL) {
    		return 0;
    	}
    	char * line = (char *)malloc(MAX_LINE);
    	while (fgets(line, MAX_LINE, fd) != NULL) {
    		if (strstr(line, internal_iface_des)) {
    			parse_internal_iface(line);
    		} else if (strstr(line, external_iface_des)) {
    			parse_external_iface(line);
    		} else if (strstr(line, dnat_rules_des)) {
    			parse_dnat_rules(line);
    		}
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    其中调用了三个自己编写的 parse 函数,负责具体条目的配置。

    区分数据包方向

    static int get_packet_direction(char *packet) 函数

    负责返回数据包方向:

    当源地址为内部地址,且目的地址为外部地址时,方向为 DIR_OUT

    当源地址为外部地址,且目的地址为 external_iface 地址时,方向为 DIR_IN

    具体设计时,可以根据源地址进行判断。具体实现如下:

    static int get_packet_direction(char *packet)
    {
    	struct iphdr * ip = packet_to_ip_hdr(packet);
    	rt_entry_t * rt = longest_prefix_match(ntohl(ip->saddr));
    	if (rt->iface->index == nat.internal_iface->index) {
    		return DIR_OUT;
    	} else if (rt->iface->index == nat.external_iface->index) {
    		return DIR_IN;
    	}
    	return DIR_INVALID;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果验证

    实验一结果

    实验结果如下:

    在这里插入图片描述

    上图可知,H1 和 H2 作为客户端向服务器端 H3 请求了两个网页。请求结果如下:

    H3->H1:

    在这里插入图片描述

    H3->H2:

    在这里插入图片描述

    由上述结果可知,SNAT 转换实验成功。

    实验二结果

    实验结果如下:

    在这里插入图片描述

    上图可知,H1 和 H2 作为服务器端,H3 作为客户端分别向 H1 和 H2 请求了两个网页。请求结果如下:

    H1 -> H3:

    在这里插入图片描述

    H2 -> H3:
    在这里插入图片描述

    由上述结果可知,DNAT 转换实验成功。

    实验三结果

    自建的网络拓扑文件如下:

        h1.cmd('ifconfig h1-eth0 10.21.0.1/16')
        h1.cmd('route add default gw 10.21.0.254')
    
        h2.cmd('ifconfig h2-eth0 10.22.0.1/16')
        h2.cmd('route add default gw 10.22.0.254')
    
        n1.cmd('ifconfig n1-eth0 10.21.0.254/16')
        n1.cmd('ifconfig n1-eth1 159.226.39.43/24')
    
        n2.cmd('ifconfig n2-eth0 10.22.0.254/16')
        n2.cmd('ifconfig n2-eth1 159.226.39.123/24')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    H1 <-> N1 <-> N2 <-> H2

    节点 N1 作为 SNAT, N2 作为 DNAT,主机 H2 提供 HTTP 服务,主机 H1 穿过两个 nat 连接到 h2 并获取相应页面。

    实验结果如下:
    在这里插入图片描述

    上图可知,H1 和 H2 作为客户端向服务器端 H3 请求了两个网页。请求结果如下:

    H2 -> H1:

    在这里插入图片描述

    由上述结果可知,实验三成功。

    调研 NAT 系统如何支持 ICMP 协议

    ICMP 的报文格式如下:

    类型(Type)代码(Code)检验和(Checksum)
    标识符(Identifier)序列号(Sequence number)
    选项(Option)

    当主机发送 ICMP 报文的时候,会根据 Type+Code 的值,来生成源端口号,根据 Identifier 的值生成目的端口号,即发送到路由器的报文如下:

    源报文:

    源 IP源端口目的 IP目的端口
    192.168.0.2(Type+Code)200.10.2.1Identifier

    在路由器上进行 SNAT,源 IP 更改后 ICMP 报文中的 Identifier 会改变,记作 IDENTIFIER。

    此时报文如下:

    源 IP源端口目的 IP目的端口
    188.10.1.2IDENTIFIER200.10.2.1Identifier

    对应的 NAT 表:

    源 IP源端口协议目的 IP目的端口
    192.168.0.2(Type+Code)ICMP188.10.1.2IDENTIFIER

    在服务器收到 ICMP 请求后,生成 ICMP 响应报文,响应报文中的(Type+Code)会作为源端口,IDENTIFIER 作为目的端口。

    源报文

    源 IP源端口目的 IP目的端口
    200.10.2.1(Type+Code)188.10.1.2IDENTIFIER
    报文到达路由器后,根据 NAT 表中,查询目的 IP 和目的端口为 188.10.1.2 和 IDENTIFIER 的信息。将目的 IP 和目的端口换为 192.168.0.2 和(Type+Code),报文就可以成功的到达客户端了。
  • 相关阅读:
    fatal error C1083: 无法打开包括文件:“stdint.h”: No such file or directory
    下载遥感数据慢的原因
    hudi系列-文件归档(archive)
    推荐5款经过时间验证的神级软件
    接口测试项目实战,充值接口+取现接口,资深测试带你一文打通...
    Android悬浮窗框架
    磁盘的基本知识和基本命令
    Day38—— 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯 (动态规划)
    leetcode/爬楼梯的最少成本
    【体系结构】IEEE754浮点数标准学习与机器码表示总结
  • 原文地址:https://blog.csdn.net/newlw/article/details/126919536