Skip to content

南京大学本科生实验报告

课程名称: 计算机网络 任课教师:田臣

学院 工程管理学院 专业(方向) 计算机金融
学号 211275022 姓名 田昊东
Email 1040880153@qq.com 开始/完成日期 2023/4/16~2023/4/16

实验名称

Lab3 Respond to ARP

实验目的

  • 本实验是ipv4路由器章节的第一部分,主要任务是实现有关arp包的接受、处理、缓存等操作的路由器程序。
  • 本实验主要分为对arp包进行存储和对arp包进行缓存两部分

实验内容

task2 Handle ARP Request

实现原理

  • 代码分为两部分

  • 第一部分是在构造函数中获取路由器个端口的ip和mac地址,建立字典存储映射关系,方便后续进行查找

    • python self.interfaces={} for item in net.interfaces(): self.interfaces[item.ipaddr]=item.ethaddr
  • 第二部分在nandle_packet中,需要先判断是不是发向路由器某个端口的arp请求包,如果是的话就根据第一部分的到的字典构造回复包并发送

    • python arp = packet.get_header(Arp) if arp is not None and arp.operation == ArpOperation.Request and arp.targetprotoaddr in self.interfaces: #构造arp回复包 res = create_ip_arp_reply(self.interfaces[arp.targetprotoaddr], arp.senderhwaddr, arp.targetprotoaddr, arp.senderprotoaddr) #发送arp回复包 self.net.send_packet(ifaceName, res) return

给定测试结果

image-20230416150549019

自定义测试

测试思路
  • 测试包共包含三种情况:
  • 发送向路由器一个端口的arp请求,应该答复
  • 发送向非路由器端口的arp请求,应该丢弃
  • 发送向路由器端口的非arp包,应该丢弃
def test_router():
    s = TestScenario("router tests")
    s.add_interface('eth0', '10:00:00:00:00:01','1.0.0.1')
    s.add_interface('eth1', '10:00:00:00:00:02','1.0.0.2')
    s.add_interface('eth2', '10:00:00:00:00:03','1.0.0.3')

    # 发送向路由器一个端口的arp请求,应该答复
    receive_pkt = create_ip_arp_request("20:00:00:00:00:01", "2.2.2.2", "1.0.0.1")
    s.expect(PacketInputEvent("eth0", receive_pkt), "An Arp package from 2.2.2.2(20:00:00:00:00:01) to 1.0.0.1(10:00:00:00:00:01) should arrive on eth0")
    send_pkt = create_ip_arp_reply("10:00:00:00:00:01","20:00:00:00:00:01","1.0.0.1","2.2.2.2")
    s.expect(PacketOutputEvent("eth0", send_pkt), "Ethernet frame destined to 20:00:00:00:00:02 should be send from eth0")
    # 发送向非路由器端口的arp请求,应该丢弃
    receive_pkt = create_ip_arp_request("20:00:00:00:00:01", "2.2.2.2", "2.0.0.1")
    s.expect(PacketInputEvent("eth0", receive_pkt), "An Arp package from 2.2.2.2(20:00:00:00:00:01) to 2.0.0.1(10:00:00:00:00:01) should arrive on eth0")
    s.expect(PacketInputTimeoutEvent(1.0), "No packet should send to eth0")
    # 发送像路由器端口的非arp包,应该丢弃
    receive_pkt = new_packet("20:00:00:00:00:01", "10:00:00:00:00:01", "2.2.2.2", "1.0.0.1")
    s.expect(PacketInputEvent("eth0", receive_pkt), "An eternet package from 2.2.2.2(20:00:00:00:00:01) to 1.0.0.1(10:00:00:00:00:01) should arrive on eth0")
    s.expect(PacketInputTimeoutEvent(1.0), "No packet should send to eth0")
    return s
测试结果

image-20230416154026963

抓包分析

  • 从server1向10.1.1.2(路由器的一个端口)进行ping操作
  • 可以看到server1先发送了arp请求包询问目标ip对应的mac地址,由于这个地址是一个路由器端口,因此路由器会进行答复,返回一个arp答复包
  • 从抓包信息可以看到:请求包中的目的mac地址为全0,进行了广播,这是因为现在只知道目的地址的ip而不知道mac,否则就不需要发送arp了
  • 从接受到的路由器返回的arp答复包中可以看到,地址不再有空缺,现在已将有了对话双方的ip和mac地址的全部信息
  • 之后发送了三个icmp包,但是都没有收到答复,这是因为当前阶段的路由器只会处理发向自己的arp包,其他包都会被直接丢弃

  • image-20230416155917003

  • image-20230416155950325

task3 Cached ARP Table

  • arp表类结构:

  • ```python class Arptable: def init(self): self.table = {} self.timeout = 100

    # 添加或更新arp缓存
    def update(self, ip, mac):
        # 先删除超时的arp缓存
        self.check()
        # 添加或更新arp缓存
        self.table[ip] = (mac, time.time())
        # 打印arp缓存
        print("arp cache: ", self.table)
    
    # 删除超时的arp缓存
    def check(self):
        for ip, (mac, t) in self.table.items():
            if time.time() - t > self.timeout:
                del self.table[ip]
    

    ```

  • 使用一个字典来维护ip和mac的对应关系

  • 目前提供两种操作:

    • update:如果ip已经在表中了,则更新mac地址,并重置时间;如果不在则直接添加进来
    • check:检查是否有表项超时,如果有则删除
  • 测试:

  • 先用server1 ping server2可以看到表项中多了server1的信息

  • 再立即用server2 ping server1可以看到表中又多了server2的信息
  • 等待一段时间后用用server1 ping client 表中只有server1的信息,这说明之前的缓存信息已经由于超时被删除
  • image-20230416164757391

实验总结

  • 这次实验总体上任务比较少,也比较简单,只实现了路由器与arp相关的部分功能
  • 期待逐步完善,最终实现一个较为完整的ipv4路由器程序