-
Notifications
You must be signed in to change notification settings - Fork 114
Expand file tree
/
Copy pathdns_server.cc
More file actions
112 lines (93 loc) · 2.96 KB
/
Copy pathdns_server.cc
File metadata and controls
112 lines (93 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "dns_server.h"
#include <esp_log.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#define TAG "DnsServer"
DnsServer::DnsServer() {
}
DnsServer::~DnsServer() {
Stop();
}
void DnsServer::Start(esp_ip4_addr_t gateway) {
// If already running, stop first
if (running_) {
Stop();
}
ESP_LOGI(TAG, "Starting DNS server");
gateway_ = gateway;
fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd_ < 0) {
ESP_LOGE(TAG, "Failed to create socket");
return;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port_);
if (bind(fd_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
ESP_LOGE(TAG, "failed to bind port %d", port_);
close(fd_);
fd_ = -1;
return;
}
running_ = true;
xTaskCreate([](void* arg) {
DnsServer* dns_server = static_cast<DnsServer*>(arg);
dns_server->Run();
vTaskDelete(NULL);
}, "DnsServerTask", 4096, this, 5, &task_handle_);
}
void DnsServer::Stop() {
if (!running_) {
return;
}
ESP_LOGI(TAG, "Stopping DNS server");
running_ = false;
// Close socket to unblock recvfrom
if (fd_ >= 0) {
shutdown(fd_, SHUT_RDWR);
close(fd_);
fd_ = -1;
}
// Wait for task to finish
if (task_handle_ != nullptr) {
// Give the task some time to exit gracefully
vTaskDelay(pdMS_TO_TICKS(100));
task_handle_ = nullptr;
}
}
void DnsServer::Run() {
char buffer[512];
while (running_) {
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int len = recvfrom(fd_, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_addr_len);
if (len < 0) {
if (!running_) {
// Socket was closed during Stop(), exit gracefully
break;
}
ESP_LOGE(TAG, "recvfrom failed, errno=%d", errno);
continue;
}
if (!running_) {
break;
}
// Simple DNS response: point all queries to 192.168.4.1
buffer[2] |= 0x80; // Set response flag
buffer[3] |= 0x80; // Set Recursion Available
buffer[7] = 1; // Set answer count to 1
// Add answer section
memcpy(&buffer[len], "\xc0\x0c", 2); // Name pointer
len += 2;
memcpy(&buffer[len], "\x00\x01\x00\x01\x00\x00\x00\x1c\x00\x04", 10); // Type, class, TTL, data length
len += 10;
memcpy(&buffer[len], &gateway_.addr, 4); // 192.168.4.1
len += 4;
ESP_LOGI(TAG, "Sending DNS response to %s", inet_ntoa(gateway_.addr));
sendto(fd_, buffer, len, 0, (struct sockaddr *)&client_addr, client_addr_len);
}
task_handle_ = nullptr;
ESP_LOGI(TAG, "DNS server task exiting");
}