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

发布于:2022-12-13 ⋅ 阅读:(446) ⋅ 点赞:(0)

基于 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;
}

其中调用了三个自己编写的 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;
}

结果验证

实验一结果

实验结果如下:

在这里插入图片描述

上图可知,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')

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.1 Identifier

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

此时报文如下:

源 IP 源端口 目的 IP 目的端口
188.10.1.2 IDENTIFIER 200.10.2.1 Identifier

对应的 NAT 表:

源 IP 源端口 协议 目的 IP 目的端口
192.168.0.2 (Type+Code) ICMP 188.10.1.2 IDENTIFIER

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

源报文

源 IP 源端口 目的 IP 目的端口
200.10.2.1 (Type+Code) 188.10.1.2 IDENTIFIER
报文到达路由器后,根据 NAT 表中,查询目的 IP 和目的端口为 188.10.1.2 和 IDENTIFIER 的信息。将目的 IP 和目的端口换为 192.168.0.2 和(Type+Code),报文就可以成功的到达客户端了。

网站公告

今日签到

点亮在社区的每一天
去签到