实验目的
给定网络拓扑以及节点的网络地址配置(包含私网地址),实现NAT地址转换功能,使得左侧的私网H1节点能够连接H2节点并传输数据
实验拓扑

实验内容
- 运行给定网络拓扑(nat_topo.py)
1 | sudo python2 topo/nat_topo.py |
- 在n1中启动NAT服务
1 | ./scripts/disable_arp.sh |
- 在h2节点启动简易HTTP服务器
1 | ./scripts/disable_offloading.sh # 防止协议栈生成错误的checksum |
- 在h1节点启动wget请求h2
1 | ./scripts/disable_offloading.sh # 防止协议栈生成错误的checksum |
主要数据结构
1 | struct nat_connection { |
实验过程
本实验老师已经给了框架,只需要将几个函数的功能实现就可以了。所以这里只介绍每个函数的功能,具体实现见源代码。
代码地址:https://gitee.com/873314461/nat_stack
is_flow_finished
这个函数主要是判断TCP流有没有结束,如果TCP两端均发送了FIN报文且seq_end与ack相等,则证明TCP流已经结束了。
即同时满足以下4个条件时,TCP流已经结束。
1 | internal_fin == true |
nat_lookup_external
这个函数是通过external_port在mapping_list中查找对应的nat_mapping对象。
只需要遍历整个链表,找到external_port相等的节点返回即可。
nat_lookup_internal
与上个函数作用类似,只是通过internal_ip和internal_port在mapping_list中查找对应的nat_mapping对象。
assign_external_port
分配一个未使用的external_port。
只需要遍历端口池(nat.assigned_ports),若nat.assigned_ports[port]为0,则将其置为1,则返回port。
free_port
释放一个端口。
将nat.assigned_ports[port]置为0。
nat_insert_mapping
创建一个nat_mapping对象,并将其插入到hash表中。
需要:
- 申请内存。
- 初始化相应信息。
- 插入到list中。
- 并将nat_mapping指针返回。
get_packet_direction
这个函数主要是通过packet的内容,判断这个报文的传送方向是DIR_IN还是DIR_OUT。
判断方法是,用packet的目的IP查找路由表,得到相应的iface。若iface与internal_iface相同,则方向为DIR_IN;若iface与external_iface相同,则方向为DIR_OUT。
具体方法如下:
- 将packet解析。
- 根据目的IP查找路由表。
- 比较iface,并返回结果。
nat_update_tcp_connection
这个函数用来更新nat_mapping对象中的tcp信息。包括:最后连接时间(update_time)和nat_connection对象。
- 解析packet。
- 计算TCP报文的seq_end。
- 更新update_time。
- 更新nat_connection对象。
PS: 注意网络序与主机序的转换!
nat_get_mapping_from_packet
通过packet在nat_mapping_list中查找对应的nat_mapping对象。
若报文方向为DIR_IN,则通过external查找。
若报文方向为DIR_OUT,则通过internal查找。
do_translation
这个函数是NAT实验的核心函数。实现真正的包转发。
- 根据(server_ip, server_port)计算hash
- 查找packet所对应的nat_mapping对象。
- 若未找到nat_mapping对象,且传输方向为DIR_OUT,则插入到nat_mapping_list中。
- 修改packet的源、目的IP地址和端口。
- 重新计算TCP和IP的checksum。
- 更新nat_mapping对象中的TCP信息。
- 将报文发送出去。
nat_timeout
这是一个单独运行的线程,用来关闭并回收已经结束的或者超时的TCP流的nat_mapping对象。
每隔一定时间,遍历整个nat_mapping_list,将超时的或者已经结束的nat_mapping对象移除,并释放资源。
PS:遍历list时,一定要使用list_for_each_entry_safe这个循环,只有在这个循环中,才可以对list进行插入或者删除节点的操作。
实验感悟
- 了解了NAT的工作原理。