dns_server.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #include "dns_server.h"
  2. #include "spiram_task.h"
  3. #include "esp_log.h"
  4. #include "esp_netif.h"
  5. #include "lwip/sockets.h"
  6. #include "freertos/FreeRTOS.h"
  7. #include "freertos/task.h"
  8. #include <string.h>
  9. static const char *TAG = "dns_server";
  10. #define DNS_PORT 53
  11. #define DNS_MAX_LEN 512
  12. // DNS header structure
  13. typedef struct __attribute__((packed)) {
  14. uint16_t id;
  15. uint16_t flags;
  16. uint16_t qdcount;
  17. uint16_t ancount;
  18. uint16_t nscount;
  19. uint16_t arcount;
  20. } dns_header_t;
  21. static int s_dns_socket = -1;
  22. static TaskHandle_t s_dns_task = NULL;
  23. static uint32_t s_redirect_ip = 0;
  24. static void dns_server_task(void *pvParameters) {
  25. uint8_t rx_buffer[DNS_MAX_LEN];
  26. uint8_t tx_buffer[DNS_MAX_LEN];
  27. struct sockaddr_in client_addr;
  28. socklen_t addr_len = sizeof(client_addr);
  29. ESP_LOGI(TAG, "DNS server task started");
  30. while (1) {
  31. int len = recvfrom(s_dns_socket, rx_buffer, sizeof(rx_buffer), 0,
  32. (struct sockaddr *)&client_addr, &addr_len);
  33. if (len < 0) {
  34. if (errno == EAGAIN || errno == EWOULDBLOCK) {
  35. vTaskDelay(pdMS_TO_TICKS(10));
  36. continue;
  37. }
  38. ESP_LOGE(TAG, "recvfrom failed: %d", errno);
  39. break;
  40. }
  41. if (len < (int)sizeof(dns_header_t)) {
  42. continue;
  43. }
  44. dns_header_t *req_header = (dns_header_t *)rx_buffer;
  45. // Build response
  46. memcpy(tx_buffer, rx_buffer, len);
  47. dns_header_t *resp_header = (dns_header_t *)tx_buffer;
  48. // Set response flags: QR=1 (response), AA=1 (authoritative), RCODE=0 (no
  49. // error)
  50. resp_header->flags = htons(0x8400);
  51. resp_header->ancount = req_header->qdcount; // Answer count = question count
  52. int resp_len = len;
  53. // Add answer section for each question
  54. uint16_t qdcount = ntohs(req_header->qdcount);
  55. uint8_t *ptr = rx_buffer + sizeof(dns_header_t);
  56. for (int i = 0; i < qdcount && resp_len < DNS_MAX_LEN - 16; i++) {
  57. // Skip question name
  58. while (*ptr != 0 && ptr < rx_buffer + len) {
  59. ptr += *ptr + 1;
  60. }
  61. ptr++; // Skip null terminator
  62. ptr += 4; // Skip QTYPE and QCLASS
  63. // Add answer: pointer to question name, type A, class IN, TTL, IP
  64. uint8_t *ans = tx_buffer + resp_len;
  65. ans[0] = 0xC0; // Pointer to offset 12 (question name)
  66. ans[1] = 0x0C;
  67. ans[2] = 0x00; // Type A
  68. ans[3] = 0x01;
  69. ans[4] = 0x00; // Class IN
  70. ans[5] = 0x01;
  71. ans[6] = 0x00; // TTL (60 seconds)
  72. ans[7] = 0x00;
  73. ans[8] = 0x00;
  74. ans[9] = 0x3C;
  75. ans[10] = 0x00; // RDLENGTH (4 bytes for IPv4)
  76. ans[11] = 0x04;
  77. // IP address (already in network byte order)
  78. memcpy(&ans[12], &s_redirect_ip, 4);
  79. resp_len += 16;
  80. }
  81. sendto(s_dns_socket, tx_buffer, resp_len, 0,
  82. (struct sockaddr *)&client_addr, addr_len);
  83. }
  84. ESP_LOGI(TAG, "DNS server task exiting");
  85. vTaskDelete(NULL);
  86. }
  87. esp_err_t dns_server_start(uint32_t redirect_ip) {
  88. if (s_dns_socket >= 0) {
  89. ESP_LOGW(TAG, "DNS server already running");
  90. return ESP_OK;
  91. }
  92. s_redirect_ip = redirect_ip;
  93. s_dns_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  94. if (s_dns_socket < 0) {
  95. ESP_LOGE(TAG, "Failed to create socket: %d", errno);
  96. return ESP_FAIL;
  97. }
  98. // Set socket timeout
  99. struct timeval timeout = {.tv_sec = 1, .tv_usec = 0};
  100. setsockopt(s_dns_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
  101. // Allow address reuse
  102. int opt = 1;
  103. setsockopt(s_dns_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  104. struct sockaddr_in server_addr = {
  105. .sin_family = AF_INET,
  106. .sin_port = htons(DNS_PORT),
  107. .sin_addr.s_addr = htonl(INADDR_ANY),
  108. };
  109. if (bind(s_dns_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) <
  110. 0) {
  111. ESP_LOGE(TAG, "Failed to bind socket: %d", errno);
  112. close(s_dns_socket);
  113. s_dns_socket = -1;
  114. return ESP_FAIL;
  115. }
  116. task_create_spiram(dns_server_task, "dns_server", 4096, NULL, 5, &s_dns_task,
  117. NULL);
  118. ESP_LOGI(TAG, "DNS server started, redirecting to " IPSTR,
  119. IP2STR((esp_ip4_addr_t *)&redirect_ip));
  120. return ESP_OK;
  121. }
  122. void dns_server_stop(void) {
  123. if (s_dns_socket >= 0) {
  124. close(s_dns_socket);
  125. s_dns_socket = -1;
  126. }
  127. if (s_dns_task) {
  128. // Task will exit on socket close
  129. s_dns_task = NULL;
  130. }
  131. ESP_LOGI(TAG, "DNS server stopped");
  132. }