lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <3cfd28edb2c2b055e74b975623a3d38ade0237f1.1766349632.git.marcdevel@gmail.com>
Date: Sun, 21 Dec 2025 22:19:38 +0100
From: Marc Suñé <marcdevel@...il.com>
To: kuba@...nel.org,
	willemdebruijn.kernel@...il.com,
	pabeni@...hat.com
Cc: netdev@...r.kernel.org,
	dborkman@...nel.org,
	Marc Suñé <marcdevel@...il.com>
Subject: [PATCH RFC net 5/5] selftests/net: use scapy for no_bcastnull_poison

Use Scapy to generate ARP/ND packets for ARP/ND no bcast/NULL MAC
poisoning.

Signed-off-by: Marc Suñé <marcdevel@...il.com>
---
 tools/testing/selftests/net/Makefile          |   2 -
 .../net/arp_ndisc_no_bcastnull_poison.sh      |  12 +-
 tools/testing/selftests/net/arp_send.c        | 138 ------------
 tools/testing/selftests/net/arp_send.py       |  24 +++
 tools/testing/selftests/net/ndisc_send.c      | 198 ------------------
 tools/testing/selftests/net/ndisc_send.py     |  36 ++++
 6 files changed, 66 insertions(+), 344 deletions(-)
 delete mode 100644 tools/testing/selftests/net/arp_send.c
 create mode 100644 tools/testing/selftests/net/arp_send.py
 delete mode 100644 tools/testing/selftests/net/ndisc_send.c
 create mode 100644 tools/testing/selftests/net/ndisc_send.py

diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index a5bd845e1c58..6fe0b962cd05 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -164,12 +164,10 @@ TEST_GEN_FILES := \
 # end of TEST_GEN_FILES
 
 TEST_GEN_PROGS := \
-	arp_send \
 	bind_timewait \
 	bind_wildcard \
 	epoll_busy_poll \
 	ipv6_fragmentation \
-	ndisc_send \
 	proc_net_pktgen \
 	reuseaddr_conflict \
 	reuseport_bpf \
