首页 > 其他分享 >CS144-Lab5-ARP

CS144-Lab5-ARP

时间:2023-01-25 10:33:06浏览次数:56  
标签:ARP arp ip CS144 header Lab5 address frame

lab 地址 :lab5-doc
代码实现:lab5-code
完整目录:
0. ByteStream
1. StreamReassembler
2. TCPReceiver
3. TCPSender
4. TCPConnection
5. ARP
6. IP-Router

1. 目标

lab0 ~ lab4 已经实现了一个基本的 TCPConnection,支持可靠的字节流,在 lab4 中官方已经实现了网络层协议数据的封装 IPV4Datagram
因此接下来我们主要需要关注的就是从 网络层 -> 数据链路层 中:

  • 发包时,IP 数据报 到 EthernetFrame 的转换
  • 收到 EthernetFrame 的处理

image

image

在处理收发 Ethernet frames 时主要涉及到 ARP 协议,什么是 ARP 协议?

地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。

我们发送 以太网帧 时,当不知道目标地址的 ip 地址时,需要通过局域网广播 arp 协议去发现目标主机的地址,并且进行一段时间的缓存方便后续查询。
对比上个 lab,新增了 network_interface 类,需要实现的核心接口如下:

// 发送数据报,转成以太网帧
void NetworkInterface::send_datagram(const InternetDatagram &dgram, const Address &next_hop)

// 接收以太网帧
optional<InternetDatagram> NetworkInterface::recv_frame(const EthernetFrame &frame)       

void tick(const size_t ms_since_last_tick);

[!note]
这里需要注意的是 ARP 协议也是网络层协议,发送 ARP 协议时也是封装在 EthernetFramepayload 中的。

2. 实现

接下来规整下我们的实现,其实主要根据 lab 中的描述实现对应接口即可。

2.1 send_datagram

接口的参数主要有 2 个 ,const InternetDatagram &dgramAddress& next_hop ,dgram 是要发送的数据包,而 next_hop 是目标地址,处理点主要如下:

  1. 地址缓存机制,主要用于检查目标地址 next_hop 是否已经缓存(新增一个地址缓存映射)
    • 已缓存,将数据包转换成 EthernetFrame ,push 到 frames_out 队列中
    • 未缓存,广播局域网 ARP 消息(其实就是 push 一个 EthernetFrame ,但是 payload 是 ARPMessage 结构序列化的 buffer)
  2. 由于 1 引出 2,缓存的有效时间为 30s,如果 30s 内与目标主机无任何通信,则缓存失效,反之更新缓存保存时长
  3. 对相同地址发送 ARP 广播查询,需要间隔 5s
  4. 当前准备发出的请求,如果由于未知地址没有发出,需要先缓存到队列中(新增一个请求队列)
  5. 由于 4 引出 5,这里有可能一直没有查询到目标地址(超时,地址不可达),但是 lab 中不需要考虑(课程 test case 跳过这种情况)。当查询到地址时,会收到一个 ARP Reply (recv_frames 接口中处理),重新检查请求队列
    代码如下:
//! \param[in] dgram the IPv4 datagram to be sent
//! \param[in] next_hop the IP address of the interface to send it to (typically a router or default gateway, but may also be another host if directly connected to the same network as the destination)
//! (Note: the Address type can be converted to a uint32_t (raw 32-bit IP address) with the Address::ipv4_numeric() method.)
void NetworkInterface::send_datagram(const InternetDatagram &dgram, const Address &next_hop) {
	// convert IP address of next hop to raw 32-bit representation (used in ARP header)
	const uint32_t next_hop_ip = next_hop.ipv4_numeric();
	// find and send ip datagram
	EthernetFrame frame;
	auto& address = _learn_address[next_hop_ip];
	if (address.is_valid) {
		_send_datagram(dgram, address.learn_address);
	}
	// send arp message request
	else {
		/*
		don’t want to flood the network with ARP requests. If the network interface already sent
		an ARP request about the same IP address in the last five seconds, don’t send a second
		request—just wait for a reply to the first one. Again, queue the datagram until you
		learn the destination Ethernet address.
		*/
		if (!address.can_query()) {
			address.datagrams.push(dgram);
			return;
		}
		// can not query again in 5s, reset query pass time
		address.query_pass_time -= LearnAddress::QUERY_VAILD_TIMEOUT;
		// setup header
		EthernetHeader& header = frame.header();
		header.dst = ETHERNET_BROADCAST;
		header.src = _ethernet_address;
		header.type = EthernetHeader::TYPE_ARP;
		
		// setup arp payload
		ARPMessage arp;
		arp.opcode = ARPMessage::OPCODE_REQUEST;
		arp.sender_ethernet_address = _ethernet_address;
		arp.sender_ip_address = _ip_address.ipv4_numeric();
		arp.target_ip_address = next_hop_ip;
		frame.payload() = arp.serialize();
		// cache datagram
		address.datagrams.push(dgram);
		_frames_out.push(frame);
	}
}

2.2 recv_frame

recv_frame 的接口参数只有一个 EthernetFrame& frame ,以太网帧,recv_frame 要做的事情比较简单:

  1. 如果 frame 是 ipv4 数据包,解析成 InternetDatagram 类型
    • 如果数据包的目标 ip 不是自己的,返回 {},反之返回解析成功的数据包
  2. 如果 frame 是 arp 数据包
    • 解析成 ARPMessage ,并且保存发送端的 ip 地址和 mac 地址映射(如果已经保存则重置过期时间)
    • 如果 ARP 请求的是自身的 ip,发送一个 ARP Reply
    • 检查可以发送的 请求队列
//! \param[in] frame the incoming Ethernet frame
optional<InternetDatagram> NetworkInterface::recv_frame(const EthernetFrame &frame) {
	uint32_t local_ip = _ip_address.ipv4_numeric();
	if (frame.header().type == EthernetHeader::TYPE_IPv4) {
		InternetDatagram datagram;
		ParseResult result = datagram.parse(frame.payload());
		if (result != ParseResult::NoError || frame.header().dst != _ethernet_address) {
			return {};
		}
		return datagram;
	}
	
	if (frame.header().type == EthernetHeader::TYPE_ARP) {
		ARPMessage arp;
		ParseResult result = arp.parse(frame.payload());
		if (result != ParseResult::NoError) {
			return {};
		}
		/*
		If the inbound frame is ARP, parse the payload as an ARPMessage and, if successful,
		remember the mapping between the sender’s IP address and Ethernet address for 30 seconds.
		*/
		auto& address = _learn_address[arp.sender_ip_address];
		address.is_valid = true;
		address.learn_address = arp.sender_ethernet_address;
		address.learn_pass_time = 0;
		address.query_pass_time = LearnAddress::QUERY_VAILD_TIMEOUT;
	
		// received arp request, reply host ip and mac
		if (arp.opcode == ARPMessage::OPCODE_REQUEST && arp.target_ip_address == local_ip) {
			// setup header
			EthernetFrame reply_frame;
			EthernetHeader& header = reply_frame.header();
			header.dst = frame.header().src;
			header.src = _ethernet_address;
			header.type = EthernetHeader::TYPE_ARP;
			// setup arp payload
			ARPMessage reply_arp;
			reply_arp.opcode = ARPMessage::OPCODE_REPLY;
			reply_arp.sender_ethernet_address = _ethernet_address;
			reply_arp.sender_ip_address = _ip_address.ipv4_numeric();
			reply_arp.target_ip_address = arp.sender_ip_address;
			reply_arp.target_ethernet_address = arp.sender_ethernet_address;
			reply_frame.payload() = reply_arp.serialize();
			// send it
			_frames_out.push(reply_frame);
		}
		// received arp reply
		if (arp.opcode == ARPMessage::OPCODE_REPLY) {
			// re-sent datagrams
			while (!address.datagrams.empty()) {
				InternetDatagram& dgram = address.datagrams.front();
				_send_datagram(dgram, address.learn_address);
				address.datagrams.pop();
			}
		}
	}
	return {};
}

2.3 tick

tick 函数要处理时间相关的逻辑,根据前面引出的要处理的点,主要就是更新地址缓存保留时间,

//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method
void NetworkInterface::tick(const size_t ms_since_last_tick) {
	for (auto& address : _learn_address) {
		LearnAddress& learn_address = address.second;
		learn_address.tick(ms_since_last_tick);
		if (learn_address.learn_timeout()) {
			learn_address.reset();
		}
	}
}

3 测试

image

标签:ARP,arp,ip,CS144,header,Lab5,address,frame
From: https://www.cnblogs.com/lawliet12/p/17066721.html

相关文章

  • CSharp: emojione
     ///<summary>///mysql数据库用编码类型utf8mb4///向sqlserver数据库插入emoji表情包///插入emoji的数据时,值value需要......
  • CSharp: SOAP,WSDL
     引用服务有修改,点右键更新 Web.config<?xmlversion="1.0"encoding="utf-8"?><configuration><configSections><sectionname="microsoft.web.services3......
  • CSharp: Lazy Load Pattern in donet core 6
     usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceGeovin.Du.DuLazyLoad.DuGhost......
  • CS144-Lab1-StreamReassembler
    lab地址:lab1-doc代码实现:lab1-code1.目标TCP一个很重要的特性是可以实现顺序、无差错、不重复和无报文丢失的流传输。在lab0中我们已经实现了一个字节流ByteSt......
  • CS144-Lab0-networking warmup
    lab地址:lab0-doc代码实现:lab0-code1.目标利用官方支持的TCPSocket,实现一个wget功能,其次,实现一个可靠的字节流。2.实现2.1webget实现上比较简单,主要就是:......
  • CS144-lab6-the IP router
    lab地址:lab6-doc代码实现:lab6-code1.目标lab6主要要实现一个路由的机制,首先互联网由多个局域网组成(不太严谨的说法),在lab5中我们只能支持在单个局域网中传递消......
  • Apache IoTDB C# SDK Apache-IoTDB-Client-CSharp
    最近今天写了IoTDB的三篇相关文章,完成了安装部署和客户端连接:WindowsServer上部署IoTDB集群DBeaver连接IoTDBDriver将IoTDB注册为Windows服务TsFile是IoTDB的底层数......
  • ARP协议
    ......
  • 将错就错:借助 YARP 转发 DNS 错乱解析造成的错误请求
    最近园子在部署IPv6时遇到了一个非常奇怪的dns解析问题,当给非www二级域名(比如q.cnblogs.com)添加AAAA(IPv6)记录后,部分用户访问q.cnblogs.com时会被错误地解析为......
  • 普林斯顿大学算法Week3:CollinearPoints共线模式识别(99分)--总结及代码
    总结(代码有详细注释)本课讲了归并排序,作业应用是排序进行共线的模式识别,java1.8中的排序用的是tim排序,结合了归并排序与插入排序,属于稳定排序:排序之后相同元素的相对......