├── CMakeLists.txt ├── LICENSE ├── README.md ├── component.mk ├── dns_server.c └── include └── dns_server.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRC_DIRS "." 3 | INCLUDE_DIRS "include" 4 | REQUIRES nvs_flash 5 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Luke Cyca 4 | Copyright (c) 2017 Olof Astrand (Ebiroll) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp32-dns-server 2 | 3 | Limitations: 4 | * Does not work when the esp32 has multiple IP interfaces (for example, STA+AP mode) 5 | -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | -------------------------------------------------------------------------------- /dns_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2017 Olof Astrand (Ebiroll) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | static const char TAG[] = "DNSSRV"; 45 | 46 | 47 | 48 | 49 | 50 | void receive_thread(void *pvParameters) { 51 | int socket_fd; 52 | struct sockaddr_in sa, ra; 53 | 54 | 55 | 56 | socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 57 | if (socket_fd < 0){ 58 | ESP_LOGE(TAG, "Failed to create socket"); 59 | exit(0); 60 | } 61 | 62 | memset(&sa, 0, sizeof(struct sockaddr_in)); 63 | 64 | tcpip_adapter_ip_info_t ip; 65 | tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip); 66 | ra.sin_family = AF_INET; 67 | ra.sin_addr.s_addr = ip.ip.addr; 68 | ra.sin_port = htons(53); 69 | if (bind(socket_fd, (struct sockaddr *)&ra, sizeof(struct sockaddr_in)) == -1) { 70 | ESP_LOGE(TAG, "Failed to bind to 53/udp"); 71 | close(socket_fd); 72 | exit(1); 73 | } 74 | 75 | struct sockaddr_in client; 76 | socklen_t client_len; 77 | client_len = sizeof(client); 78 | int length; 79 | char data[80]; 80 | char response[100]; 81 | char ipAddress[INET_ADDRSTRLEN]; 82 | int idx; 83 | int err; 84 | 85 | ESP_LOGI(TAG, "DNS Server listening on 53/udp"); 86 | while (1) { 87 | length = recvfrom(socket_fd, data, sizeof(data), 0, (struct sockaddr *)&client, &client_len); 88 | if (length > 0) { 89 | data[length] = '\0'; 90 | 91 | inet_ntop(AF_INET, &(client.sin_addr), ipAddress, INET_ADDRSTRLEN); 92 | ESP_LOGI(TAG, "Replying to DNS request (len=%d) from %s", length, ipAddress); 93 | 94 | // Prepare our response 95 | response[0] = data[0]; 96 | response[1] = data[1]; 97 | response[2] = 0b10000100 | (0b00000001 & data[2]); //response, authorative answer, not truncated, copy the recursion bit 98 | response[3] = 0b00000000; //no recursion available, no errors 99 | response[4] = data[4]; 100 | response[5] = data[5]; //Question count 101 | response[6] = data[4]; 102 | response[7] = data[5]; //answer count 103 | response[8] = 0x00; 104 | response[9] = 0x00; //NS record count 105 | response[10]= 0x00; 106 | response[11]= 0x00; //Resource record count 107 | 108 | memcpy(response+12, data+12, length-12); //Copy the rest of the query section 109 | idx = length; 110 | 111 | // Prune off the OPT 112 | // FIXME: We should parse the packet better than this! 113 | if ((response[idx-11] == 0x00) && (response[idx-10] == 0x00) && (response[idx-9] == 0x29)) 114 | idx -= 11; 115 | 116 | //Set a pointer to the domain name in the question section 117 | response[idx] = 0xC0; 118 | response[idx+1] = 0x0C; 119 | 120 | //Set the type to "Host Address" 121 | response[idx+2] = 0x00; 122 | response[idx+3] = 0x01; 123 | 124 | //Set the response class to IN 125 | response[idx+4] = 0x00; 126 | response[idx+5] = 0x01; 127 | 128 | //A 32 bit integer specifying TTL in seconds, 0 means no caching 129 | response[idx+6] = 0x00; 130 | response[idx+7] = 0x00; 131 | response[idx+8] = 0x00; 132 | response[idx+9] = 0x00; 133 | 134 | //RDATA length 135 | response[idx+10] = 0x00; 136 | response[idx+11] = 0x04; //4 byte IP address 137 | 138 | //The IP address 139 | response[idx + 12] = 192; 140 | response[idx + 13] = 168; 141 | response[idx + 14] = 1; 142 | response[idx + 15] = 1; 143 | 144 | err = sendto(socket_fd, response, idx+16, 0, (struct sockaddr *)&client, client_len); 145 | if (err < 0) { 146 | ESP_LOGE(TAG, "sendto failed: %s", strerror(errno)); 147 | } 148 | } 149 | } 150 | close(socket_fd); 151 | } 152 | 153 | void init_dns_server() { 154 | xTaskCreate(&receive_thread, "receive_thread", 3048, NULL, 5, NULL); 155 | } 156 | -------------------------------------------------------------------------------- /include/dns_server.h: -------------------------------------------------------------------------------- 1 | void init_dns_server(); 2 | --------------------------------------------------------------------------------