{"id":26879726,"url":"https://github.com/skysingh04/dns-server-rust","last_synced_at":"2025-07-26T17:11:09.642Z","repository":{"id":237835992,"uuid":"795329522","full_name":"SkySingh04/DNS-Server-Rust","owner":"SkySingh04","description":"Building a DNS Server from Scratch in RUST!","archived":false,"fork":false,"pushed_at":"2025-01-06T13:16:04.000Z","size":75,"stargazers_count":19,"open_issues_count":4,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-07T20:11:15.293Z","etag":null,"topics":["dns","dns-server","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SkySingh04.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.MD","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-05-03T03:36:51.000Z","updated_at":"2025-02-27T20:09:56.000Z","dependencies_parsed_at":"2024-05-03T10:10:27.332Z","dependency_job_id":"30beaf60-84f4-4ed0-aeaa-50e987d793e0","html_url":"https://github.com/SkySingh04/DNS-Server-Rust","commit_stats":null,"previous_names":["akash-singh04/dns_server-rust","skysingh04/dns-server-rust"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SkySingh04/DNS-Server-Rust","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkySingh04%2FDNS-Server-Rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkySingh04%2FDNS-Server-Rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkySingh04%2FDNS-Server-Rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkySingh04%2FDNS-Server-Rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SkySingh04","download_url":"https://codeload.github.com/SkySingh04/DNS-Server-Rust/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SkySingh04%2FDNS-Server-Rust/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267198700,"owners_count":24051559,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dns","dns-server","rust"],"created_at":"2025-03-31T13:31:45.982Z","updated_at":"2025-07-26T17:11:09.607Z","avatar_url":"https://github.com/SkySingh04.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# A DNS Server : Built with RUST!\nBuilding a DNS Server from Scratch in RUST!(yes I consider this language to be the language of the cool kids and yes I struggle to write a simple function in it and yes I want to earn money without having to do full stack). \n\nI have written notes about all the things I have learned in this Readme file, they are written in Hinglish for my reference.\n\n\n## Part 1 : Implementing the protocol\n\nDNS Packets ko bhejte h over UDP transport and limited to 512 bytes(Wo alag baat h there is exception where it can be sent over TCP as well and eDNS se packet size badha sakte h).\n\nDNS uses the same format in queries and responses. Mainly a DNS packet consists of:\n- Header : Isme hoga information about the query/response\n- Question Section : List of questions(hota ek hi h in practice) , each indicating the query name(domain) and the record type of interest\n- Answer Section : List of relevant records of the requested type\n- Authority Section : A list of name servers used for resolving queries recursively.\n- Additional Section : Additional useful info.\n\nEssentially 3 different objects ko support karna hoga:\n- Header : [dnsheader.rs](src/protocol/dnsheader.rs) mein implement kar diye : Iske liye we created another implementaion for the rescode field also in [resultcode.rs](src/protocol/resultcode.rs). RCode is set by the server to indicate the status of the response, i.e. whether or not it was successful or failed, and agar fail hua toh providing details about the cause of the failure.\n- Question : [dnsquestion.rs](src/protocol/dnsquestion.rs) : Iske liye we created another implementation of [querytype](src/protocol/querytype.rs), so that we can represent the *record type* being queried. \n- Record : [dnsrecord.rs](src/protocol/dnsrecord.rs) is used to represent the actual dns records and allow us to add new records later on easily.\n\n\n[byte_packet_buffer.rs](src/protocol/byte_packet_buffer.rs) asli problematic kaam karta h. The thing is DNS encodes each name into a sequence of labels, with each label prepended by a single byte indicating its length. Example would be *[3]www[6]google[3]com[0]*. Ye phir bhi theek h, but it gets even more problematic when jumps come into place. \n\n\u003e Due to the original size constraints of DNS, of 512 bytes for a single packet, some type of compression was needed. Since most of the space required is for the domain names, and part of the same name tends to reoccur, there's some obvious space saving opportunity.\n\nTo save space from reoccuring set of characters, DNS packets include a \"jump directive\", telling the packet parser to jump to another position, and finish reading the name there. This _jump_ can be read if the length byte has the two most significant bits set,iska matlab jump hai, and we need to follow the pointer.\n\nEk aur baat to be taken care of is, this jumps can cause a cycle if some problematic person adds it to the packet, so wo check karna padega. This along with reading of the packets is all implemented in the byte_packet_buffer.\n\nBas phir, we can put together all of this now in our [dnspacket.rs](src/protocol/dnspacket.rs) to finish our protocol implementation.\n\nTo test it out, run the [main.rs](src/protocol/main.rs) file with our `response_packet.txt` \n\nThe output will be : \n```\ncargo run\n   Compiling DNS-Server-Rust v0.1.0 (/home/akash/Desktop/rust/DNS-Server-Rust)\n\nwarning: `DNS-Server-Rust` (bin \"DNS-Server-Rust\") generated 8 warnings\n    Finished dev [unoptimized + debuginfo] target(s) in 0.17s\n     Running `target/debug/DNS-Server-Rust`\nDnsHeader {\n    id: 16488,\n    recursion_desired: true,\n    truncated_message: false,\n    authoritative_answer: false,\n    opcode: 0,\n    response: true,\n    rescode: NOERROR,\n    checking_disabled: false,\n    authed_data: false,\n    z: false,\n    recursion_available: true,\n    questions: 1,\n    answers: 1,\n    authoritative_entries: 0,\n    resource_entries: 0,\n}\nDnsQuestion {\n    name: \"google.com\",\n    qtype: A,\n}\nA {\n    domain: \"google.com\",\n    addr: 142.250.183.238,\n    ttl: 74,\n}\n```\n\n## Part 2 : Building a stub resolver\n\nA stub resolver is a DNS Client that doesn't feature any built-in support for recursive lookup and that will only work with a DNS server that does.\n\n- We need to extend our [byte_packet_buffer.rs](src/protocol/byte_packet_buffer.rs) to add methods for writing bytes and for writing query names in labeled form. Additionally, we will be extending our Header, Record, Question and Packet structs.\n\n- Next we can implement a Stub Resolver using the *UDPSocket* included in rust, instead of having to read a packet file.\n\nThe output of running the stub resolver was : \n```\ncargo run\nwarning: crate `DNS_Server_Rust` should have a snake case name\n  |\n  = help: convert the identifier to snake case: `dns_server_rust`\n  = note: `#[warn(non_snake_case)]` on by default\n\nwarning: `DNS-Server-Rust` (bin \"DNS-Server-Rust\") generated 1 warning\n    Finished dev [unoptimized + debuginfo] target(s) in 0.00s\n     Running `target/debug/DNS-Server-Rust`\nDnsHeader {\n    id: 6666,\n    recursion_desired: true,\n    truncated_message: false,\n    authoritative_answer: false,\n    opcode: 0,\n    response: true,\n    rescode: NOERROR,\n    checking_disabled: false,\n    authed_data: false,\n    z: false,\n    recursion_available: true,\n    questions: 1,\n    answers: 1,\n    authoritative_entries: 0,\n    resource_entries: 0,\n}\nDnsQuestion {\n    name: \"google.com\",\n    qtype: A,\n}\nA {\n    domain: \"google.com\",\n    addr: 172.217.167.142,\n    ttl: 80,\n}\n```\n\n## Part 3 : Adding More Record types\n\nCurrently we support only A type records. But ofcourse, there are n number of record types (most of them don't see any use) but some important ones are: \n\n| ID  | Name  | Description                                              | Encoding                                         |\n| --- | ----- | -------------------------------------------------------- | ------------------------------------------------ |\n| 1   | A     | Alias - Mapping names to IP addresses                    | Preamble + Four bytes for IPv4 adress            |\n| 2   | NS    | Name Server - The DNS server address for a domain        | Preamble + Label Sequence                        |\n| 5   | CNAME | Canonical Name - Maps names to names                     | Preamble + Label Sequence                        |\n| 6   | SOA   | Start of Authority - Provides authoritative information  | Preamble + Label Sequence          |\n| 15  | MX    | Mail eXchange - The host of the mail server for a domain | Preamble + 2-bytes for priority + Label Sequence |\n| 16  | TXT   | Text - Arbitrary text data associated with a domain      | Preamble + Text data                              |\n| 28  | AAAA  | IPv6 address                                             | Preamble + Sixteen bytes for IPv6 address        |\n\n- We need to update our `QueryType` enum and change our utility functions. We also need to extend our `DnsRecord` for reading new record types and extend the functions foe reading and writing the new type of records.\n\nNow if we query for *Yahoo.com* with QueryType set as *MX*, we can see our new type of records:\n\n```\ncargo run\n   Compiling DNS-Server-Rust v0.1.0 (/home/akash/Desktop/rust/DNS-Server-Rust)\n\nwarning: `DNS-Server-Rust` (bin \"DNS-Server-Rust\") generated 2 warnings\n    Finished dev [unoptimized + debuginfo] target(s) in 0.14s\n     Running `target/debug/DNS-Server-Rust`\nDnsHeader {\n    id: 6666,\n    recursion_desired: true,\n    truncated_message: false,\n    authoritative_answer: false,\n    opcode: 0,\n    response: true,\n    rescode: NOERROR,\n    checking_disabled: false,\n    authed_data: false,\n    z: false,\n    recursion_available: true,\n    questions: 1,\n    answers: 3,\n    authoritative_entries: 0,\n    resource_entries: 0,\n}\nDnsQuestion {\n    name: \"yahoo.com\",\n    qtype: MX,\n}\nMX {\n    domain: \"yahoo.com\",\n    priority: 1,\n    host: \"mta5.am0.yahoodns.net\",\n    ttl: 1673,\n}\nMX {\n    domain: \"yahoo.com\",\n    priority: 1,\n    host: \"mta7.am0.yahoodns.net\",\n    ttl: 1673,\n}\nMX {\n    domain: \"yahoo.com\",\n    priority: 1,\n    host: \"mta6.am0.yahoodns.net\",\n    ttl: 1673,\n}\n```\n\nAnd for *meetakash.vercel.app* with *SOA* query type:\n```\ncargo run\n   Compiling DNS-Server-Rust v0.1.0 (/home/akash/Desktop/rust/DNS-Server-Rust)\n\nwarning: `DNS-Server-Rust` (bin \"DNS-Server-Rust\") generated 2 warnings\n    Finished dev [unoptimized + debuginfo] target(s) in 0.15s\n     Running `target/debug/DNS-Server-Rust`\nDnsHeader {\n    id: 6666,\n    recursion_desired: true,\n    truncated_message: false,\n    authoritative_answer: false,\n    opcode: 0,\n    response: true,\n    rescode: NOERROR,\n    checking_disabled: false,\n    authed_data: false,\n    z: false,\n    recursion_available: true,\n    questions: 1,\n    answers: 0,\n    authoritative_entries: 1,\n    resource_entries: 0,\n}\nDnsQuestion {\n    name: \"meetakash.vercel.app\",\n    qtype: SOA,\n}\nSOA {\n    domain: \"vercel.app\",\n    mname: \"ns1.vercel-dns.com\",\n    rname: \"hostmaster.nsone.net\",\n    serial: 1659373707,\n    refresh: 43200,\n    retry: 7200,\n    expire: 1209600,\n    minimum: 14400,\n    ttl: 1800,\n}\n```\n\n## Part 4 : Ab banega Actual DNS Server\n\nThere are essentially two types of DNS servers, A DNS server can do both in theory but usually they are mutually exclusive.\n\n- *Authoritative Server* : A DNS Server hosting one or more \"zones\".ex: The authoritative servers for the zone google.com are ns1.google.com, ns2.google.com, ns3.google.com and ns4.google.com.\n\n- *Caching Server* : A DNS server that serves DNS lookups by first checking its chache to see if it already knows of rhe record being requested, and if not performs a recursive lookup.\n\nFirst we can implement a server that simply forwards queries to another caching server, i.e. a \"DNS proxy server\". We will refactor our [main.rs](src/main.rs) by moving our lookup code into a separate function. Along with that, we will write our server code to handle requests.\n\nNow we can start our server in one terminal and then use `dig` to perform lookup in a second terminal.\n\n```\ndig @127.0.0.1 -p 2053 meetakash.vercel.app\n\n; \u003c\u003c\u003e\u003e DiG 9.18.18-0ubuntu0.22.04.2-Ubuntu \u003c\u003c\u003e\u003e @127.0.0.1 -p 2053 meetakash.vercel.app\n; (1 server found)\n;; global options: +cmd\n;; Got answer:\n;; -\u003e\u003eHEADER\u003c\u003c- opcode: QUERY, status: NOERROR, id: 37880\n;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;meetakash.vercel.app.          IN      A\n\n;; ANSWER SECTION:\nmeetakash.vercel.app.   1800    IN      A       76.76.21.93\nmeetakash.vercel.app.   1800    IN      A       76.76.21.164\n\n;; Query time: 148 msec\n;; SERVER: 127.0.0.1#2053(127.0.0.1) (UDP)\n;; WHEN: Sat Jun 08 10:26:37 IST 2024\n;; MSG SIZE  rcvd: 110\n```\n\nAnd in our server terminal we can see : \n```\ncargo run\n   Compiling DNS-Server-Rust v0.1.0 (/home/akash/Desktop/rust/DNS-Server-Rust)\nwarning: `DNS-Server-Rust` (bin \"DNS-Server-Rust\") generated 1 warning\n    Finished dev [unoptimized + debuginfo] target(s) in 0.15s\n     Running `target/debug/DNS-Server-Rust`\nServer started successfully on port 2053\nReceived query: DnsQuestion { name: \"google.com\", qtype: A }\nAnswer: A { domain: \"google.com\", addr: 142.250.196.78, ttl: 245 }\nReceived query: DnsQuestion { name: \"meetakash.vercel.app\", qtype: A }\nAnswer: A { domain: \"meetakash.vercel.app\", addr: 76.76.21.93, ttl: 1800 }\nAnswer: A { domain: \"meetakash.vercel.app\", addr: 76.76.21.164, ttl: 1800 }\n```\n\nLessgooo, we have a DNS server that is able to respond to queries with several different record types!!\n\n## Part 5 : Implementing a recursive resolver\n\nOur server is very nice as it is now, but we are reliant on another server to actually perform the lookup.\n\nThe question is first issued to one of the Internet's 13 root servers. Any resolver will need to know of these 13 servers before hand. A file containing all of them, in bind format, is available on the internet and called [named.root](https://www.internic.net/domain/named.root). These servers all contain the same information, and to get started we can pick one of them at random.\n\nThe flow is simple:\n\n- The initial query is sent to the root server, which don't know the full `www.google.com` but they do know about `com`, and the reply will tell us where to go next.(This step is usually cached).\n\n- Next again, we will get a list of shortlisted domains that will point us to the domain.\n\n- On this lookup, we will get the IP address of our website.\n\nIn practice, a DNS server will maintain a cache, and most TLD's will be known since before. That means that most queries will only ever require two lookups by the server, and commonly one or zero.\n\nNow we can extend [dnspacket.rs](src/protocol/dnspacket.rs) for recursive lookups. Then, we can implement our recursive lookup and change our `handle_query` function to use our new recursive lookup!\n\nGreat, now we can see the output as : \n```\ndig @127.0.0.1 -p 2053 www.google.com\n\n; \u003c\u003c\u003e\u003e DiG 9.18.18-0ubuntu0.22.04.2-Ubuntu \u003c\u003c\u003e\u003e @127.0.0.1 -p 2053 www.google.com\n; (1 server found)\n;; global options: +cmd\n;; Got answer:\n;; -\u003e\u003eHEADER\u003c\u003c- opcode: QUERY, status: NOERROR, id: 35891\n;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;www.google.com.                        IN      A\n\n;; ANSWER SECTION:\nwww.google.com.         300     IN      A       172.217.163.196\n\n;; Query time: 195 msec\n;; SERVER: 127.0.0.1#2053(127.0.0.1) (UDP)\n;; WHEN: Wed Jun 12 13:42:43 IST 2024\n;; MSG SIZE  rcvd: 62\n\n```\n\nAnd in our server window : \n```\n Finished dev [unoptimized + debuginfo] target(s) in 0.34s\n     Running `target/debug/DNS-Server-Rust`\nServer started successfully on port 2053\nReceived query: DnsQuestion { name: \"www.google.com\", qtype: A }\nAttempting lookup of A www.google.com with ns 198.41.0.4\nAttempting lookup of A www.google.com with ns 192.41.162.30\nAttempting lookup of A www.google.com with ns 216.239.34.10\nAnswer: A { domain: \"www.google.com\", addr: 172.217.163.196, ttl: 300 }\n```\n\nAnd that's it! That is our DNS server completed!\n\n## Contributing\n\nContributions are welcome! Please read the [CONTRIBUTING.md](CONTRIBUTING.md) file for more details on how to get involved.\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskysingh04%2Fdns-server-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskysingh04%2Fdns-server-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskysingh04%2Fdns-server-rust/lists"}