--Decode a string like "de ad be ef" into a binary string (in this case - --four-byte 0xDEADBEEF.) function unhex(str) str = string.gsub (str, "(%x%x) ?", function(h) return string.char(tonumber(h,16)) end) return str end --Convert an IPv4 address like 127.0.0.1 to four-byte binary string. function ipv4_to_hex(ip) ret = "" for v in ip:gmatch("(%d%d?%d?)[.]?") do --at least one digit, maybe a dot. if ret == nil then break end ret = ret .. string.char(v) end return ret end --A table of known IP addresses. responses = { ["localhost"] = "127.0.0.1", ["google-public-dns-a.google.com"] = "8.8.8.8" } --Read the query. transaction_id = io.stdin:read(2) flags = io.stdin:read(2) questions = io.stdin:read(2) answer_rrs = io.stdin:read(2) authority_rrs = io.stdin:read(2) additional_rrs = io.stdin:read(2) query = "" raw_query = "" while true do --Read a byte, then as many bytes as the hex value of the first one. byte = io.stdin:read(1) raw_query = raw_query .. byte if byte:byte(1)==0x00 then --NULL marks end of the string. break end for i=1,byte:byte(1) do byte = io.stdin:read(1) raw_query = raw_query .. byte query = query .. byte end query = query .. '.' end query=query:sub(1,query:len()-1) --strip the trailing dot. ip = responses[query] -- 1... .... .... .... = Response: Message is a response -- .000 0... .... .... = Opcode: Standard query (0) -- .... .0.. .... .... = Authoritative: Server is not an authority for domain -- .... ..0. .... .... = Truncated: Message is not truncated -- .... ...1 .... .... = Recursion desired: Do query recursively flags = unhex('81') if ip ~= nil then ip = ipv4_to_hex(ip) answers = unhex("00 01") -- .... .... 1... .... = Recursion available: Server can do recursive queries -- .... .... .0.. .... = Z: reserved (0) -- .... .... ..0. .... = Answer authenticated: Answer/authority portion was -- not authenticated by the server -- .... .... ...0 .... = Non-authenticated data: Unacceptable -- .... .... .... 0000 = Reply code: No error (0) flags = unhex("81 80") else answers = unhex("00 00") --.... .... 1... .... = Recursion available: Server can do recursive queries --.... .... ..1. .... = Answer authenticated: Answer/authority portion was -- authenticated by the server --.... .... ...0 .... = Non-authenticated data: Unacceptable --.... .... .... 0011 = Reply code: No such name (3) flags = unhex("81 a3") end q_type = io.stdin:read(2) class = io.stdin:read(2) aditional_records = io.stdin:read(11) --hardcoded for "dig". io.stderr:write("Got a query '"..query.."'.\n") io.stderr:flush() io.stdout:write(transaction_id) io.stdout:write(flags) --flags, hardcoded. io.stdout:write(questions) io.stdout:write(answers) io.stdout:write(unhex("00 00")) io.stdout:write(unhex("00 00")) --question section io.stdout:write(raw_query) io.stdout:write(q_type) io.stdout:write(class) if ip ~= nil then --answer section io.stdout:write(unhex("c0 0c")) --hostname offset? io.stdout:write(q_type) io.stdout:write(class) io.stdout:write(unhex("00 00 00 da")) --TTL = 3min38s io.stdout:write(unhex("00 04")) --data length io.stdout:write(ip) end io.stdout:flush()