0218-地址解析协议

环境

  • Time 2022-11-20
  • VirtualBox 7.0.2
  • Rust 1.65.0
  • pnet 0.31.0
  • CentOS 7

前言

说明

参考:https://docs.rs/pnet_packet/latest/pnet_packet/index.html

目标

使用两台虚拟机,通过 IP 地址,获取到目标主机的 MAC 地址。
日常使用的时候,都是使用 IP 连接服务器,需要使用地址解析协议 ARP 获取 MAC 地址。
IP 地址属于三层协议的内容,所以已经从二层数据链路层进入到了三层网络层。

新增 IP 地址

增加 IP 地址的命令:ip addr add 192.168.44.88/24 dev enp0s8

主机一:

[root@centos7 ~]# hostname
centos7
[root@centos7 ~]# ip addr show enp0s8
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:16:d2:3f brd ff:ff:ff:ff:ff:ff
    inet 192.168.44.44/24 scope global enp0s8
       valid_lft forever preferred_lft forever

主机二:

[root@centos7-1 ~]# ip addr show enp0s8
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:36:b1:35 brd ff:ff:ff:ff:ff:ff
    inet 192.168.44.88/24 scope global enp0s8
       valid_lft forever preferred_lft forever
[root@centos7-1 ~]# hostname
centos7-1

可以看到主机一的 IP 是 44,主机二的 IP 是 88。

init_ethernet

fn init_ethernet(interface: &NetworkInterface) -> [u8; 42] {
    // ARP 协议 28 字节,加上数据帧(目的MAC + 源MAC + 类型)14 字节,共 42 字节
    let mut result = [0u8; 42];
    let mut ethernet = MutableEthernetPacket::new(&mut result).unwrap();
    // 地址解析协议还没有目的 MAC,只能发送广播
    ethernet.set_destination(MacAddr::broadcast());
    ethernet.set_source(interface.mac.unwrap());
    // 类型为 ARP,对应数字:0x0806
    ethernet.set_ethertype(EtherTypes::Arp);
    result
}

init_arp

fn init_arp(interface: NetworkInterface) -> [u8; 28] {
    let mut result = [0u8; 28];
    let mut arp = MutableArpPacket::new(&mut result).unwrap();
    let target_ip = "192.168.44.88".parse().unwrap();
    let source_ip = match interface.ips.get(0).unwrap().ip() {
        IpAddr::V4(ip) => ip,
        _ => unreachable!(),
    };
    // 具体参考 RFC 826
    arp.set_hardware_type(ArpHardwareTypes::Ethernet);
    arp.set_protocol_type(EtherTypes::Ipv4);
    arp.set_hw_addr_len(6);
    arp.set_proto_addr_len(4);
    arp.set_operation(ArpOperations::Request);
    arp.set_sender_hw_addr(interface.mac.unwrap());
    arp.set_sender_proto_addr(source_ip);
    arp.set_target_hw_addr(MacAddr::zero());
    arp.set_target_proto_addr(target_ip);
    result
}

main

use std::net::IpAddr;

use pnet_datalink::{channel, Channel, MacAddr, NetworkInterface};
use pnet_packet::arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPacket};
use pnet_packet::ethernet::{EtherTypes, MutableEthernetPacket};
use pnet_packet::{MutablePacket, Packet};

fn main() {
    let interface = pnet_datalink::interfaces()
        .into_iter()
        .find(|iface| iface.name == "enp0s8")
        .unwrap();

    let channel = channel(&interface, Default::default());
    let (mut sender, mut reader) = match channel {
        Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
        _ => panic!("Not a valid channel returned"),
    };

    let mut ethernet = init_ethernet(&interface);
    let mut arp = init_arp(interface);
    let mut ethernet = MutableEthernetPacket::new(&mut ethernet).unwrap();
    let mut arp = MutableArpPacket::new(&mut arp).unwrap();

    ethernet.set_payload(arp.packet_mut());
    sender.send_to(ethernet.packet(), None).unwrap().unwrap();

    println!("Sent ARP request");
    let buf = reader.next().unwrap();
    let arp = ArpPacket::new(&buf[MutableEthernetPacket::minimum_packet_size()..]).unwrap();
    println!("Target MAC address: {}", arp.get_sender_hw_addr());
}

目的 MAC

Sent ARP request
Target MAC address: 08:00:27:36:b1:35

向目的 IP 地址发送的 ARP 协议,操作系统自动回应。

ARP 缓存

[root@centos7-1 ~]# ip neigh list
192.168.1.144 dev enp0s3 lladdr 08:00:27:93:92:f2 STALE
192.168.1.3 dev enp0s3 lladdr 00:e2:69:5c:cf:b5 DELAY
192.168.44.44 dev enp0s8 lladdr 08:00:27:16:d2:3f STALE
192.168.1.1 dev enp0s3 lladdr d0:60:8c:86:7f:9c STALE
fe80::1 dev enp0s3 lladdr d0:60:8c:86:7f:9c router STALE

可以通过命令 ip neigh list 查看 ARP 缓存。

总结

通过 ARP 协议获取到了目的主机的 MAC 地址。

附录

posted @   jiangbo4444  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2020-08-12 【JavaScript】Object 构造函数和属性
点击右上角即可分享
微信分享提示