mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
Fix reverse DNS slave: strip trailing newline from input
The GANL adapter sends IP addresses to the slave with a trailing '\n' delimiter (stream framing), but slave.cpp passed the raw buffer — including the newline — to getaddrinfo(), which rejects it. This caused reverse DNS to silently fail, falling back to numeric IPs. Latent sinceb7fec8bc8(2012) when inet_addr() was replaced by getaddrinfo(); activated bya6f579c30(2026-03-03) when GANL replaced the old SOCK_DGRAM transport with stream pipes. Adds testcases/tools/SlaveDNS with 11 protocol-level tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7b9e415896
commit
982b82fbc8
2 changed files with 171 additions and 0 deletions
|
|
@ -207,6 +207,19 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
arg[len] = '\0';
|
||||
|
||||
// Strip trailing whitespace (the GANL adapter sends a newline
|
||||
// delimiter after the IP address).
|
||||
//
|
||||
while (len > 0 && (arg[len-1] == '\n' || arg[len-1] == '\r' || arg[len-1] == ' '))
|
||||
{
|
||||
arg[--len] = '\0';
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
child = fork();
|
||||
switch (child)
|
||||
{
|
||||
|
|
|
|||
158
testcases/tools/SlaveDNS
Executable file
158
testcases/tools/SlaveDNS
Executable file
|
|
@ -0,0 +1,158 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# SlaveDNS - Verify the reverse DNS slave binary works correctly.
|
||||
#
|
||||
# Tests the slave binary's protocol: write an IP address, read back
|
||||
# "<ip> <hostname>\n". Uses both with-newline and without-newline
|
||||
# inputs to match the GANL adapter's actual wire format.
|
||||
#
|
||||
# Exit 0 on success, 1 on failure.
|
||||
#
|
||||
|
||||
BIN=../mux/game/bin
|
||||
SLAVE=$BIN/slave
|
||||
PASS=0
|
||||
FAIL=0
|
||||
TOTAL=0
|
||||
|
||||
passed() {
|
||||
PASS=$((PASS + 1))
|
||||
TOTAL=$((TOTAL + 1))
|
||||
echo " PASS: $1"
|
||||
}
|
||||
|
||||
failed() {
|
||||
FAIL=$((FAIL + 1))
|
||||
TOTAL=$((TOTAL + 1))
|
||||
echo " FAIL: $1"
|
||||
}
|
||||
|
||||
echo "=== Reverse DNS Slave Tests ==="
|
||||
echo ""
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 0: Binary exists and is executable
|
||||
# ------------------------------------------------------------------
|
||||
if [ -x "$SLAVE" ]; then
|
||||
passed "slave binary exists and is executable"
|
||||
else
|
||||
failed "slave binary missing or not executable ($SLAVE)"
|
||||
echo ""
|
||||
echo "Result: FAIL (slave binary not found)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 1: Loopback without trailing newline (bare IP)
|
||||
# ------------------------------------------------------------------
|
||||
RESULT=$(printf "127.0.0.1" | timeout 10 "$SLAVE" 2>/dev/null)
|
||||
if echo "$RESULT" | grep -q "^127\.0\.0\.1 "; then
|
||||
passed "127.0.0.1 (no newline) resolves (got: $(echo "$RESULT" | tr -d '\n'))"
|
||||
else
|
||||
failed "127.0.0.1 (no newline) unexpected output (got: '$RESULT')"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 2: Loopback WITH trailing newline (GANL wire format)
|
||||
#
|
||||
# The GANL adapter appends '\n' after the IP. The slave must strip
|
||||
# the newline before passing it to getaddrinfo().
|
||||
# ------------------------------------------------------------------
|
||||
RESULT_NL=$(printf "127.0.0.1\n" | timeout 10 "$SLAVE" 2>/dev/null)
|
||||
if echo "$RESULT_NL" | grep -q "^127\.0\.0\.1 "; then
|
||||
passed "127.0.0.1 (with newline) resolves (got: $(echo "$RESULT_NL" | tr -d '\n'))"
|
||||
else
|
||||
failed "127.0.0.1 (with newline) unexpected output (got: '$RESULT_NL')"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 3: Response format — at least two space-separated fields
|
||||
# ------------------------------------------------------------------
|
||||
NFIELDS=$(echo "$RESULT" | head -1 | awk '{print NF}')
|
||||
if [ "$NFIELDS" -ge 2 ] 2>/dev/null; then
|
||||
passed "response has >= 2 fields (ip + hostname)"
|
||||
else
|
||||
failed "response field count unexpected (got $NFIELDS fields)"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 4: IP field in response matches input
|
||||
# ------------------------------------------------------------------
|
||||
RESP_IP=$(echo "$RESULT" | head -1 | awk '{print $1}')
|
||||
if [ "$RESP_IP" = "127.0.0.1" ]; then
|
||||
passed "response IP matches input (127.0.0.1)"
|
||||
else
|
||||
failed "response IP mismatch (expected 127.0.0.1, got '$RESP_IP')"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 5: With-newline and without-newline produce the same result
|
||||
# ------------------------------------------------------------------
|
||||
CLEAN1=$(echo "$RESULT" | head -1 | tr -s ' ')
|
||||
CLEAN2=$(echo "$RESULT_NL" | head -1 | tr -s ' ')
|
||||
if [ "$CLEAN1" = "$CLEAN2" ]; then
|
||||
passed "newline/no-newline produce identical output"
|
||||
else
|
||||
failed "newline/no-newline differ ('$CLEAN1' vs '$CLEAN2')"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 6: RFC 5737 documentation address (192.0.2.1) — no PTR
|
||||
# ------------------------------------------------------------------
|
||||
RESULT2=$(printf "192.0.2.1\n" | timeout 10 "$SLAVE" 2>/dev/null)
|
||||
RESP2_IP=$(echo "$RESULT2" | head -1 | awk '{print $1}')
|
||||
RESP2_HOST=$(echo "$RESULT2" | head -1 | awk '{print $2}')
|
||||
if [ "$RESP2_IP" = "192.0.2.1" ]; then
|
||||
passed "192.0.2.1 echoes back IP field correctly"
|
||||
else
|
||||
failed "192.0.2.1 IP field mismatch (got '$RESP2_IP')"
|
||||
fi
|
||||
|
||||
if [ -n "$RESP2_HOST" ]; then
|
||||
passed "192.0.2.1 returned a hostname field ('$RESP2_HOST')"
|
||||
else
|
||||
failed "192.0.2.1 returned empty hostname"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 7: Multiple lookups in a single session
|
||||
# ------------------------------------------------------------------
|
||||
RESULT3=$(printf "127.0.0.1\n192.0.2.1\n" | timeout 15 "$SLAVE" 2>/dev/null)
|
||||
NLINES=$(echo "$RESULT3" | grep -c '.')
|
||||
if [ "$NLINES" -ge 2 ] 2>/dev/null; then
|
||||
passed "multiple lookups returned $NLINES results"
|
||||
else
|
||||
failed "multiple lookups returned $NLINES results (expected >= 2)"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 8: Slave exits cleanly when stdin closes (EOF)
|
||||
# ------------------------------------------------------------------
|
||||
printf "" | timeout 5 "$SLAVE" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
passed "slave exits cleanly on EOF"
|
||||
else
|
||||
failed "slave did not exit cleanly on EOF (exit code $?)"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 9: Empty/whitespace-only input is ignored (no crash)
|
||||
# ------------------------------------------------------------------
|
||||
RESULT4=$(printf "\n\n \n" | timeout 5 "$SLAVE" 2>/dev/null)
|
||||
EXIT_CODE=$?
|
||||
if [ $EXIT_CODE -eq 0 ]; then
|
||||
passed "whitespace-only input handled gracefully"
|
||||
else
|
||||
failed "whitespace-only input caused exit code $EXIT_CODE"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Summary
|
||||
# ------------------------------------------------------------------
|
||||
echo ""
|
||||
echo "=== DNS Slave: $PASS/$TOTAL passed, $FAIL failed ==="
|
||||
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue