+ add technical document
This commit is contained in:
parent
1ac9419c94
commit
bc81a0ecff
|
@ -0,0 +1,327 @@
|
|||
# AdGuard Home Technical Document
|
||||
|
||||
The document describes technical details and internal algorithms of AdGuard Home.
|
||||
|
||||
Contents:
|
||||
* First startup
|
||||
* Installation wizard
|
||||
* "Get install settings" command
|
||||
* "Check configuration" command
|
||||
* Disable DNSStubListener
|
||||
* "Apply configuration" command
|
||||
* Enable DHCP server
|
||||
* "Check DHCP" command
|
||||
* "Enable DHCP" command
|
||||
* Static IP check/set
|
||||
|
||||
|
||||
## First startup
|
||||
|
||||
The first application startup is detected when there's no .yaml configuration file.
|
||||
|
||||
We check if the user is root, otherwise we fail with an error.
|
||||
|
||||
Web server is started up on port 3000 and automatically redirects requests to `/` to Installation wizard.
|
||||
|
||||
After Installation wizard steps are completed, we write configuration to a file and start normal operation.
|
||||
|
||||
|
||||
## Installation wizard
|
||||
|
||||
This is the collection of UI screens that are shown to a user on first application startup.
|
||||
|
||||
The screens are:
|
||||
|
||||
1. Welcome
|
||||
2. Set up network interface and listening ports for Web and DNS servers
|
||||
3. Set up administrator username and password
|
||||
4. Configuration complete
|
||||
5. Done
|
||||
|
||||
Algorithm:
|
||||
|
||||
Screen 2:
|
||||
* UI asks server for initial information and shows it
|
||||
* User edits the default settings, clicks on "Next" button
|
||||
* UI asks server to check new settings
|
||||
* Server searches for the known issues
|
||||
* UI shows information about the known issues and the means to fix them
|
||||
* Server applies automatic fixes of the known issues on command from UI
|
||||
|
||||
Screen 3:
|
||||
* UI asks server to apply the configuration
|
||||
* Server restarts DNS server
|
||||
|
||||
|
||||
### "Get install settings" command
|
||||
|
||||
Request:
|
||||
|
||||
GET /control/install/get_addresses
|
||||
|
||||
Response:
|
||||
|
||||
200 OK
|
||||
|
||||
{
|
||||
"web_port":80,
|
||||
"dns_port":53,
|
||||
"interfaces":{
|
||||
"enp2s0":{"name":"enp2s0","mtu":1500,"hardware_address":"","ip_addresses":["",""],"flags":"up|broadcast|multicast"},
|
||||
"lo":{"name":"lo","mtu":65536,"hardware_address":"","ip_addresses":["127.0.0.1","::1"],"flags":"up|loopback"},
|
||||
}
|
||||
}
|
||||
|
||||
If `interfaces.flags` doesn't contain `up` flag, UI must show `(Down)` status next to its IP address in interfaces selector.
|
||||
|
||||
|
||||
### "Check configuration" command
|
||||
|
||||
Request:
|
||||
|
||||
POST /control/install/check_config
|
||||
|
||||
{
|
||||
"web":{"port":80,"ip":"192.168.11.33"},
|
||||
"dns":{"port":53,"ip":"127.0.0.1","autofix":false},
|
||||
}
|
||||
|
||||
Server should check whether a port is available only in case it itself isn't already listening on that port.
|
||||
|
||||
Server replies on success:
|
||||
|
||||
200 OK
|
||||
|
||||
{
|
||||
"web":{"status":""},
|
||||
"dns":{"status":""},
|
||||
}
|
||||
|
||||
Server replies on error:
|
||||
|
||||
200 OK
|
||||
|
||||
{
|
||||
"web":{"status":"ERROR MESSAGE"},
|
||||
"dns":{"status":"ERROR MESSAGE", "can_autofix": true|false},
|
||||
}
|
||||
|
||||
|
||||
### Disable DNSStubListener
|
||||
|
||||
On Linux, if 53 port is not available, server performs several additional checks to determine if the issue can be fixed automatically.
|
||||
|
||||
#### Phase 1
|
||||
|
||||
Request:
|
||||
|
||||
POST /control/install/check_config
|
||||
|
||||
{
|
||||
"dns":{"port":53,"ip":"127.0.0.1","autofix":false}
|
||||
}
|
||||
|
||||
Check if DNSStubListener is enabled:
|
||||
|
||||
systemctl is-enabled systemd-resolved
|
||||
|
||||
Check if DNSStubListener is active:
|
||||
|
||||
grep -E '#?DNSStubListener=yes' /etc/systemd/resolved.conf
|
||||
|
||||
If the issue can be fixed automatically, server replies with `"can_autofix":true`
|
||||
|
||||
200 OK
|
||||
|
||||
{
|
||||
"dns":{"status":"ERROR MESSAGE", "can_autofix":true},
|
||||
}
|
||||
|
||||
In this case UI shows "Fix" button next to error message.
|
||||
|
||||
#### Phase 2
|
||||
|
||||
If user clicks on "Fix" button, UI sends request to perform an automatic fix
|
||||
|
||||
POST /control/install/check_config
|
||||
|
||||
{
|
||||
"dns":{"port":53,"ip":"127.0.0.1","autofix":true},
|
||||
}
|
||||
|
||||
Deactivate (save backup as `resolved.conf.orig`) and stop DNSStubListener:
|
||||
|
||||
sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf
|
||||
systemctl reload-or-restart systemd-resolved
|
||||
|
||||
Server replies:
|
||||
|
||||
200 OK
|
||||
|
||||
{
|
||||
"dns":{"status":""},
|
||||
}
|
||||
|
||||
|
||||
### "Apply configuration" command
|
||||
|
||||
Request:
|
||||
|
||||
POST /control/install/configure
|
||||
|
||||
{
|
||||
"web":{"port":80,"ip":"192.168.11.33"},
|
||||
"dns":{"port":53,"ip":"127.0.0.1"},
|
||||
"username":"u",
|
||||
"password":"p",
|
||||
}
|
||||
|
||||
Server checks the parameters once again, restarts DNS server, replies:
|
||||
|
||||
200 OK
|
||||
|
||||
On error, server responds with code 400 or 500. In this case UI should show error message and reset to the beginning.
|
||||
|
||||
400 Bad Request
|
||||
|
||||
ERROR MESSAGE
|
||||
|
||||
|
||||
## Enable DHCP server
|
||||
|
||||
Algorithm:
|
||||
|
||||
* UI shows DHCP configuration screen with "Enabled DHCP" button disabled, and "Check DHCP" button enabled
|
||||
* User clicks on "Check DHCP"; UI sends request to server
|
||||
* Server may fail to detect whether there is another DHCP server working in the network. In this case UI shows a warning.
|
||||
* Server may detect that a dynamic IP configuration is used for this interface. In this case UI shows a warning.
|
||||
* UI enables "Enable DHCP" button
|
||||
* User clicks on "Enable DHCP"; UI sends request to server
|
||||
* Server sets a static IP (if necessary), enables DHCP server, sends the status back to UI
|
||||
* UI shows the status
|
||||
|
||||
|
||||
### "Check DHCP" command
|
||||
|
||||
Request:
|
||||
|
||||
POST /control/dhcp/find_active_dhcp
|
||||
|
||||
vboxnet0
|
||||
|
||||
Response:
|
||||
|
||||
200 OK
|
||||
|
||||
{
|
||||
"other_server": {
|
||||
"found": "yes|no|error",
|
||||
"error": "Error message", // set if found=error
|
||||
},
|
||||
"static_ip": {
|
||||
"static": "yes|no|error",
|
||||
"ip": "<Current dynamic IP address>", // set if static=no
|
||||
}
|
||||
}
|
||||
|
||||
If `other_server.found` is:
|
||||
* `no`: everything is fine - there is no other DHCP server
|
||||
* `yes`: we found another DHCP server. UI shows a warning.
|
||||
* `error`: we failed to determine whether there's another DHCP server. `other_server.error` contains error details. UI shows a warning.
|
||||
|
||||
If `static_ip.static` is:
|
||||
* `yes`: everything is fine - server uses static IP address.
|
||||
|
||||
* `no`: `static_ip.ip` contains the current dynamic IP address which we may set as static. In this case UI shows a warning:
|
||||
|
||||
Your system uses dynamic IP address configuration for interface <CURRENT INTERFACE NAME>. In order to use DHCP server a static IP address must be set. Your current IP address is <static_ip.ip>. We will automatically set this IP address as static if you press Enable DHCP button.
|
||||
|
||||
* `error`: this means that the server failed to check for a static IP. In this case UI shows a warning:
|
||||
|
||||
In order to use DHCP server a static IP address must be set. We failed to determine if this network interface is configured using static IP address. Please set a static IP address manually.
|
||||
|
||||
|
||||
### "Enable DHCP" command
|
||||
|
||||
Request:
|
||||
|
||||
POST /control/dhcp/set_config
|
||||
|
||||
{
|
||||
"enabled":true,
|
||||
"interface_name":"vboxnet0",
|
||||
"gateway_ip":"192.169.56.1",
|
||||
"subnet_mask":"255.255.255.0",
|
||||
"range_start":"192.169.56.3",
|
||||
"range_end":"192.169.56.3",
|
||||
"lease_duration":60,
|
||||
"icmp_timeout_msec":0
|
||||
}
|
||||
|
||||
Response:
|
||||
|
||||
200 OK
|
||||
|
||||
OK
|
||||
|
||||
|
||||
### Static IP check/set
|
||||
|
||||
Before enabling DHCP server we have to make sure the network interface we use has a static IP configured.
|
||||
|
||||
#### Phase 1
|
||||
|
||||
On Debian systems DHCP is configured by `/etc/dhcpcd.conf`.
|
||||
|
||||
To detect if a static IP is used currently we search for line
|
||||
|
||||
interface eth0
|
||||
|
||||
and then look for line
|
||||
|
||||
static ip_address=...
|
||||
|
||||
If the interface already has a static IP, everything is set up, we don't have to change anything.
|
||||
|
||||
To get the current IP address along with netmask we execute
|
||||
|
||||
ip -oneline -family inet address show eth0
|
||||
|
||||
which will print:
|
||||
|
||||
2: eth0 inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0\ valid_lft forever preferred_lft forever
|
||||
|
||||
To get the current gateway address:
|
||||
|
||||
ip route show dev enp2s0
|
||||
|
||||
which will print:
|
||||
|
||||
default via 192.168.0.1 proto dhcp metric 100
|
||||
|
||||
|
||||
#### Phase 2
|
||||
|
||||
This method only works on Raspbian.
|
||||
|
||||
On Ubuntu DHCP for a network interface can't be disabled via `dhcpcd.conf`. This must be configured in `/etc/netplan/01-netcfg.yaml`.
|
||||
|
||||
Fedora doesn't use `dhcpcd.conf` configuration at all.
|
||||
|
||||
Step 1.
|
||||
|
||||
To set a static IP address we add these lines to `dhcpcd.conf`:
|
||||
|
||||
interface eth0
|
||||
static ip_address=192.168.0.1/24
|
||||
static routers=192.168.0.1
|
||||
static domain_name_servers=192.168.0.1
|
||||
|
||||
* Don't set 'routers' if we couldn't find gateway IP
|
||||
* Set 'domain_name_servers' equal to our IP
|
||||
|
||||
Step 2.
|
||||
|
||||
If we would set a different IP address, we'd need to replace the IP address for the current network configuration. But currently this step isn't necessary.
|
||||
|
||||
ip addr replace dev eth0 192.168.0.1/24
|
Loading…
Reference in New Issue