Created
May 21, 2025 08:01
-
-
Save aerosol/0b6f7491a1726ac2c622f83550b699e5 to your computer and use it in GitHub Desktop.
simple_dns_server.ex
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule SimpleDNSServer do | |
@moduledoc """ | |
A simple DNS server that responds to TXT queries with fixed sample values. | |
""" | |
# Use 5353 for testing to avoid requiring root privileges for port 53 | |
@dns_port 9999 | |
@txt_records ["v=spf1 include:_spf.example.com ~all", "key1=value1", "key2=value2"] | |
def start do | |
{:ok, socket} = :gen_udp.open(@dns_port, [:binary, active: true, ip: {0, 0, 0, 0}]) | |
IO.puts("DNS server running on port #{@dns_port}") | |
loop(socket) | |
end | |
defp loop(socket) do | |
receive do | |
{:udp, _socket, client_ip, client_port, query} -> | |
IO.inspect({client_ip, client_port, query}, label: "Received DNS query") | |
response = build_response(query) | |
:gen_udp.send(socket, client_ip, client_port, response) | |
loop(socket) | |
end | |
end | |
defp build_response(query) do | |
# Extract the transaction ID (first 2 bytes of the query) | |
<<transaction_id::16, flags::16, qdcount::16, _rest::binary>> = query | |
# Build the DNS response header | |
header = << | |
# Transaction ID | |
transaction_id::16, | |
# Flags: Standard query response, no error | |
0b10000100_00000000::16, | |
# Questions: Echo the number of questions | |
qdcount::16, | |
# Answer RRs: 1 | |
1::16, | |
# Authority RRs: 0 | |
0::16, | |
# Additional RRs: 0 | |
0::16 | |
>> | |
# Extract the question section (everything after the header) | |
<<_header::binary-size(12), question::binary>> = query | |
# Build the answer section for a single TXT record | |
txt_value = "v=spf1 include:_spf.example.com ~all" | |
txt_data = encode_txt_data(txt_value) | |
answer = << | |
# Name: Pointer to the question | |
0xC00C::16, | |
# Type: TXT | |
16::16, | |
# Class: IN (Internet) | |
1::16, | |
# TTL: 60 seconds | |
60::32, | |
# Data length | |
byte_size(txt_data)::16, | |
# TXT data | |
txt_data::binary | |
>> | |
# Combine the header, question, and answer sections | |
header <> question <> answer | |
end | |
defp encode_txt_data(txt_value) do | |
# Encode the TXT value as a length-prefixed string | |
<<byte_size(txt_value)::8, txt_value::binary>> | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment