@@ -135,4 +135,63 @@ public function testResponseCodeValidation(): void
135135 additionalCount: 0
136136 );
137137 }
138+
139+ /**
140+ * Test that packets with non-zero Z bits are accepted for interoperability.
141+ *
142+ * RFC 1035 says Z bits MUST be zero, but many DNS clients/proxies
143+ * (including Google's infrastructure) set these bits. We intentionally
144+ * ignore them to maximize compatibility.
145+ */
146+ public function testDecodeAcceptsNonZeroZBits (): void
147+ {
148+ // Flags with Z bits set (bits 4-6):
149+ // QR=1, opcode=0, AA=0, TC=0, RD=1, RA=1, Z=0b111, RCODE=0
150+ // = 1000 0001 1111 0000 = 0x81F0
151+ $ flagsWithAllZBits = 0x81F0 ;
152+ $ binaryHeader = pack ('nnnnnn ' , 0x1234 , $ flagsWithAllZBits , 1 , 0 , 0 , 0 );
153+
154+ $ decoded = Header::decode ($ binaryHeader );
155+
156+ // Verify the header is decoded correctly despite Z bits
157+ $ this ->assertSame (0x1234 , $ decoded ->id );
158+ $ this ->assertTrue ($ decoded ->isResponse );
159+ $ this ->assertSame (0 , $ decoded ->opcode );
160+ $ this ->assertFalse ($ decoded ->authoritative );
161+ $ this ->assertFalse ($ decoded ->truncated );
162+ $ this ->assertTrue ($ decoded ->recursionDesired );
163+ $ this ->assertTrue ($ decoded ->recursionAvailable );
164+ $ this ->assertSame (0 , $ decoded ->responseCode );
165+ $ this ->assertSame (1 , $ decoded ->questionCount );
166+ }
167+
168+ /**
169+ * Test various Z bit patterns are all accepted.
170+ */
171+ public function testDecodeAcceptsVariousZBitPatterns (): void
172+ {
173+ $ zBitPatterns = [
174+ 0x0010 , // Z bit 4 only
175+ 0x0020 , // Z bit 5 only
176+ 0x0040 , // Z bit 6 only
177+ 0x0030 , // Z bits 4 and 5
178+ 0x0050 , // Z bits 4 and 6
179+ 0x0060 , // Z bits 5 and 6
180+ 0x0070 , // All Z bits (4, 5, 6)
181+ ];
182+
183+ foreach ($ zBitPatterns as $ zBits ) {
184+ // Base flags: QR=0, opcode=0, AA=0, TC=0, RD=1, RA=0, RCODE=0
185+ // = 0000 0001 0000 0000 = 0x0100
186+ $ flags = 0x0100 | $ zBits ;
187+ $ binaryHeader = pack ('nnnnnn ' , 0xABCD , $ flags , 1 , 0 , 0 , 0 );
188+
189+ $ decoded = Header::decode ($ binaryHeader );
190+
191+ $ this ->assertSame (0xABCD , $ decoded ->id , "Failed for Z bits pattern: " . sprintf ('0x%04X ' , $ zBits ));
192+ $ this ->assertFalse ($ decoded ->isResponse );
193+ $ this ->assertTrue ($ decoded ->recursionDesired );
194+ $ this ->assertSame (0 , $ decoded ->responseCode );
195+ }
196+ }
138197}
0 commit comments