DNS Resolver server is being shutdown early

Hi,

I’m implementing the resolver server and for most tests it works except for test “Parse header section #uc8”.

It looks like the Client that sends the DNS packets is making multiple requests, and because the program is launched using “–resover <forward_server>” all the requests are forwarded to the resolver.

The issue is that the Resolver server is being shut down early, I will put the log trace of the tests below, you can see that the Client sends 3 separate requests to my server for “codecrafters.io”, my server forwards these 3 requests separately and receive the right answer for the first two requests but I’m receiving only the header from the Resolver for the third request.

Here are my logs:

[tester::#UC8] Running tests for Stage #UC8 (Parse header section)
[tester::#UC8] Starting DNS server on 127.0.0.1:2053
[tester::#UC8] Running program
[tester::#UC8] DNS resolver listening on 127.0.0.1:5354
[tester::#UC8] Connecting to 127.0.0.1:2053 using UDP
[your_program] Setting 127.0.0.1:5354 as a forward destination
[your_program] Incoming data from Client (hex):
[your_program] 1e cf 01 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[your_program] Preparing to forward question(s) to the Resolver server
[your_program] Connected to remote server
[your_program] Outgoing data to Resolver (hex):
[your_program] 1e cf 01 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[your_program] Forwarder server received data
[your_program] Incoming data from Resolver (hex):
[tester::#UC8] Querying: ;codecrafters.io.	IN	 A
[tester::#UC8] Sending Request: (Messages with >>> prefix are part of this log)
[tester::#UC8] >>> ;; opcode: QUERY, status: NOERROR, id: 23115
[tester::#UC8] >>> ;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
[tester::#UC8] >>>
[tester::#UC8] >>> ;; QUESTION SECTION:
[tester::#UC8] >>> ;codecrafters.io.	IN	 A
[tester::#UC8] >>>
[your_program] 1e cf 81 00 00 01 00 01 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01 0c 63 6f 64 65 63 72 61 66 74 65 72 73 02 69
[your_program] 6f 00 00 01 00 01 00 00 0e 10 00 04 4c 4c 15 15
[your_program]
[your_program] Outgoing data to Client (hex):
[your_program] 1e cf 81 00 00 01 00 01 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01 0c 63 6f 64 65 63 72 61 66 74 65 72 73 02 69
[your_program] 6f 00 00 01 00 01 00 00 0e 10 00 04 4c 4c 15 15
[your_program]
[your_program] Incoming data from Client (hex):
[your_program] 5a 4b 01 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[your_program] Preparing to forward question(s) to the Resolver server
[your_program] Already connected to remote server
[your_program] Outgoing data to Resolver (hex):
[your_program] 5a 4b 01 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[tester::#UC8] Received Response: (Messages with >>> prefix are part of this log)
[tester::#UC8] >>> ;; opcode: QUERY, status: NOERROR, id: 23115
[tester::#UC8] >>> ;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
[tester::#UC8] >>>
[tester::#UC8] >>> ;; QUESTION SECTION:
[tester::#UC8] >>> ;codecrafters.io.	IN	 A
[tester::#UC8] >>>
[tester::#UC8] >>> ;; ANSWER SECTION:
[tester::#UC8] >>> codecrafters.io.	3600	IN	A	76.76.21.21
[tester::#UC8] >>>
[tester::#UC8] Querying: ;codecrafters.io.	IN	 A
[tester::#UC8] Sending Request: (Messages with >>> prefix are part of this log)
[tester::#UC8] >>> ;; opcode: IQUERY, status: NOERROR, id: 23115
[tester::#UC8] >>> ;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
[tester::#UC8] >>>
[tester::#UC8] >>> ;; QUESTION SECTION:
[tester::#UC8] >>> ;codecrafters.io.	IN	 A
[tester::#UC8] >>>
[your_program] Forwarder server received data
[your_program] Incoming data from Resolver (hex):
[your_program] 5a 4b 81 00 00 01 00 01 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01 0c 63 6f 64 65 63 72 61 66 74 65 72 73 02 69
[your_program] 6f 00 00 01 00 01 00 00 0e 10 00 04 4c 4c 15 15
[your_program]
[your_program] Outgoing data to Client (hex):
[your_program] 5a 4b 81 00 00 01 00 01 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01 0c 63 6f 64 65 63 72 61 66 74 65 72 73 02 69
[your_program] 6f 00 00 01 00 01 00 00 0e 10 00 04 4c 4c 15 15
[your_program]
[your_program] Incoming data from Client (hex):
[your_program] 5a 4b 09 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[your_program] Preparing to forward question(s) to the Resolver server
[your_program] Already connected to remote server
[your_program] Outgoing data to Resolver (hex):
[your_program] 5a 4b 09 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[your_program] Forwarder server received data
[your_program] Incoming data from Resolver (hex):
[your_program] 5a 4b 89 04 00 00 00 00 00 00 00 00
[your_program]
[your_program] panic: runtime error: index out of range [33] with length 12
[your_program]
[your_program] goroutine 1 [running]:
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.decodeLabel({0xc000102600?, 0x0?, 0xc000074a80?}, 0x4d013a?, 0x8?)
[your_program] 	/app/server/decoder.go:81 +0x2f4
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Decoder).DecodeQuestion(0xc000074b98)
[your_program] 	/app/server/decoder.go:54 +0x30
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Decoder).DecodeAnswer(0xc000074b98, 0xc?)
[your_program] 	/app/server/decoder.go:65 +0x45
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Server).forwardQuestions(0xc000074ee8, {0x5a4b, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, ...}, ...)
[your_program] 	/app/server/server.go:162 +0x3cd
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Server).handleUDPEndpoint(0xc000074ee8, {{0xc000100000}})
[your_program] 	/app/server/server.go:74 +0x189
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Server).ListenUDP(0xc000074ee8, 0xc000044028?)
[your_program] 	/app/server/server.go:48 +0x90
[your_program] main.main()
[your_program] 	/app/app/main.go:28 +0x1bc
[tester::#UC8] Shutting down DNS resolver server...
[tester::#UC8] DNS query failed: read udp 127.0.0.1:48779->127.0.0.1:2053: i/o timeout.
[tester::#UC8] If you are seeing this after a while then it is likely that your server is not responding with appropriate id
[tester::#UC8] Test failed

I’m getting “panic: runtime error: index out of range [33] with length 12” because I decoded the Resolver’s answer from the offset of my request (since the header and question should be the same length in the answer as in the request).

I can work around it by implementing a Cache for my Server, which will cancel the need to forward the last two requests, but I think there is an issue with the test, it shuts down the resolver too early.

Implementing a Cache allowed me to work around this issue but sometimes, the Resolver seems to misbehave, another example:

[tester::#YC9] Running tests for Stage #YC9 (Parse compressed packet)
[tester::#YC9] Starting DNS server on 127.0.0.1:2053
[tester::#YC9] Running program
[tester::#YC9] Connecting to 127.0.0.1:2053 using UDP
[tester::#YC9] DNS resolver listening on 127.0.0.1:5354
[your_program] Setting 127.0.0.1:5354 as a forward destination
[your_program] Incoming data from Client (hex):
[your_program] 58 dc 01 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[your_program] Preparing to forward question(s) to the Resolver server
[your_program] Connected to remote server
[your_program] Outgoing data to Resolver (hex):
[your_program] 58 dc 01 00 00 01 00 00 00 00 00 00 0c 63 6f 64
[your_program] 65 63 72 61 66 74 65 72 73 02 69 6f 00 00 01 00
[your_program] 01
[your_program]
[your_program] Forwarder server received data
[your_program] Incoming data from Resolver (hex):
[your_program]
[your_program]
[your_program] panic: runtime error: index out of range [33] with length 0
[your_program]
[your_program] goroutine 1 [running]:
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.decodeLabel({0xc0000aa200?, 0x0?, 0xc0000b9990?}, 0x4d013a?, 0xe8?)
[your_program] 	/app/server/decoder.go:81 +0x2f4
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Decoder).DecodeQuestion(0xc0000b9b30)
[your_program] 	/app/server/decoder.go:54 +0x30
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Decoder).DecodeAnswer(0xc0000b9b30, 0x0?)
[your_program] 	/app/server/decoder.go:65 +0x45
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Server).forwardQuestions(0xc0000b9ee0, {0x58dc, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, ...}, ...)
[your_program] 	/app/server/server.go:168 +0x5c7
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Server).handleUDPEndpoint(0xc0000b9ee0, {{0xc0000a6000}})
[your_program] 	/app/server/server.go:75 +0x189
[your_program] github.com/codecrafters-io/dns-server-starter-go/server.(*Server).ListenUDP(0xc00008cee0, 0xc000084020?)
[your_program] 	/app/server/server.go:49 +0x90
[your_program] main.main()
[your_program] 	/app/app/main.go:28 +0x1dc
[tester::#YC9] Shutting down DNS resolver server...
[tester::#YC9] Looks like your program has terminated. A DNS server is expected to be a long-running process.
[tester::#YC9] Test failed

After this failure, I ran the tests again and all the tests passed.

I don’t think the problem is my code, as you can see in the logs, the first request sent by the client is met with an empty response from the Resolver, I didn’t change any code, ran the tests again and passed, clearly something environmental to the Resolver/Tests.

@ValentinJub The message causing the error is actually well-formed. The issue is that both the QDCOUNT and ANCOUNT fields are 0, meaning the entire message consists only of the header, with no question or answer records.

If you can modify the code to handle such messages, caching won’t be necessary.

Thanks for your answer, I should have paid more attention to what the header said!

But I’m glad I was able to work around it using a Cache, after all, that’s how DNS work :stuck_out_tongue:

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.