diff --git a/tools/testing/selftests/net/arp_ndisc_no_bcastnull_poison.sh b/tools/testing/selftests/net/arp_ndisc_no_bcastnull_poison.sh
index dd0bdd0e3f37..8dc79da27a2e 100755
--- a/tools/testing/selftests/net/arp_ndisc_no_bcastnull_poison.sh
+++ b/tools/testing/selftests/net/arp_ndisc_no_bcastnull_poison.sh
@@ -75,7 +75,7 @@ run_no_arp_poisoning() {
 	ip netns exec ${PEER_NS} ping -c 1 ${V4_ADDR0} >/dev/null 2>&1
 
 	# Poison with a valid MAC to ensure injection is working
-	./arp_send ${veth0_ifindex} ${BCAST_MAC} ${VALID_MAC} ${op} \
+	python3 ./arp_send.py "veth0" ${BCAST_MAC} ${VALID_MAC} ${op} \
 		${V4_ADDR0} ${VALID_MAC} ${V4_ADDR0} ${VALID_MAC}
 
 	neigh=$(ip netns exec ${PEER_NS} ip neigh show ${V4_ADDR0} | \
@@ -88,7 +88,7 @@ run_no_arp_poisoning() {
 	fi
 
 	# Poison with tmac
-	./arp_send ${veth0_ifindex} ${l2_dmac} ${VALID_MAC} ${op} \
+	python3 ./arp_send.py "veth0" ${BCAST_MAC} ${VALID_MAC} ${op} \
 		${V4_ADDR0} ${tmac} ${V4_ADDR0} ${tmac}
 
 	neigh=$(ip netns exec ${PEER_NS} ip neigh show ${V4_ADDR0} | \
@@ -119,8 +119,8 @@ run_no_ndp_poisoning() {
 	ip netns exec ${PEER_NS} ping -c 1 ${V6_ADDR0} >/dev/null 2>&1
 
 	# Poison with a valid MAC to ensure injection is working
-	./ndisc_send ${veth0_ifindex} ${l2_dmac} ${VALID_MAC} ${dst_ip} \
-		${V6_ADDR0} ${tip} ${op} ${VALID_MAC}
+	python3 ./ndisc_send.py "veth0" ${l2_dmac} ${VALID_MAC} \
+		${dst_ip} ${V6_ADDR0} ${tip} ${op} ${VALID_MAC}
 	neigh=$(ip netns exec ${PEER_NS} ip neigh show ${V6_ADDR0} | \
 		grep ${VALID_MAC})
 	if [ "${neigh}" == "" ]; then
@@ -131,8 +131,8 @@ run_no_ndp_poisoning() {
 	fi
 
 	# Poison with tmac
-	./ndisc_send ${veth0_ifindex} ${l2_dmac} ${VALID_MAC} ${dst_ip} \
-		${V6_ADDR0} ${tip} ${op} ${tmac}
+	python3 ./ndisc_send.py "veth0" ${l2_dmac} ${VALID_MAC} \
+		${dst_ip} ${V6_ADDR0} ${tip} ${op} ${tmac}
 	neigh=$(ip netns exec ${PEER_NS} ip neigh show ${V6_ADDR0} | \
 		grep ${tmac})
 	if [ "${neigh}" != "" ]; then
diff --git a/tools/testing/selftests/net/arp_send.c b/tools/testing/selftests/net/arp_send.c
deleted file mode 100644
index 463ee435c9c1..000000000000
--- a/tools/testing/selftests/net/arp_send.c
+++ /dev/null
@@ -1,138 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <inttypes.h>
-#include <netinet/ether.h>
-#include <arpa/inet.h>
-
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>
-
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
-
-struct arp_pkt {
-	struct ethhdr eth;
-	struct {
-		struct arphdr hdr;
-
-		/* Variable part for Ethernet IP ARP */
-		unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
-		__be32 ar_sip;                  /* sender IP address       */
-		unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
-		__be32 ar_tip;                  /* target IP address       */
-	} __packed arp;
-} __packed;
-
-int parse_opts(int argc, char **argv, int *ifindex, struct arp_pkt *pkt)
-{
-	int rc;
-	struct ether_addr *mac;
-	uint16_t op_code;
-
-	if (argc != 9) {
-		fprintf(stderr, "Usage: %s <iface> <mac_dst> <mac_src> <op_code> <target-ip> <target-hwaddr> <sender-ip> <sender-hwaddr>\n",
-			argv[0]);
-		return -1;
-	}
-
-	*ifindex = atoi(argv[1]);
-	mac = ether_aton(argv[2]);
-	if (!mac) {
-		fprintf(stderr, "Unable to parse mac_dst from '%s'\n", argv[2]);
-		return -1;
-	}
-
-	/* Ethernet */
-	memcpy(pkt->eth.h_dest, mac, ETH_ALEN);
-	mac = ether_aton(argv[3]);
-	if (!mac) {
-		fprintf(stderr, "Unable to parse mac_src from '%s'\n", argv[3]);
-		return -1;
-	}
-	memcpy(pkt->eth.h_source, mac, ETH_ALEN);
-	pkt->eth.h_proto = htons(ETH_P_ARP);
-
-	/* ARP */
-	op_code = atol(argv[4]);
-	if (op_code != ARPOP_REQUEST && op_code != ARPOP_REPLY) {
-		fprintf(stderr, "Invalid ARP op %s\n", argv[4]);
-		return -1;
-	}
-	pkt->arp.hdr.ar_op = htons(op_code);
-
-	pkt->arp.hdr.ar_hrd = htons(0x1); /* Ethernet */
-	pkt->arp.hdr.ar_pro = htons(ETH_P_IP);
-	pkt->arp.hdr.ar_hln = ETH_ALEN;
-	pkt->arp.hdr.ar_pln = 4;
-
-	rc = inet_pton(AF_INET, argv[5], &pkt->arp.ar_tip);
-	if (rc != 1) {
-		fprintf(stderr, "Invalid IPv4 address %s\n", argv[5]);
-		return -1;
-	}
-	rc = inet_pton(AF_INET, argv[7], &pkt->arp.ar_sip);
-	if (rc != 1) {
-		fprintf(stderr, "Invalid IPv4 address %s\n", argv[7]);
-		return -1;
-	}
-
-	mac = ether_aton(argv[6]);
-	if (!mac) {
-		fprintf(stderr, "Unable to parse target-hwaddr from '%s'\n",
-			argv[6]);
-		return -1;
-	}
-	memcpy(pkt->arp.ar_tha, mac, ETH_ALEN);
-	mac = ether_aton(argv[8]);
-	if (!mac) {
-		fprintf(stderr, "Unable to parse sender-hwaddr from '%s'\n",
-			argv[8]);
-		return -1;
-	}
-	memcpy(pkt->arp.ar_sha, mac, ETH_ALEN);
-
-	return 0;
-}
-
-int main(int argc, char **argv)
-{
-	int rc, fd;
-	struct sockaddr_ll bind_addr = {0};
-	int ifindex;
-	struct arp_pkt pkt = {0};
-
-	if (parse_opts(argc, argv, &ifindex, &pkt) < 0)
-		return -1;
-
-	fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-	if (fd < 0) {
-		fprintf(stderr, "Unable to open raw socket(%d). Need root privileges?\n",
-			fd);
-		return 1;
-	}
-
-	bind_addr.sll_family   = AF_PACKET;
-	bind_addr.sll_protocol = htons(ETH_P_ALL);
-	bind_addr.sll_ifindex  = ifindex;
-
-	rc = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
-	if (rc < 0) {
-		fprintf(stderr, "Unable to bind raw socket(%d). Invalid iface '%d'?\n",
-			rc, ifindex);
-		return 1;
-	}
-
-	rc = send(fd, &pkt, sizeof(pkt), 0);
-	if (rc < 0) {
-		fprintf(stderr, "Unable to send packet: %d\n", rc);
-		return 1;
-	}
-
-	return 0;
-}
diff --git a/tools/testing/selftests/net/arp_send.py b/tools/testing/selftests/net/arp_send.py
new file mode 100644
index 000000000000..1161dfd60b27
--- /dev/null
+++ b/tools/testing/selftests/net/arp_send.py
@@ -0,0 +1,24 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+import sys
+from scapy.all import *
+
+if len(sys.argv) != 9:
+    print(f"Usage: {sys.argv[0]} <iface> <mac_dst> <mac_src> <op_code> <target-ip> <target-hwaddr> <sender-ip> <sender-hwaddr>\n");
+
+iface = sys.argv[1]
+mac_dst = sys.argv[2]
+mac_src = sys.argv[3]
+op = int(sys.argv[4])
+tip = sys.argv[5]
+tha = sys.argv[6]
+sip = sys.argv[5]
+sha = sys.argv[6]
+
+pkt = (
+    Ether(dst=mac_dst, src=mac_src) /
+    ARP(op=op, psrc=sip, hwsrc=sha, pdst=tip, hwdst=tha)
+)
+
+sendp(pkt, iface=iface, verbose=False)
diff --git a/tools/testing/selftests/net/ndisc_send.c b/tools/testing/selftests/net/ndisc_send.c
deleted file mode 100644
index 4f226221d079..000000000000
--- a/tools/testing/selftests/net/ndisc_send.c
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <inttypes.h>
-#include <netinet/ether.h>
-#include <arpa/inet.h>
-
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>
-#include <linux/ipv6.h>
-#include <linux/icmpv6.h>
-
-#define ICMPV6_ND_NS 135
-#define ICMPV6_ND_NA 136
-#define ICMPV6_ND_SLLADR 1
-#define ICMPV6_ND_TLLADR 2
-
-#ifndef __noinline
-#define __noinline __attribute__((noinline))
-#endif
-#ifndef __packed
-#define __packed __attribute__((packed))
-#endif
-
-struct icmp6_pseudohdr {
-	struct in6_addr saddr;
-	struct in6_addr daddr;
-	uint32_t plen;
-	uint8_t zero[3];
-	uint8_t next;
-};
-
-struct ndisc_pkt {
-	struct ethhdr eth;
-	struct ipv6hdr ip6;
-	struct ndp_hdrs {
-		struct icmp6hdr hdr;
-		struct in6_addr target;
-
-		uint8_t opt_type;
-		uint8_t opt_len;
-		uint8_t opt_mac[ETH_ALEN];
-	} __packed ndp;
-} __packed;
-
-__noinline uint32_t csum_add(void *buf, int len, uint32_t sum)
-{
-	uint16_t *p = (uint16_t *)buf;
-
-	while (len > 1) {
-		sum += *p++;
-		len -= 2;
-	}
-
-	if (len)
-		sum += *(uint8_t *)p;
-
-	return sum;
-}
-
-static uint16_t csum_fold(uint32_t sum)
-{
-	return ~((sum & 0xffff) + (sum >> 16)) ? : 0xffff;
-}
-
-int parse_opts(int argc, char **argv, int *ifindex, struct ndisc_pkt *pkt)
-{
-	struct ether_addr *mac;
-	uint16_t op;
-	struct icmp6_pseudohdr ph = {0};
-	uint32_t sum = 0;
-
-	if (argc != 9) {
-		fprintf(stderr, "Usage: %s <iface> <mac_dst> <mac_src> <dst_ip> <src_ip> <target_ip> <op> <lladr>\n",
-			argv[0]);
-		return -1;
-	}
-
-	*ifindex = atoi(argv[1]);
-	mac = ether_aton(argv[2]);
-	if (!mac) {
-		fprintf(stderr, "Unable to parse mac_dst from '%s'\n", argv[1]);
-		return -1;
-	}
-
-	/* Ethernet */
-	memcpy(pkt->eth.h_dest, mac, ETH_ALEN);
-	mac = ether_aton(argv[3]);
-	if (!mac) {
-		fprintf(stderr, "Unable to parse mac_src from '%s'\n", argv[2]);
-		return -1;
-	}
-	memcpy(pkt->eth.h_source, mac, ETH_ALEN);
-	pkt->eth.h_proto = htons(ETH_P_IPV6);
-
-	/* IPv6 */
-	pkt->ip6.version = 6;
-	pkt->ip6.nexthdr = IPPROTO_ICMPV6;
-	pkt->ip6.hop_limit = 255;
-
-	if (inet_pton(AF_INET6, argv[4], &pkt->ip6.daddr) != 1) {
-		fprintf(stderr, "Unable to parse src_ip from '%s'\n", argv[4]);
-		return -1;
-	}
-	if (inet_pton(AF_INET6, argv[5], &pkt->ip6.saddr) != 1) {
-		fprintf(stderr, "Unable to parse src_ip from '%s'\n", argv[5]);
-		return -1;
-	}
-
-	/* ICMPv6 */
-	op = atoi(argv[7]);
-	if (op != ICMPV6_ND_NS && op != ICMPV6_ND_NA) {
-		fprintf(stderr, "Invalid ICMPv6 op %d\n", op);
-		return -1;
-	}
-
-	pkt->ndp.hdr.icmp6_type = op;
-	pkt->ndp.hdr.icmp6_code = 0;
-
-	if (inet_pton(AF_INET6, argv[6], &pkt->ndp.target) != 1) {
-		fprintf(stderr, "Unable to parse target_ip from '%s'\n",
-			argv[6]);
-		return -1;
-	}
-
-	/* Target/Source Link-Layer Address */
-	if (op == ICMPV6_ND_NS) {
-		pkt->ndp.opt_type = ICMPV6_ND_SLLADR;
-	} else {
-		pkt->ndp.opt_type = ICMPV6_ND_TLLADR;
-		pkt->ndp.hdr.icmp6_override = 1;
-	}
-	pkt->ndp.opt_len = 1;
-
-	mac = ether_aton(argv[8]);
-	if (!mac) {
-		fprintf(stderr, "Invalid lladdr %s\n", argv[8]);
-		return -1;
-	}
-
-	memcpy(pkt->ndp.opt_mac, mac, ETH_ALEN);
-
-	pkt->ip6.payload_len = htons(sizeof(pkt->ndp));
-
-	/* Pseudoheader */
-	ph.saddr = pkt->ip6.saddr;
-	ph.daddr = pkt->ip6.daddr;
-	ph.plen = htonl(sizeof(pkt->ndp));
-	ph.next = IPPROTO_ICMPV6;
-
-	sum = csum_add(&ph, sizeof(ph), 0);
-	sum = csum_add(&pkt->ndp, sizeof(pkt->ndp), sum);
-
-	pkt->ndp.hdr.icmp6_cksum = csum_fold(sum);
-
-	return 0;
-}
-
-int main(int argc, char **argv)
-{
-	int rc, fd;
-	struct sockaddr_ll bind_addr = {0};
-	int ifindex;
-	struct ndisc_pkt pkt = {0};
-
-	if (parse_opts(argc, argv, &ifindex, &pkt) < 0)
-		return -1;
-
-	fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-	if (fd < 0) {
-		fprintf(stderr, "Unable to open raw socket(%d). Need root privileges?\n",
-			fd);
-		return 1;
-	}
-
-	bind_addr.sll_family   = AF_PACKET;
-	bind_addr.sll_protocol = htons(ETH_P_ALL);
-	bind_addr.sll_ifindex  = ifindex;
-
-	rc = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
-	if (rc < 0) {
-		fprintf(stderr, "Unable to bind raw socket(%d). Invalid iface '%d'?\n",
-			rc, ifindex);
-		return 1;
-	}
-
-	rc = send(fd, &pkt, sizeof(pkt), 0);
-	if (rc < 0) {
-		fprintf(stderr, "Unable to send packet: %d\n", rc);
-		return 1;
-	}
-
-	return 0;
-}
diff --git a/tools/testing/selftests/net/ndisc_send.py b/tools/testing/selftests/net/ndisc_send.py
new file mode 100644
index 000000000000..7b1a1c057862
--- /dev/null
+++ b/tools/testing/selftests/net/ndisc_send.py
@@ -0,0 +1,36 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+import sys
+from scapy.all import *
+
+if len(sys.argv) != 9:
+    print(f"Usage: {sys.argv[0]} <iface> <mac_dst> <mac_src> <ip_dst> <ip_src> <target_ip> <op> <lladr>")
+
+iface = sys.argv[1]
+mac_dst = sys.argv[2]
+mac_src = sys.argv[3]
+ip_dst = sys.argv[4]
+ip_src = sys.argv[5]
+tip = sys.argv[6]
+op = int(sys.argv[7])
+lladdr = sys.argv[8]
+
+NDP_NA=136
+
+if op == NDP_NA:
+    pkt = (
+        Ether(dst=mac_dst, src=mac_src) /
+        IPv6(src=ip_src, dst=ip_dst, hlim=255) /
+        ICMPv6ND_NA(R=0, S=0, O=1, tgt=tip) /
+        ICMPv6NDOptDstLLAddr(lladdr=lladdr)
+    )
+else:
+    pkt = (
+        Ether(dst=mac_dst, src=mac_src) /
+        IPv6(src=ip_src, dst=ip_dst, hlim=255) /
+        ICMPv6ND_NS(tgt=tip) /
+        ICMPv6NDOptSrcLLAddr(lladdr=lladdr)
+    )
+
+sendp(pkt, iface=iface, verbose=False)
-- 
2.47.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