12#if PC_ENABLE_DNS_SERVER
22bool ci_eq(
const char *a,
const char *b)
28 if (ca >=
'A' && ca <=
'Z')
32 if (cb >=
'A' && cb <=
'Z')
48bool parse_question(
const uint8_t *q,
size_t qlen,
char *name,
size_t name_cap, uint16_t *qtype,
size_t *qend)
79 if (n + 1 >= name_cap)
85 for (uint8_t k = 0; k < len; k++)
87 if (n + 1 >= name_cap)
91 name[n++] = (char)q[i++];
99 *qtype = (uint16_t)((q[i] << 8) | q[i + 1]);
108 if (!query || !out || !resolve || qlen < 12)
114 uint8_t opcode = (uint8_t)((query[2] >> 3) & 0xF);
121 memcpy(out, query, 12);
122 out[2] = (uint8_t)(0x84 | (query[2] & 0x01));
125 out[8] = out[9] = out[10] = out[11] = 0;
132 if (!parse_question(query, qlen, name,
sizeof(name), &qtype, &qend))
141 memcpy(out, query, qend);
142 out[2] = (uint8_t)(0x84 | (query[2] & 0x01));
146 out[8] = out[9] = out[10] = out[11] = 0;
148 uint32_t ip = (qtype == 1) ? resolve(name) : 0;
153 out[3] = (qtype == 1) ? 0x03 : 0;
157 if (qend + 16 > out_cap)
170 out[n++] = (uint8_t)(ttl >> 24);
171 out[n++] = (uint8_t)(ttl >> 16);
172 out[n++] = (uint8_t)(ttl >> 8);
173 out[n++] = (uint8_t)ttl;
176 out[n++] = (uint8_t)(ip >> 24);
177 out[n++] = (uint8_t)(ip >> 16);
178 out[n++] = (uint8_t)(ip >> 8);
179 out[n++] = (uint8_t)ip;
200bool pc_dns_server_add(
const char *name, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
202 if (!name || !name[0])
215 memcpy(s_dns.names[s_dns.count], name, nlen + 1);
216 s_dns.ips[s_dns.count] = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d;
227 for (
size_t i = 0; i < s_dns.count; i++)
229 if (ci_eq(s_dns.names[i], name))
246void pc_dns_server_udp_handler(
const uint8_t *data,
size_t len,
const struct pc_udp_peer *peer,
void *ctx)
260 return pc_udp_listen(53, pc_dns_server_udp_handler,
nullptr);
Authoritative DNS server (UDP/53) - resolve local names on an offline LAN.
size_t pc_dns_server_build_response(const uint8_t *query, size_t qlen, uint32_t ttl, DnsResolveFn resolve, uint8_t *out, size_t out_cap)
Build a DNS reply to query. Pure - no clock, no I/O.
bool pc_dns_server_begin()
Start answering DNS queries on UDP/53 from the built-in table.
bool pc_dns_server_add(const char *name, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
Add an A record to the built-in table (case-insensitive name).
uint32_t(* DnsResolveFn)(const char *name)
Resolve a queried name to an IPv4 address.
void pc_dns_server_clear()
Remove every record from the built-in table.
uint32_t pc_dns_server_lookup(const char *name)
Look name up in the built-in table.
User-facing configuration for ProtoCore.
#define PC_DNS_SERVER_TTL
TTL (seconds) the DNS server puts on its answers.
#define PC_DNS_NAME_MAX
Max length of a queried/stored DNS name (bytes, incl NUL).
#define PC_DNS_SERVER_MAX_RECORDS
Max A records in the DNS server's fixed table.
bool pc_udp_listen(uint16_t port, pc_udp_handler handler, void *ctx)
Bind a UDP port and route incoming datagrams to handler.
bool pc_udp_send(const struct pc_udp_peer *peer, const uint8_t *data, size_t len)
Send a datagram back to the peer captured during the handler call.
Layer 4 (Transport) - connectionless UDP datagram service.