mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
dns: resolve host names
A small resolver for IPv4 address records, so that clients such as NTP can be given a host name: "dns server <ip> [<ip>]", "dns lookup <name>" and "dns". Without a configured server it uses the one DHCP handed out. A query goes to the servers in turn every two seconds and gives up after six tries; answers with compressed names and CNAME records ahead of the address are understood. A name that already is a dotted address is taken without a query. The resolver sits in BANK3, the command line in BANK2 next to the helpers it uses. The System page shows and sets the servers.
This commit is contained in:
1 parent
13b75a73c9
commit
67b8c718fb
11 files changed
+372
-3
No files matched your search
@@ -69,6 +69,8 @@ SRCS = \
|
||||
rtlplayground.c \
|
||||
boot.c \
|
||||
sfp.c \
|
||||
dns.c \
|
||||
dns_cli.c \
|
||||
syslog.c \
|
||||
udp_apps.c
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "sfp.h"
|
||||
#include "dhcp.h"
|
||||
#include "syslog.h"
|
||||
#include "dns.h"
|
||||
#include "uip/uip.h"
|
||||
#include "version.h"
|
||||
|
||||
@@ -1802,6 +1803,8 @@ void cmd_parser(void) __banked
|
||||
parse_mtu();
|
||||
} else if (cmd_compare(0, "syslog")) {
|
||||
parse_syslog();
|
||||
} else if (cmd_compare(0, "dns")) {
|
||||
dns_parse();
|
||||
} else if (cmd_compare(0, "ip")) {
|
||||
if (cmd_compare(1, "dhcp")) {
|
||||
dhcp_start();
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* DNS resolver for the RTL837x platform
|
||||
* This code is in the Public Domain
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "cmd_parser.h"
|
||||
#include "uip/uip.h"
|
||||
#include "dhcp.h"
|
||||
#include "dns.h"
|
||||
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
#define DNS_PORT 53
|
||||
#define DNS_TRIES 6
|
||||
#define DNS_TIMEOUT (2 * SYS_TICK_HZ)
|
||||
|
||||
extern __xdata struct dhcp_state dhcp_state;
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
|
||||
__xdata struct dns_state dns_state;
|
||||
__xdata uip_ipaddr_t dns_ip;
|
||||
uint8_t * __xdata dns_cand[3];
|
||||
|
||||
|
||||
static uint8_t dns_used(__xdata uint8_t *a) __reentrant
|
||||
{
|
||||
return a[0] | a[1] | a[2] | a[3];
|
||||
}
|
||||
|
||||
|
||||
static uint8_t dns_name_is_ip(void) __reentrant
|
||||
{
|
||||
__xdata char *s = dns_state.name;
|
||||
uint8_t i, n;
|
||||
uint16_t v;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
v = 0;
|
||||
n = 0;
|
||||
while (*s >= '0' && *s <= '9') {
|
||||
v = v * 10 + (*s++ - '0');
|
||||
if (++n > 3 || v > 255)
|
||||
return 0;
|
||||
}
|
||||
if (!n)
|
||||
return 0;
|
||||
dns_state.addr[i] = v;
|
||||
if (i < 3 && *s++ != '.')
|
||||
return 0;
|
||||
}
|
||||
return !*s;
|
||||
}
|
||||
|
||||
|
||||
static void dns_next(void) __reentrant
|
||||
{
|
||||
uint8_t k = 0;
|
||||
|
||||
if (dns_state.conn) {
|
||||
uip_udp_remove(dns_state.conn);
|
||||
dns_state.conn = 0;
|
||||
}
|
||||
if (dns_used(dns_state.server[0]))
|
||||
dns_cand[k++] = dns_state.server[0];
|
||||
if (dns_used(dns_state.server[1]))
|
||||
dns_cand[k++] = dns_state.server[1];
|
||||
if (dns_used(dhcp_state.dns))
|
||||
dns_cand[k++] = dhcp_state.dns;
|
||||
if (!k || dns_state.tries >= DNS_TRIES) {
|
||||
dns_state.status = DNS_FAILED;
|
||||
if (dns_state.verbose)
|
||||
print_string(k ? "DNS: no answer\n" : "DNS: no server\n");
|
||||
return;
|
||||
}
|
||||
k = dns_state.tries % k;
|
||||
uip_ipaddr(dns_ip, dns_cand[k][0], dns_cand[k][1], dns_cand[k][2], dns_cand[k][3]);
|
||||
dns_state.conn = uip_udp_new(&dns_ip, HTONS(DNS_PORT));
|
||||
if (!dns_state.conn) {
|
||||
dns_state.status = DNS_FAILED;
|
||||
print_string("DNS: no free UDP connection\n");
|
||||
return;
|
||||
}
|
||||
dns_state.send = 1;
|
||||
}
|
||||
|
||||
|
||||
static void dns_query(void) __reentrant
|
||||
{
|
||||
__xdata uint8_t *p = (__xdata uint8_t *)uip_appdata;
|
||||
__xdata char *n = dns_state.name;
|
||||
__xdata uint8_t *label;
|
||||
uint16_t len = 12;
|
||||
|
||||
dns_state.id++;
|
||||
p[0] = dns_state.id >> 8;
|
||||
p[1] = dns_state.id;
|
||||
p[2] = 0x01;
|
||||
p[3] = 0x00;
|
||||
p[4] = 0;
|
||||
p[5] = 1;
|
||||
p[6] = p[7] = p[8] = p[9] = p[10] = p[11] = 0;
|
||||
while (*n) {
|
||||
label = p + len++;
|
||||
*label = 0;
|
||||
while (*n && *n != '.') {
|
||||
p[len++] = *n++;
|
||||
(*label)++;
|
||||
}
|
||||
if (*n)
|
||||
n++;
|
||||
}
|
||||
p[len++] = 0;
|
||||
p[len++] = 0;
|
||||
p[len++] = 1;
|
||||
p[len++] = 0;
|
||||
p[len++] = 1;
|
||||
uip_udp_send(len);
|
||||
}
|
||||
|
||||
|
||||
static uint16_t dns_skip_name(__xdata uint8_t *p, uint16_t i, uint16_t len) __reentrant
|
||||
{
|
||||
while (i < len) {
|
||||
if (!p[i])
|
||||
return i + 1;
|
||||
if ((p[i] & 0xc0) == 0xc0)
|
||||
return i + 2;
|
||||
i += p[i] + 1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void dns_answer(void) __reentrant
|
||||
{
|
||||
__xdata uint8_t *p = (__xdata uint8_t *)uip_appdata;
|
||||
uint16_t len = uip_datalen();
|
||||
uint16_t i, an;
|
||||
|
||||
if (dns_state.status != DNS_PENDING || len < 12 || !(p[2] & 0x80)
|
||||
|| p[0] != (uint8_t)(dns_state.id >> 8) || p[1] != (uint8_t)dns_state.id)
|
||||
return;
|
||||
an = ((uint16_t)p[6] << 8) | p[7];
|
||||
i = dns_skip_name(p, 12, len) + 4;
|
||||
while (!(p[3] & 0x0f) && an-- && i + 10 <= len) {
|
||||
i = dns_skip_name(p, i, len);
|
||||
if (i + 10 > len)
|
||||
break;
|
||||
if (!p[i] && p[i + 1] == 1 && !p[i + 8] && p[i + 9] == 4 && i + 14 <= len) {
|
||||
memcpy(dns_state.addr, p + i + 10, 4);
|
||||
dns_state.status = DNS_DONE;
|
||||
uip_udp_remove(dns_state.conn);
|
||||
dns_state.conn = 0;
|
||||
if (dns_state.verbose) {
|
||||
print_string("DNS: ");
|
||||
print_string_x(dns_state.name);
|
||||
print_string(" is ");
|
||||
print_ip(dns_state.addr);
|
||||
write_char('\n');
|
||||
}
|
||||
return;
|
||||
}
|
||||
i += 10 + (((uint16_t)p[i + 8] << 8) | p[i + 9]);
|
||||
}
|
||||
dns_state.tries = DNS_TRIES;
|
||||
dns_next();
|
||||
}
|
||||
|
||||
|
||||
void dns_init(void) __banked
|
||||
{
|
||||
memset(dns_state.server, 0, sizeof(dns_state.server));
|
||||
dns_state.name[0] = 0;
|
||||
dns_state.status = DNS_IDLE;
|
||||
dns_state.conn = 0;
|
||||
}
|
||||
|
||||
|
||||
void dns_lookup(void) __banked
|
||||
{
|
||||
if (dns_name_is_ip()) {
|
||||
dns_state.status = DNS_DONE;
|
||||
return;
|
||||
}
|
||||
dns_state.tries = 0;
|
||||
dns_state.status = DNS_PENDING;
|
||||
dns_next();
|
||||
}
|
||||
|
||||
|
||||
void dns_show(void) __banked
|
||||
{
|
||||
print_string("DNS servers ");
|
||||
print_ip(dns_state.server[0]);
|
||||
write_char(' ');
|
||||
print_ip(dns_state.server[1]);
|
||||
print_string(", from DHCP ");
|
||||
print_ip(dhcp_state.dns);
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
|
||||
void dns_callback(uint16_t lport) __banked __reentrant
|
||||
{
|
||||
if (!dns_state.conn || lport != dns_state.conn->lport)
|
||||
return;
|
||||
if (uip_newdata()) {
|
||||
dns_answer();
|
||||
return;
|
||||
}
|
||||
if (dns_state.status != DNS_PENDING)
|
||||
return;
|
||||
if (dns_state.send) {
|
||||
dns_state.send = 0;
|
||||
dns_state.sent = ticks;
|
||||
dns_query();
|
||||
return;
|
||||
}
|
||||
if (ticks - dns_state.sent >= DNS_TIMEOUT) {
|
||||
dns_state.tries++;
|
||||
dns_next();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _DNS_H_
|
||||
#define _DNS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DNS_NAME_LEN 48
|
||||
|
||||
#define DNS_IDLE 0
|
||||
#define DNS_PENDING 1
|
||||
#define DNS_DONE 2
|
||||
#define DNS_FAILED 3
|
||||
|
||||
struct uip_udp_conn;
|
||||
|
||||
struct dns_state {
|
||||
uint8_t server[2][4]; /* configured servers, 0.0.0.0 = unused */
|
||||
char name[DNS_NAME_LEN]; /* name of the current or last lookup */
|
||||
uint8_t addr[4]; /* address found by the last lookup */
|
||||
uint8_t status; /* DNS_* */
|
||||
uint8_t verbose; /* print the result of the lookup */
|
||||
uint8_t tries; /* queries sent for the current lookup */
|
||||
uint8_t send; /* a query is due on the connection */
|
||||
uint16_t id;
|
||||
uint32_t sent; /* ticks when the last query went out */
|
||||
struct uip_udp_conn *conn;
|
||||
};
|
||||
|
||||
extern __xdata struct dns_state dns_state;
|
||||
|
||||
void dns_init(void) __banked;
|
||||
void dns_lookup(void) __banked;
|
||||
void dns_show(void) __banked;
|
||||
void dns_callback(uint16_t lport) __banked __reentrant;
|
||||
void dns_parse(void) __banked __reentrant;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Command line interface of the DNS resolver for the RTL837x platform
|
||||
* This code is in the Public Domain
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "cmd_parser.h"
|
||||
#include "dns.h"
|
||||
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||
extern __xdata uint8_t cmd_words_len;
|
||||
extern __xdata uint8_t cmd_words_b[15];
|
||||
extern __xdata uint8_t ip[4];
|
||||
uint8_t cmd_compare(uint8_t start, __code const uint8_t * cmd);
|
||||
uint8_t parse_ip(uint8_t idx);
|
||||
|
||||
|
||||
void dns_parse(void) __banked __reentrant
|
||||
{
|
||||
__xdata uint8_t *s;
|
||||
uint8_t n;
|
||||
|
||||
if (cmd_words_len < 2) {
|
||||
dns_show();
|
||||
return;
|
||||
}
|
||||
if (cmd_compare(1, "server") && cmd_words_len >= 3 && parse_ip(cmd_words_b[2])) {
|
||||
memcpy(dns_state.server[0], ip, 4);
|
||||
memset(dns_state.server[1], 0, 4);
|
||||
if (cmd_words_len >= 4) {
|
||||
if (!parse_ip(cmd_words_b[3]))
|
||||
goto err;
|
||||
memcpy(dns_state.server[1], ip, 4);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cmd_compare(1, "lookup") && cmd_words_len >= 3) {
|
||||
if (dns_state.status == DNS_PENDING) {
|
||||
print_string("DNS: a lookup is already running\n");
|
||||
return;
|
||||
}
|
||||
s = &cmd_buffer[cmd_words_b[2]];
|
||||
for (n = 0; s[n] && s[n] != ' '; n++) {
|
||||
if (n == DNS_NAME_LEN - 1)
|
||||
goto err;
|
||||
dns_state.name[n] = s[n];
|
||||
}
|
||||
dns_state.name[n] = 0;
|
||||
dns_state.verbose = 1;
|
||||
dns_lookup();
|
||||
if (dns_state.status == DNS_DONE) {
|
||||
print_ip(dns_state.addr);
|
||||
write_char('\n');
|
||||
}
|
||||
return;
|
||||
}
|
||||
err:
|
||||
print_string("Error: dns [server <ip> [<ip>]|lookup <name>]\n");
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# DNS
|
||||
|
||||
The switch can resolve host names to IPv4 addresses, for the NTP client and
|
||||
for anything else that is given a name instead of an address.
|
||||
|
||||
```
|
||||
dns server <ip> [<ip>] # one or two servers, 0.0.0.0 removes them
|
||||
dns lookup <name> # resolve a name and print the address
|
||||
dns # show the servers
|
||||
```
|
||||
|
||||
Without a configured server the resolver uses the one handed out by DHCP.
|
||||
Only address records are looked up; a query goes to the servers in turn,
|
||||
every two seconds, and gives up after six tries. A name that already is a
|
||||
dotted address is taken as it is, without a query.
|
||||
|
||||
The DNS servers are set in the Network card of the System page as well.
|
||||
Settings made there or on the console are kept only once the configuration is
|
||||
saved.
|
||||
+16
-3
@@ -83,7 +83,7 @@ sy_ip_err:"Invalid IP / netmask / gateway",sy_host_err:"Hostname: 1-23 printable
|
||||
sy_net_q:"Apply network settings?",sy_net_d:"The management IP changes to {ip}: this page will need to be reopened there.",
|
||||
sy_ip_changed:"IP changed, reconnect at http://{ip}/",sy_dhcp_q:"Switch to DHCP?",
|
||||
sy_dhcp_d:"The switch requests an address via DHCP. You must find its new IP to reconnect.",
|
||||
sy_sysip_err:"Invalid syslog server IP",sy_sysport_err:"Syslog port must be 1-65535",
|
||||
sy_sysip_err:"Invalid syslog server IP",sy_dns1:"DNS server",sy_dns2:"Second DNS",sy_dns_err:"Invalid DNS server IP",sy_dns_dhcp:"from DHCP: {ip}",sy_sysport_err:"Syslog port must be 1-65535",
|
||||
sy_pw_len:"Password: 1-20 characters",sy_pw_space:"Password cannot contain spaces",sy_pw_match:"Passwords do not match",
|
||||
sy_pw_q:"Change admin password?",sy_pw_d:"Takes effect immediately for new logins. Save to flash to persist.",
|
||||
sy_reboot_q:"Reboot the switch?",sy_reboot_d:"There are UNSAVED changes and they will be lost. Save to flash first if you want to keep them.",
|
||||
@@ -658,6 +658,7 @@ var CONF_CMDS=[
|
||||
/^gw\s+(\d{1,3}\.){3}\d{1,3}$/,/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||
/^syslog\s+(on|off)$/,/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,/^syslog\s+port\s+\d{1,5}$/,
|
||||
/^session\s+\d{1,5}$/,
|
||||
/^dns\s+server\s+(\d{1,3}\.){3}\d{1,3}(\s+(\d{1,3}\.){3}\d{1,3})?$/,
|
||||
/^passwd\s+\S+$/,/^hostname\s+\S{1,23}$/,
|
||||
/^vlan\s+\d{1,4}\s+d$/,/^vlan\s+\d{1,4}\s+mgmt$/,
|
||||
/^vlan\s+\d{1,4}(\s+[a-zA-Z]\w*)?(\s+\d{1,2}t?)+$/,
|
||||
@@ -1744,6 +1745,16 @@ function sysLoad(){
|
||||
if(S.info.session_timeout)$("sy-sesstmo").value=S.info.session_timeout;
|
||||
}).catch(function(){});
|
||||
cfgReload();
|
||||
dnsLoad();
|
||||
}
|
||||
function dnsLoad(){
|
||||
return api("/cmd",{method:"POST",body:"dns"}).then(function(r){
|
||||
var m=r.body.match(/DNS servers ([\d.]+) ([\d.]+), from DHCP ([\d.]+)/);
|
||||
if(!m)return;
|
||||
function v(x){return x==="0.0.0.0"?"":x}
|
||||
$("sy-dns1").value=v(m[1]);$("sy-dns2").value=v(m[2]);
|
||||
$("sy-dnsdhcp").textContent=m[3]==="0.0.0.0"?"":t("sy_dns_dhcp",{ip:m[3]});
|
||||
}).catch(function(){});
|
||||
}
|
||||
function cfgParseKnown(txt){
|
||||
var igmp=false,syslog=false;
|
||||
@@ -1760,13 +1771,15 @@ function cfgParseKnown(txt){
|
||||
$("sy-apply").addEventListener("click",function(){
|
||||
var ip=$("sy-ip").value.trim(),mask=$("sy-mask").value.trim(),gw=$("sy-gw").value.trim();
|
||||
if(!okIp(ip)||!okIp(mask)||!okIp(gw)){toast(t("sy_ip_err"),"err");return;}
|
||||
var d1=$("sy-dns1").value.trim(),d2=$("sy-dns2").value.trim();
|
||||
if((d1&&!okIp(d1))||(d2&&!okIp(d2))){toast(t("sy_dns_err"),"err");return;}
|
||||
var cmds=[];
|
||||
var hn=$("sy-host").value.trim();
|
||||
if(hn&&hn!==S.info.hostname){
|
||||
if(!/^[\x21-\x7e]{1,23}$/.test(hn)||/["\\]/.test(hn)){toast(t("sy_host_err"),"err");return;}
|
||||
cmds.push("hostname "+hn);
|
||||
}
|
||||
cmds.push("ip "+ip+"\nnetmask "+mask+"\ngw "+gw);
|
||||
cmds.push("ip "+ip+"\nnetmask "+mask+"\ngw "+gw+"\ndns server "+(d1||"0.0.0.0")+(d2?" "+d2:""));
|
||||
var changingIp=ip!==S.info.ip_address;
|
||||
confirmModal(t("sy_net_q"),changingIp?t("sy_net_d",{ip:ip}):"",function(){
|
||||
postCmds(cmds).then(function(){
|
||||
@@ -1862,7 +1875,7 @@ tabHooks.system={enter:sysLoad};
|
||||
|
||||
var CONF_OVERWRITE=[
|
||||
/^ip\b/,/^gw\b/,/^netmask\b/,/^hostname\b/,
|
||||
/^syslog\s+ip\b/,/^syslog\s+port\b/,/^passwd\b/,/^session\b/,
|
||||
/^syslog\s+ip\b/,/^syslog\s+port\b/,/^dns\s+server\b/,/^passwd\b/,/^session\b/,
|
||||
/^vlan\s+\d{1,4}\s+mgmt$/,/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
|
||||
/^pvid\s+\d{1,2}\b/,
|
||||
/^port\s+\d{1,2}(?!\s+name\b)/,/^port\s+\d{1,2}\s+name\b/,
|
||||
|
||||
@@ -360,6 +360,9 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
||||
<label class="row"><span class="lb" data-i18n="i_ip">IP address</span><input class="in" id="sy-ip" size="15"></label>
|
||||
<label class="row"><span class="lb" data-i18n="i_mask">Netmask</span><input class="in" id="sy-mask" size="15"></label>
|
||||
<label class="row"><span class="lb" data-i18n="i_gw">Gateway</span><input class="in" id="sy-gw" size="15"></label>
|
||||
<label class="row"><span class="lb" data-i18n="sy_dns1">DNS server</span><input class="in" id="sy-dns1" size="15"></label>
|
||||
<label class="row"><span class="lb" data-i18n="sy_dns2">Second DNS</span><input class="in" id="sy-dns2" size="15"></label>
|
||||
<p class="small mut" id="sy-dnsdhcp"></p>
|
||||
<div style="display:flex;gap:10px;margin-top:12px">
|
||||
<button class="ctl pri" id="sy-apply" data-i18n="c_apply">Apply</button>
|
||||
<button class="ctl" id="sy-dhcp" data-i18n="sy_dhcp" data-i18n-t="sy_dhcp_t">Use DHCP</button>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "machine.h"
|
||||
#include "phy.h"
|
||||
#include "syslog.h"
|
||||
#include "dns.h"
|
||||
#include "httpd/page_impl.h"
|
||||
#include "boot.h"
|
||||
#include "sfp.h"
|
||||
@@ -1756,6 +1757,7 @@ void main(void)
|
||||
check_and_flash_update_image();
|
||||
|
||||
syslog_init();
|
||||
dns_init();
|
||||
|
||||
#ifdef DEBUG
|
||||
// This register seems to work on the RTL8373 only if also the SDS
|
||||
|
||||
@@ -6,4 +6,5 @@ void udp_callbacks(void)
|
||||
{
|
||||
dhcp_callback(uip_udp_conn->lport); // let the application decide if this is for it or not
|
||||
syslog_callback(uip_udp_conn->lport); // let the application decide if this is for it or not
|
||||
dns_callback(uip_udp_conn->lport);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "dhcp.h"
|
||||
#include "syslog.h"
|
||||
#include "dns.h"
|
||||
|
||||
void udp_callbacks(void);
|
||||
|
||||
|
||||
Reference in new issue
Block a user