Reason for layer locking: More accurate result.
Operating systems are generic, Scapy frames are specific, so Scapy frames give troubleshooting accuracy.
Environment: VyOS router in Oracle VM VirtualBox.
LAYER 2 - Data Link Test
Steps:
- Put listener on eth0 on VyOS
- Run Scapy frame
Scapy frame to send (L2 broadcast - locks to L2):
Layer 2 Lock Test - Pure L2 - VyOS eth0
from scapy.all import *
p = Ether(dst="ff:ff:ff:ff:ff:ff")
hexdump(p)
0000 FF FF FF FF FF FF 00 00 00 00 00 00 90 00
Breakdown:
FF FF FF FF FF FF = dst - broadcast all MACs
00 00 00 00 00 00 = src - zero - Scapy default when no MAC bound
90 00 = type - Loopback - blank L2 frame
srp(p, iface="eth0", timeout=3)
Begin emission:
Finished sending 1 packets.
Received 0 packets, got 0 answers, remaining 1 packets
Result: L2 TX works - frame was put on wire, layer-locked, no IP.
LAYER 3 - Network Layer Test
L3 Test - Hardcoded MAC + Static IP - VyOS eth0
Goal: Exclude DHCP and ARP to prove L3 TX.
STEP 1 - Find MAC (Linux command)
$ cat /sys/class/net/eth0/address
08:00:27:bf:9a:64
STEP 2 - Put static IP (VyOS config)
configure
set interfaces ethernet eth0 address 192.168.56.10/24
commit
save
exit
STEP 3 - Put listener in background (same terminal)
$ sudo tcpdump -i eth0 -e -n icmp &
[1] 3047
tcpdump: listening on eth0, link-type EN10MB
STEP 4 - Scapy - hardcode MAC and IP to kill ARP
$ sudo python3
from scapy.all import *
my_mac = "08:00:27:bf:9a:64"
my_ip = "192.168.56.10"
p = Ether(dst=my_mac, src=my_mac) / IP(dst=my_ip, src=my_ip) / ICMP()
hexdump(p)
0000 08 00 27 BF 9A 64 08 00 27 BF 9A 64 08 00 45 00..'.d..'.d..E.
0010 00 1C 00 01 00 00 40 01 89 7B C0 A8 38 0A C0 A8......@..{..8...
0020 38 0A 08 00 F7 FF 00 00 00 00 8.........
Breakdown:
08 00 27 BF 9A 64 = dst MAC = your eth0 (hardcoded)
08 00 27 BF 9A 64 = src MAC = your eth0 (hardcoded)
08 00 = Type = IPv4
45 00 = IP version / header
C0 A8 38 0A = hex for 192.168.56.10 src
C0 A8 38 0A = hex for 192.168.56.10 dst
08 00 = ICMP Echo Request
srp(p, iface="eth0", timeout=3)
Begin emission:
Finished sending 1 packets.
13:38:43.976853 08:00:27:bf:9a:64 > 08:00:27:bf:9a:64, ethertype IPv4 (0x0800), length 42: 192.168.56.10 > 192.168.56.10: ICMP echo request
.
Received 0 packets, got 0 answers, remaining 1 packets
RESULT:
L3 TX UP - Confirmed.
tcpdump saw the frame on eth0 (line above), proving Layer 2 and Layer 3 headers were built correctly and transmitted with no DHCP/ARP.
Received 0 is EXPECTED here because we pinged ourselves (src=dst). Linux routes self-pings via lo, not eth0, so no Echo Reply is generated on eth0. This is not L3 down.
For full L3 up with reply, ping gateway 192.168.56.1 with its MAC, and srp will show "got 1 answers".
LAYER 4 - Transport Layer Test
L4 Test - UDP Port 50001
Why put a listener on port 50001?
We use 50001 because it is in the clean dynamic range 49152-65535. Nothing else on VyOS uses it, so there is no L5-L7 app interfering. If something arrives there, we know it is pure L4 Transport being tested. We also need a listener (nc -l -u -p 50001) otherwise the OS would drop the UDP and we would see nothing.
The listener was run in one terminal as:
sudo nc -l -u -p 50001 > /tmp/udp.txt &
The frame we sent:
L4 must be carried inside L3, so we still need an IP. We used loopback because we are sending from VyOS to itself:
from scapy.all import *
udp_clean = IP(dst="127.0.0.1")/UDP(dport=50001)/Raw(load="L4-TEST")
send(udp_clean)
Breakdown:
- IP(dst="127.0.0.1") = L3 part - VyOS lo loopback
- /UDP(dport=50001) = L4 part - clean port
- /Raw(load="L4-TEST") = payload to prove delivery
Sent with:
sudo python3 -c "from scapy.all import *; send(IP(dst='127.0.0.1')/UDP(dport=50001)/Raw(load='L4-TEST'), verbose=1)"
The result:
cat /tmp/udp.txt
L4-TEST
And tcpdump -i lo -n port 50001 showed the packet on lo.
Conclusion: Payload L4-TEST was delivered to clean port 50001. No other service uses this port. This proves L4 UDP is UP.
Top comments (0)