@@ -21,6 +21,13 @@ if (!function_exists("posix_getuid") || posix_getuid() != 0) {
2121$ dst_mac = "\xff\xff\xff\xff\xff\xff" ;
2222$ src_mac = "\x00\x00\x00\x00\x00\x00" ;
2323
24+ // Drain any pending packets from a socket.
25+ function drain_socket (Socket $ s ): void {
26+ socket_set_nonblock ($ s );
27+ while (@socket_recvfrom ($ s , $ buf , 65536 , 0 , $ addr ) !== false ) {}
28+ socket_set_block ($ s );
29+ }
30+
2431echo "--- Undersized frame (below 14-byte ethernet header) --- \n" ;
2532$ s_send = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
2633socket_bind ($ s_send , 'lo ' );
@@ -35,6 +42,7 @@ $s_send = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
3542$ s_recv = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
3643socket_bind ($ s_send , 'lo ' );
3744socket_bind ($ s_recv , 'lo ' );
45+ drain_socket ($ s_recv );
3846
3947// Ethernet header with no payload, padded to minimum 60 bytes.
4048$ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , 0x9000 ), 60 , "\x00" );
@@ -54,6 +62,7 @@ $s_send = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
5462$ s_recv = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
5563socket_bind ($ s_send , 'lo ' );
5664socket_bind ($ s_recv , 'lo ' );
65+ drain_socket ($ s_recv );
5766
5867// Use a made-up ethertype (0xBEEF). Kernel delivers it fine on loopback.
5968$ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , 0xBEEF ) . "bogus " , 60 , "\x00" );
@@ -69,14 +78,16 @@ var_dump(str_contains($buf, "bogus"));
6978socket_close ($ s_send );
7079socket_close ($ s_recv );
7180
72- echo "--- Truncated IP header (valid ether header, garbage IP) --- \n" ;
81+ echo "--- Garbage payload with custom ethertype --- \n" ;
7382$ s_send = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
7483$ s_recv = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
7584socket_bind ($ s_send , 'lo ' );
7685socket_bind ($ s_recv , 'lo ' );
86+ drain_socket ($ s_recv );
7787
78- // ETH_P_IP ethertype but only 4 bytes of garbage instead of a real IP header.
79- $ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , ETH_P_IP ) . "\xDE\xAD\xBE\xEF" , 60 , "\x00" );
88+ // Use a non-standard ethertype (0x88B5, reserved for local experimental use)
89+ // with garbage payload. Avoids kernel IP/IPv6 stack interception.
90+ $ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , 0x88B5 ) . "\xDE\xAD\xBE\xEF" , 60 , "\x00" );
8091$ sent = socket_sendto ($ s_send , $ frame , strlen ($ frame ), 0 , "lo " , 1 );
8192var_dump ($ sent === 60 );
8293
@@ -88,14 +99,15 @@ var_dump(str_contains($buf, "\xDE\xAD\xBE\xEF"));
8899socket_close ($ s_send );
89100socket_close ($ s_recv );
90101
91- echo "--- Truncated IPv6 header --- \n" ;
102+ echo "--- Another garbage payload with experimental ethertype --- \n" ;
92103$ s_send = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
93104$ s_recv = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
94105socket_bind ($ s_send , 'lo ' );
95106socket_bind ($ s_recv , 'lo ' );
107+ drain_socket ($ s_recv );
96108
97- // ETH_P_IPV6 ethertype but only a few garbage bytes as payload .
98- $ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , ETH_P_IPV6 ) . "\xCA\xFE" , 60 , "\x00" );
109+ // Use 0x88B6, another local experimental ethertype .
110+ $ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , 0x88B6 ) . "\xCA\xFE" , 60 , "\x00" );
99111$ sent = socket_sendto ($ s_send , $ frame , strlen ($ frame ), 0 , "lo " , 1 );
100112var_dump ($ sent === 60 );
101113
@@ -112,6 +124,7 @@ $s_send = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
112124$ s_recv = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
113125socket_bind ($ s_send , 'lo ' );
114126socket_bind ($ s_recv , 'lo ' );
127+ drain_socket ($ s_recv );
115128
116129$ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , 0x0000 ) . "zerotype " , 60 , "\x00" );
117130$ sent = socket_sendto ($ s_send , $ frame , strlen ($ frame ), 0 , "lo " , 1 );
@@ -130,6 +143,7 @@ $s_send = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
130143$ s_recv = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
131144socket_bind ($ s_send , 'lo ' );
132145socket_bind ($ s_recv , 'lo ' );
146+ drain_socket ($ s_recv );
133147
134148$ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , 0xFFFF ) . "maxtype " , 60 , "\x00" );
135149$ sent = socket_sendto ($ s_send , $ frame , strlen ($ frame ), 0 , "lo " , 1 );
@@ -148,6 +162,7 @@ $s_send = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
148162$ s_recv = socket_create (AF_PACKET , SOCK_RAW , ETH_P_ALL );
149163socket_bind ($ s_send , 'lo ' );
150164socket_bind ($ s_recv , 'lo ' );
165+ drain_socket ($ s_recv );
151166
152167$ payload = str_repeat ("X " , 200 );
153168$ frame = str_pad ($ dst_mac . $ src_mac . pack ("n " , 0x9000 ) . $ payload , 214 , "\x00" );
@@ -174,11 +189,11 @@ bool(true)
174189bool(true)
175190bool(true)
176191bool(true)
177- --- Truncated IP header (valid ether header, garbage IP) ---
192+ --- Garbage payload with custom ethertype ---
178193bool(true)
179194bool(true)
180195bool(true)
181- --- Truncated IPv6 header ---
196+ --- Another garbage payload with experimental ethertype ---
182197bool(true)
183198bool(true)
184199bool(true)
0 commit comments