惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
月光博客
月光博客
AI
AI
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CXSECURITY Database RSS Feed - CXSecurity.com
WordPress大学
WordPress大学
GbyAI
GbyAI
L
Lohrmann on Cybersecurity
O
OpenAI News
Schneier on Security
Schneier on Security
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Troy Hunt's Blog
V2EX - 技术
V2EX - 技术
W
WeLiveSecurity
L
LINUX DO - 最新话题
人人都是产品经理
人人都是产品经理
S
Security Affairs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
Arctic Wolf
Recorded Future
Recorded Future
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
GRAHAM CLULEY
N
Netflix TechBlog - Medium
TaoSecurity Blog
TaoSecurity Blog
C
Check Point Blog
Scott Helme
Scott Helme
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
PCI Perspectives
PCI Perspectives
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Vercel News
Vercel News
The Hacker News
The Hacker News
Y
Y Combinator Blog
Latest news
Latest news
SecWiki News
SecWiki News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
Cisco Blogs
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题

C0reFast记事本

一个virtio-blk设备IO大小的问题 使用单台高配服务器(部署你的业务) 一个Solidigm P41 Plus的冷数据问题 硬件Bonding卸载场景下的ARP/ND双发 “无限”套娃,在WSL的Docker中使用YOLOv11做目标检测 在三条指令内实现闰年判断 一个中断关闭时间太长导致的网络延迟问题 一个Linux新老内核对于硬件中断的统计差异 IPIP隧道导致的DPDK收包RSS队列不均匀问题 在KVM虚拟机中开启TSC作为时钟源 x86平台的TSC(TIME-STAMP COUNTER) 一个UFO引发的惨案 在RHEL系统中快速抓取火焰图 反序列化AWS/阿里云样式的基于Query的API请求 DIY一个8盘位全闪NAS 分享一个记录LSI RAID卡芯片和各个OEM对应卡型号列表的神贴 在移动硬盘盒上启用SSD的Trim功能 SPDK的“Reduce”块压缩算法 实现一个Kubernetes的身份认证代理服务
测试ARP/ND双发效果的小工具
陈孚 · 2025-08-14 · via C0reFast记事本

上一篇Blog里说了一下关于ARP/ND双发的实现,但是还遗留了一个小问题,就是如何测试最终的效果,毕竟正常情况下,ARP还有ND相关的报文,都是由内核协议栈根据需要发出的,不太稳定,总不能一直抓包等着内核发包吧?所以还是需要借助一些工具来实现。

ARP双发的测试还是比较简单的,毕竟大家都知道arping这个工具,可以用来发送ARP请求并接收ARP应答。使用起来也是非常顺畅的:

# arping 192.68.100.1 -c 2
ARPING 192.68.100.1 from 192.68.100.21 eth0
Unicast reply from 192.68.100.1 [00:11:22:33:44:01]  1.315ms
Unicast reply from 192.68.100.1 [00:11:22:33:44:01]  1.355ms
Unicast reply from 192.68.100.1 [00:11:22:33:44:01]  1.112ms
Unicast reply from 192.68.100.1 [00:11:22:33:44:01]  1.233ms
Sent 2 probes (1 broadcast(s))
Received 4 response(s)

可以发现,arping工具发送了2个ARP请求,成功地收到了4次ARP应答,这表明ARP双发功能正常。两次请求中,第一次是广播请求,可以模拟第一次学习MAC地址时的场景,第二次是单播请求,可以模拟已有MAC后的确认场景,尝试抓包,也是可以看到结果是符合预期的:

# sudo tcpdump -i eth0 arp -nnn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

20:16:03.982709 ARP, Request who-has 192.68.100.1 (ff:ff:ff:ff:ff:ff) tell 192.68.100.21, length 28
20:16:03.983231 ARP, Reply 192.68.100.1 is-at 00:11:22:33:44:01, length 46
20:16:03.983298 ARP, Reply 192.68.100.1 is-at 00:11:22:33:44:01, length 46
20:16:04.982738 ARP, Request who-has 192.68.100.1 (00:11:22:33:44:01) tell 192.68.100.21, length 28
20:16:04.983343 ARP, Reply 192.68.100.1 is-at 00:11:22:33:44:01, length 46
20:16:04.983412 ARP, Reply 192.68.100.1 is-at 00:11:22:33:44:01, length 46

6 packets captured
6 packets received by filter
0 packets dropped by kernel

ND双发检测

接下来轮到IPv6的ND报文了,这里介绍一个工具包NDisc6,可以部分替代arping的功能,为什么是部分替代呢?因为和arping不同,ndisc6不支持发送单播NS报文,只支持发送组播报文,这样就只能模拟第一次学习的情况,没办法模拟后续了,我们先用这个工具模拟一下组播的场景:

# sudo ndisc6 2408:fffe::1 eth0 -m
Soliciting 2408:fffe::1 (2408:fffe::1) on eth0...
Target link-layer address: 00:10:00:54:00:24
 from 2408:fffe::1
Target link-layer address: 00:10:00:54:00:24
 from 2408:fffe::1

可以看到发送一个NS,收到两个NA,说明ND双发功能也是正常的。尝试抓包,也是可以看到结果是符合预期的:

# sudo tcpdump -i eth0 icmp6 -nnn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

