diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 1e66a0e8..33d3fa53 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -201,12 +201,12 @@ "install_auth_password_enter": "Enter password", "install_step": "Step", "install_devices_title": "Configure your devices", - "install_devices_desc": "In order for AdGuard Home to start working, you need to configure your devices to use it.", + "install_devices_desc": "To start using AdGuard Home, you need to configure your devices to use it.", "install_submit_title": "Congratulations!", "install_submit_desc": "The setup procedure is finished and you are ready to start using AdGuard Home.", "install_devices_router": "Router", "install_devices_router_desc": "This setup will automatically cover all the devices connected to your home router and you will not need to configure each of them manually.", - "install_devices_address": "AdGuard Home DNS server is listening to the following addresses", + "install_devices_address": "AdGuard Home DNS server is listening on the following addresses", "install_devices_router_list_1": "Open the preferences for your router. Usually, you can access it from your browser via a URL (like http:\/\/192.168.0.1\/ or http:\/\/192.168.1.1\/). You may be asked to enter the password. If you don't remember it, you can often reset the password by pressing a button on the router itself. Some routers require a specific application, which in that case should be already installed on your computer\/phone.", "install_devices_router_list_2": "Find the DHCP\/DNS settings. Look for the DNS letters next to a field which allows two or three sets of numbers, each broken into four groups of one to three digits.", "install_devices_router_list_3": "Enter your AdGuard Home server addresses there.", @@ -314,5 +314,21 @@ "access_blocked_desc": "Don't confuse this with filters. AdGuard Home will drop DNS queries with these domains in query's question.", "access_settings_saved": "Access settings successfully saved", "updates_checked": "Updates successfully checked", - "check_updates_now": "Check updates now" + "check_updates_now": "Check for updates now", + "dns_privacy": "DNS Privacy", + "setup_dns_privacy_1": "<0>DNS-over-TLS: Use <1>{{address}} string.", + "setup_dns_privacy_2": "<0>DNS-over-HTTPS: Use <1>{{address}} string.", + "setup_dns_privacy_3": "<0>Please note that encrypted DNS protocols are supported only on Android 9. So you need to install additional software for other operating systems.<0>Here's a list of software you can use.", + "setup_dns_privacy_android_1": "Android 9 supports DNS-over-TLS natively. To configure it, go to Settings → Network & internet → Advanced → Private DNS and enter your domain name there.", + "setup_dns_privacy_android_2": "<0>AdGuard for Android supports <1>DNS-over-HTTPS and <1>DNS-over-TLS.", + "setup_dns_privacy_android_3": "<0>Intra adds <1>DNS-over-HTTPS support to Android.", + "setup_dns_privacy_ios_1": "<0>DNSCloak supports <1>DNS-over-HTTPS, but in order to configure it to use your own server, you'll need to generate a <2>DNS Stamp for it.", + "setup_dns_privacy_ios_2": "<0>AdGuard for iOS supports <1>DNS-over-HTTPS and <1>DNS-over-TLS setup.", + "setup_dns_privacy_other_title": "Other implementations", + "setup_dns_privacy_other_1": "AdGuard Home itself can be a secure DNS client on any platform.", + "setup_dns_privacy_other_2": "<0>dnsproxy supports all known secure DNS protocols.", + "setup_dns_privacy_other_3": "<0>dnscrypt-proxy supports <1>DNS-over-HTTPS.", + "setup_dns_privacy_other_4": "<0>Mozilla Firefox supports <1>DNS-over-HTTPS.", + "setup_dns_privacy_other_5": "You will find more implementations <0>here and <1>here.", + "setup_dns_notice": "In order to use <1>DNS-over-HTTPS or <1>DNS-over-TLS, you need to <0>configure Encryption in AdGuard Home settings." } \ No newline at end of file diff --git a/client/src/components/Header/Version.js b/client/src/components/Header/Version.js index 6ac4f1ab..042b47a9 100644 --- a/client/src/components/Header/Version.js +++ b/client/src/components/Header/Version.js @@ -2,11 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Trans, withNamespaces } from 'react-i18next'; -import { getDnsAddress } from '../../helpers/helpers'; - const Version = (props) => { const { - dnsVersion, dnsAddresses, dnsPort, processingVersion, t, + dnsVersion, dnsAddresses, processingVersion, t, } = props; return ( @@ -31,9 +29,7 @@ const Version = (props) => {
- {dnsAddresses.map(ip => ( -
  • {getDnsAddress(ip, dnsPort)}
  • - ))} + {dnsAddresses.map(ip =>
  • {ip}
  • )}
    diff --git a/client/src/components/Settings/Encryption/Form.js b/client/src/components/Settings/Encryption/Form.js index 0b60271a..94e9923c 100644 --- a/client/src/components/Settings/Encryption/Form.js +++ b/client/src/components/Settings/Encryption/Form.js @@ -6,7 +6,7 @@ import { Trans, withNamespaces } from 'react-i18next'; import flow from 'lodash/flow'; import format from 'date-fns/format'; -import { renderField, renderSelectField, toNumber, port, isSafePort } from '../../../helpers/form'; +import { renderField, renderSelectField, toNumber, port, portTLS, isSafePort } from '../../../helpers/form'; import { EMPTY_DATE } from '../../../helpers/constants'; import i18n from '../../../i18n'; @@ -167,7 +167,7 @@ let Form = (props) => { type="number" className="form-control" placeholder={t('encryption_dot')} - validate={[port]} + validate={[portTLS]} normalize={toNumber} onChange={handleChange} disabled={!isEnabled} diff --git a/client/src/components/SetupGuide/index.js b/client/src/components/SetupGuide/index.js index bea2bbb1..4fb68d64 100644 --- a/client/src/components/SetupGuide/index.js +++ b/client/src/components/SetupGuide/index.js @@ -2,8 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Trans, withNamespaces } from 'react-i18next'; -import { getDnsAddress } from '../../helpers/helpers'; - import Guide from '../ui/Guide'; import Card from '../ui/Card'; import PageTitle from '../ui/PageTitle'; @@ -13,7 +11,6 @@ const SetupGuide = ({ t, dashboard: { dnsAddresses, - dnsPort, }, }) => (
    @@ -28,12 +25,10 @@ const SetupGuide = ({ install_devices_address:
    - {dnsAddresses - .map(ip =>
  • {getDnsAddress(ip, dnsPort)}
  • ) - } + {dnsAddresses.map(ip =>
  • {ip}
  • )}
    - + ); diff --git a/client/src/components/ui/Guide.js b/client/src/components/ui/Guide.js index 9e89f7ec..bc18366a 100644 --- a/client/src/components/ui/Guide.js +++ b/client/src/components/ui/Guide.js @@ -1,83 +1,373 @@ -import React from 'react'; +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; import { Trans, withNamespaces } from 'react-i18next'; import Tabs from '../ui/Tabs'; import Icons from '../ui/Icons'; -const Guide = () => ( -
    - - -
    -
    - install_devices_router +const Guide = (props) => { + const { dnsAddresses } = props; + const tlsAddress = (dnsAddresses && dnsAddresses.filter(item => item.includes('tls://'))) || ''; + const httpsAddress = + (dnsAddresses && dnsAddresses.filter(item => item.includes('https://'))) || ''; + const showDnsPrivacyNotice = httpsAddress.length < 1 && tlsAddress.length < 1; + + return ( +
    + + +
    +
    + install_devices_router +
    +
    +

    + install_devices_router_desc +

    +
      +
    1. + install_devices_router_list_1 +
    2. +
    3. + install_devices_router_list_2 +
    4. +
    5. + install_devices_router_list_3 +
    6. +
    +
    -
    -

    install_devices_router_desc

    -
      -
    1. install_devices_router_list_1
    2. -
    3. install_devices_router_list_2
    4. -
    5. install_devices_router_list_3
    6. -
    +
    +
    Windows
    +
    +
      +
    1. + install_devices_windows_list_1 +
    2. +
    3. + install_devices_windows_list_2 +
    4. +
    5. + install_devices_windows_list_3 +
    6. +
    7. + install_devices_windows_list_4 +
    8. +
    9. + install_devices_windows_list_5 +
    10. +
    11. + install_devices_windows_list_6 +
    12. +
    +
    -
    -
    -
    - Windows +
    +
    macOS
    +
    +
      +
    1. + install_devices_macos_list_1 +
    2. +
    3. + install_devices_macos_list_2 +
    4. +
    5. + install_devices_macos_list_3 +
    6. +
    7. + install_devices_macos_list_4 +
    8. +
    +
    -
    -
      -
    1. install_devices_windows_list_1
    2. -
    3. install_devices_windows_list_2
    4. -
    5. install_devices_windows_list_3
    6. -
    7. install_devices_windows_list_4
    8. -
    9. install_devices_windows_list_5
    10. -
    11. install_devices_windows_list_6
    12. -
    +
    +
    Android
    +
    +
      +
    1. + install_devices_android_list_1 +
    2. +
    3. + install_devices_android_list_2 +
    4. +
    5. + install_devices_android_list_3 +
    6. +
    7. + install_devices_android_list_4 +
    8. +
    9. + install_devices_android_list_5 +
    10. +
    +
    -
    -
    -
    - macOS +
    +
    iOS
    +
    +
      +
    1. + install_devices_ios_list_1 +
    2. +
    3. + install_devices_ios_list_2 +
    4. +
    5. + install_devices_ios_list_3 +
    6. +
    7. + install_devices_ios_list_4 +
    8. +
    +
    -
    -
      -
    1. install_devices_macos_list_1
    2. -
    3. install_devices_macos_list_2
    4. -
    5. install_devices_macos_list_3
    6. -
    7. install_devices_macos_list_4
    8. -
    +
    +
    + dns_privacy +
    +
    + {tlsAddress && tlsAddress.length > 0 && ( +
    + text, + text, + ]} + > + setup_dns_privacy_1 + +
    + )} + {httpsAddress && httpsAddress.length > 0 && ( +
    + text, + text, + ]} + > + setup_dns_privacy_2 + +
    + )} + {showDnsPrivacyNotice && ( +
    + + link + , + text, + ]} + > + setup_dns_notice + +
    + )} + {!showDnsPrivacyNotice && ( + +
    + text

    ]}> + setup_dns_privacy_3 +
    +
    +
    + Android +
      +
    • + setup_dns_privacy_android_1 +
    • +
    • + + link + , + text, + ]} + > + setup_dns_privacy_android_2 + +
    • +
    • + + link + , + text, + ]} + > + setup_dns_privacy_android_3 + +
    • +
    +
    +
    + iOS +
      +
    • + + link + , + text, + + link + , + ]} + > + setup_dns_privacy_ios_1 + +
    • +
    • + + link + , + text, + ]} + > + setup_dns_privacy_ios_2 + +
    • +
    +
    +
    + + setup_dns_privacy_other_title + +
      +
    • + setup_dns_privacy_other_1 +
    • +
    • + + link + , + ]} + > + setup_dns_privacy_other_2 + +
    • +
    • + + link + , + text, + ]} + > + setup_dns_privacy_other_3 + +
    • +
    • + + link + , + text, + ]} + > + setup_dns_privacy_other_4 + +
    • +
    • + + link + , + + link + , + ]} + > + setup_dns_privacy_other_5 + +
    • +
    +
    +
    + )} +
    -
    -
    -
    - Android -
    -
    -
      -
    1. install_devices_android_list_1
    2. -
    3. install_devices_android_list_2
    4. -
    5. install_devices_android_list_3
    6. -
    7. install_devices_android_list_4
    8. -
    9. install_devices_android_list_5
    10. -
    -
    -
    -
    -
    - iOS -
    -
    -
      -
    1. install_devices_ios_list_1
    2. -
    3. install_devices_ios_list_2
    4. -
    5. install_devices_ios_list_3
    6. -
    7. install_devices_ios_list_4
    8. -
    -
    -
    - -
    -); + +
    + ); +}; + +Guide.defaultProps = { + dnsAddresses: [], +}; + +Guide.propTypes = { + dnsAddresses: PropTypes.array, + t: PropTypes.func.isRequired, +}; export default withNamespaces()(Guide); diff --git a/client/src/components/ui/Icons.js b/client/src/components/ui/Icons.js index 92a9efa4..ac9a2a5b 100644 --- a/client/src/components/ui/Icons.js +++ b/client/src/components/ui/Icons.js @@ -59,6 +59,10 @@ const Icons = () => ( + + + + ); diff --git a/client/src/components/ui/Tab.js b/client/src/components/ui/Tab.js index 1498e3ab..cce9b132 100644 --- a/client/src/components/ui/Tab.js +++ b/client/src/components/ui/Tab.js @@ -11,6 +11,7 @@ class Tab extends Component { const { activeTab, label, + title, } = this.props; const tabClass = classnames({ @@ -26,7 +27,7 @@ class Tab extends Component { - {label} + {title || label}
    ); } @@ -36,6 +37,7 @@ Tab.propTypes = { activeTab: PropTypes.string.isRequired, label: PropTypes.string.isRequired, onClick: PropTypes.func.isRequired, + title: PropTypes.string, }; export default Tab; diff --git a/client/src/components/ui/Tabs.css b/client/src/components/ui/Tabs.css index 9c7c567f..cd1671e9 100644 --- a/client/src/components/ui/Tabs.css +++ b/client/src/components/ui/Tabs.css @@ -49,3 +49,12 @@ .tab__text p { margin-bottom: 5px; } + +.tab__text ul, +.tab__text ol { + padding-left: 25px; +} + +.tab__paragraph { + margin-bottom: 10px; +} diff --git a/client/src/components/ui/Tabs.js b/client/src/components/ui/Tabs.js index f376e825..a15b0ee6 100644 --- a/client/src/components/ui/Tabs.js +++ b/client/src/components/ui/Tabs.js @@ -27,12 +27,13 @@ class Tabs extends Component {
    {children.map((child) => { - const { label } = child.props; + const { label, title } = child.props; return ( diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index 0a9895ca..9faf2e5f 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -41,7 +41,7 @@ export const LANGUAGES = [ }, { key: 'pt-br', - name: 'Português (BR)', + name: 'Portuguese (BR)', }, { key: 'sv', diff --git a/client/src/helpers/form.js b/client/src/helpers/form.js index 72397396..39c4b7aa 100644 --- a/client/src/helpers/form.js +++ b/client/src/helpers/form.js @@ -76,6 +76,15 @@ export const port = (value) => { return false; }; +export const portTLS = (value) => { + if (value === 0) { + return false; + } else if (value && (value < 80 || value > 65535)) { + return form_error_port_range; + } + return false; +}; + export const isSafePort = (value) => { if (UNSAFE_PORTS.includes(value)) { return form_error_port_unsafe; diff --git a/home/control.go b/home/control.go index 48b31a2d..9e06258a 100644 --- a/home/control.go +++ b/home/control.go @@ -80,27 +80,60 @@ func httpUpdateConfigReloadDNSReturnOK(w http.ResponseWriter, r *http.Request) { returnOK(w) } -func handleStatus(w http.ResponseWriter, r *http.Request) { - log.Tracef("%s %v", r.Method, r.URL) +func addDNSAddress(dnsAddresses *[]string, addr string) { + if config.DNS.Port != 53 { + addr = fmt.Sprintf("%s:%d", addr, config.DNS.Port) + } + *dnsAddresses = append(*dnsAddresses, addr) +} +// Get the list of DNS addresses the server is listening on +func getDNSAddresses() []string { dnsAddresses := []string{} + if config.DNS.BindHost == "0.0.0.0" { + ifaces, e := getValidNetInterfacesForWeb() if e != nil { log.Error("Couldn't get network interfaces: %v", e) + return []string{} } + for _, iface := range ifaces { for _, addr := range iface.Addresses { - dnsAddresses = append(dnsAddresses, addr) + addDNSAddress(&dnsAddresses, addr) } } - } - if len(dnsAddresses) == 0 { - dnsAddresses = append(dnsAddresses, config.DNS.BindHost) + + } else { + addDNSAddress(&dnsAddresses, config.DNS.BindHost) } + if config.TLS.Enabled && len(config.TLS.ServerName) != 0 { + + if config.TLS.PortHTTPS != 0 { + addr := config.TLS.ServerName + if config.TLS.PortHTTPS != 443 { + addr = fmt.Sprintf("%s:%d", addr, config.TLS.PortHTTPS) + } + addr = fmt.Sprintf("https://%s/dns-query", addr) + dnsAddresses = append(dnsAddresses, addr) + } + + if config.TLS.PortDNSOverTLS != 0 { + addr := fmt.Sprintf("tls://%s:%d", config.TLS.ServerName, config.TLS.PortDNSOverTLS) + dnsAddresses = append(dnsAddresses, addr) + } + } + + return dnsAddresses +} + +func handleStatus(w http.ResponseWriter, r *http.Request) { + log.Tracef("%s %v", r.Method, r.URL) + data := map[string]interface{}{ - "dns_addresses": dnsAddresses, + "dns_addresses": getDNSAddresses(), "http_port": config.BindPort, "dns_port": config.DNS.Port, "protection_enabled": config.DNS.ProtectionEnabled,