2#if defined(USE_ESP32) && (defined(USE_CAPTIVE_PORTAL) || defined(USE_WEBSERVER_CAPTIVE))
7#include <lwip/sockets.h>
15static constexpr uint16_t DNS_PORT = 53;
16static constexpr uint16_t DNS_QR_FLAG = 1 << 15;
17static constexpr uint16_t DNS_AA_FLAG = 1 << 10;
18static constexpr uint16_t DNS_OPCODE_MASK = 0x7800;
19static constexpr uint16_t DNS_QTYPE_A = 0x0001;
20static constexpr uint16_t DNS_QCLASS_IN = 0x0001;
21static constexpr uint16_t DNS_ANSWER_TTL = 300;
51#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
52 char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
53 ESP_LOGV(TAG,
"Starting DNS server on %s", ip.
str_to(ip_buf));
59 ESP_LOGE(TAG,
"Socket create failed");
73 ESP_LOGE(TAG,
"Bind failed: %d", errno);
77 ESP_LOGV(TAG,
"Bound to port %d", DNS_PORT);
83 ESP_LOGV(TAG,
"Stopped");
92 socklen_t client_addr_len =
sizeof(client_addr);
104 const int err = errno;
105 if (err != EAGAIN && err != EWOULDBLOCK && err != EINTR) {
106 ESP_LOGE(TAG,
"recvfrom failed: %d", err);
111 ESP_LOGVV(TAG,
"Received %d bytes from %s:%d",
len, inet_ntoa(client_addr.
sin_addr), ntohs(client_addr.
sin_port));
113 if (
len <
static_cast<ssize_t>(
sizeof(DNSHeader) + 1)) {
114 ESP_LOGV(TAG,
"Request too short: %d",
len);
119 DNSHeader *header = (DNSHeader *) this->
buffer_;
120 uint16_t
flags = ntohs(header->flags);
121 uint16_t
qd_count = ntohs(header->qd_count);
125 ESP_LOGV(TAG,
"Not a standard query: flags=0x%04X, qd_count=%d",
flags,
qd_count);
130 uint8_t *ptr = this->
buffer_ +
sizeof(DNSHeader);
133 while (ptr <
end && *ptr != 0) {
134 uint8_t label_len = *ptr;
135 if (label_len > 63) {
139 if (ptr + label_len + 1 >
end) {
142 ptr += label_len + 1;
146 if (ptr >=
end || *ptr != 0) {
152 if (ptr +
sizeof(DNSQuestion) >
end) {
157 DNSQuestion *question = (DNSQuestion *) ptr;
158 uint16_t qtype = ntohs(question->type);
159 uint16_t qclass = ntohs(question->dns_class);
162 if (qtype != DNS_QTYPE_A || qclass != DNS_QCLASS_IN) {
163 ESP_LOGV(TAG,
"Not an A query: type=0x%04X, class=0x%04X", qtype, qclass);
168 header->flags = htons(DNS_QR_FLAG | DNS_AA_FLAG);
169 header->an_count = htons(1);
172 size_t question_len = (ptr +
sizeof(DNSQuestion)) - this->
buffer_ -
sizeof(DNSHeader);
173 size_t answer_offset =
sizeof(DNSHeader) + question_len;
176 if (answer_offset +
sizeof(DNSAnswer) >
sizeof(this->
buffer_)) {
177 ESP_LOGW(TAG,
"Response too large");
181 DNSAnswer *answer = (DNSAnswer *) (this->
buffer_ + answer_offset);
184 answer->ptr_offset = htons(0xC000 |
sizeof(DNSHeader));
185 answer->type = htons(DNS_QTYPE_A);
186 answer->dns_class = htons(DNS_QCLASS_IN);
187 answer->ttl = htonl(DNS_ANSWER_TTL);
188 answer->addr_len = htons(4);
192 answer->ip_addr = addr.addr;
194 size_t response_len = answer_offset +
sizeof(DNSAnswer);
200 ESP_LOGV(TAG,
"Send failed: %d", errno);
202 ESP_LOGV(TAG,
"Sent %d bytes", sent);
bool ready() const
Check if the socket has buffered data ready to read.
int bind(const struct sockaddr *addr, socklen_t addrlen)
ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
int setsockopt(int level, int optname, const void *optval, socklen_t optlen)
network::IPAddress server_ip_
uint8_t buffer_[DNS_BUFFER_SIZE]
socket::ListenSocket * socket_
void process_next_request()
bool start(const network::IPAddress &ip)
Returns false when the socket could not be created or bound.
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
struct in_addr ip4_addr_t
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address and specified port for the IP version used by socket_ip().
std::unique_ptr< ListenSocket > socket_ip_loop_monitored(int type, int protocol)
ESPHOME_LOG_TAG(TAG, "web_server_base.dns")
char * str_to(char *buf) const