20:18:18.959590 IP6 fe80::f816:3eff:fefa:556f > ff02::1:ff00:1: ICMP6, neighbor solicitation, who has 2408:fffe::1, length 32
20:18:18.961594 IP6 2408:fffe::1 > fe80::f816:3eff:fefa:556f: ICMP6, neighbor advertisement, tgt is 2408:fffe::1, length 32
20:18:18.962687 IP6 2408:fffe::1 > fe80::f816:3eff:fefa:556f: ICMP6, neighbor advertisement, tgt is 2408:fffe::1, length 32

3 packets captured
3 packets received by filter
0 packets dropped by kernel

那单播NS报文怎么办呢?因为没找到合适的工具,因此还是借助AI自己实现了一个脚本来完成这个任务:

#!/usr/bin/env python3
"""
IPv6邻居发现工具 - 类似arping的NS/NA实现
使用Scapy发送和接收ICMPv6邻居发现报文
"""

import argparse
import time
from scapy.all import Ether, IPv6, ICMPv6ND_NS, ICMPv6ND_NA, srp, get_if_list

def send_ns(target_ip, iface=None, timeout=1, retry=1, verbose=False, dst_mac=None):
    """
    发送一个NS报文并等待所有NA响应
    :param target_ip: 目标IPv6地址
    :param iface: 网络接口名称
    :param timeout: 超时时间(秒)
    :param retry: 重试次数(仅在没有收到任何响应时重试)
    :param verbose: 详细输出模式
    :param dst_mac: 目标MAC地址(单播模式)
    :return: 响应列表 [(src_ip, src_mac), ...] 或 []
    """
    if iface and iface not in get_if_list():
        print(f"警告: 接口 {iface} 不存在")
        return []

    dst_mac = dst_mac if dst_mac else "33:33:ff:00:00:00"
    ns_pkt = Ether(dst=dst_mac) / \
             IPv6(dst=target_ip) / \
             ICMPv6ND_NS(tgt=target_ip)
    
    if verbose:
        print("发送NS报文:")
        ns_pkt.show()

    all_responses = []
    
    for attempt in range(retry):
        if verbose:
            print(f"尝试 {attempt+1}/{retry}...")
        
        # 发送一个NS报文并收集所有响应,在超时时间内持续监听
        answered, unanswered = srp(ns_pkt, iface=iface, timeout=timeout, verbose=0, multi=True)
        
        # 处理所有收到的响应
        for sent, received in answered:
            if received.haslayer(ICMPv6ND_NA):
                src_ip = received[IPv6].src
                src_mac = received[Ether].src
                response_info = (src_ip, src_mac)
                all_responses.append(response_info)
                if verbose:
                    print(f"收到NA响应 #{len(all_responses)}:")
                    received.show()
        
        # 如果收到了响应,就不再重试
        if all_responses:
            if verbose:
                print(f"收到 {len(all_responses)} 个NA响应,停止重试")
            break
        elif verbose:
            print("本轮未收到响应")
    
    return all_responses

def main():
    parser = argparse.ArgumentParser(description="IPv6邻居发现工具")
    parser.add_argument("target", help="目标IPv6地址")
    parser.add_argument("-i", "--iface", help="网络接口名称")
    parser.add_argument("-t", "--timeout", type=int, default=1,
                       help="超时时间(秒)")
    parser.add_argument("-c", "--count", type=int, default=1,
                       help="重试次数(默认1次,仅在无响应时重试)")
    parser.add_argument("-v", "--verbose", action="store_true",
                       help="详细输出模式")
    parser.add_argument("-m", "--mac",
                       help="指定目标MAC地址(单播模式)")
    args = parser.parse_args()

    if args.verbose:
        print("可用网络接口:", ", ".join(get_if_list()))

    results = send_ns(args.target, args.iface, args.timeout,
                     args.count, args.verbose, args.mac)
    if results:
        print(f"\n收到 {len(results)} 个NA响应:")
        for i, (ip, mac) in enumerate(results, 1):
            print(f"  {i}. {args.target} 的MAC地址是 {mac} (来自 {ip})")
    else:
        print(f"\n无法获取 {args.target} 的MAC地址")

if __name__ == "__main__":
    main()

借助这个脚本,就可以实现发送单播NS,并收集所有的ND返回:

# sudo python3 ip6ndisc.py 2408:fffe::1 -m 00:10:00:54:00:24

收到 2 个NA响应:
  1. 2408:fffe::1 的MAC地址是 00:10:00:54:00:24 (来自 2408:fffe::1)
  2. 2408:fffe::1 的MAC地址是 00:10:00:54:00:24 (来自 2408:fffe::1)

抓包也符合预期:

# sudo tcpdump -i eth0 icmp6 -nnn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:27:25.782766 IP6 2408:fffe::21:1 > 2408:fffe::1: ICMP6, neighbor solicitation, who has 2408:fffe::1, length 24
14:27:25.784537 IP6 2408:fffe::1 > 2408:fffe::21:1: ICMP6, neighbor advertisement, tgt is 2408:fffe::1, length 32
14:27:25.784739 IP6 2408:fffe::1 > 2408:fffe::21:1: ICMP6, neighbor advertisement, tgt is 2408:fffe::1, length 32

3 packets captured
3 packets received by filter
0 packets dropped by kernel