Merge branch 'master' into feature/update_locales
This commit is contained in:
commit
a5e189bdf3
|
@ -253,7 +253,7 @@
|
||||||
"rate_limit": "Rate limit",
|
"rate_limit": "Rate limit",
|
||||||
"edns_enable": "Enable EDNS Client Subnet",
|
"edns_enable": "Enable EDNS Client Subnet",
|
||||||
"edns_cs_desc": "If enabled, AdGuard Home will be sending clients' subnets to the DNS servers.",
|
"edns_cs_desc": "If enabled, AdGuard Home will be sending clients' subnets to the DNS servers.",
|
||||||
"rate_limit_desc": "The number of requests per second that a single client is allowed to make (0: unlimited)",
|
"rate_limit_desc": "The number of requests per second that a single client is allowed to make (setting it to 0 means unlimited)",
|
||||||
"blocking_ipv4_desc": "IP address to be returned for a blocked A request",
|
"blocking_ipv4_desc": "IP address to be returned for a blocked A request",
|
||||||
"blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request",
|
"blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request",
|
||||||
"blocking_mode_default": "Default: Respond with REFUSED when blocked by Adblock-style rule; respond with the IP address specified in the rule when blocked by /etc/hosts-style rule",
|
"blocking_mode_default": "Default: Respond with REFUSED when blocked by Adblock-style rule; respond with the IP address specified in the rule when blocked by /etc/hosts-style rule",
|
||||||
|
@ -564,10 +564,9 @@
|
||||||
"enter_cache_size": "Enter cache size",
|
"enter_cache_size": "Enter cache size",
|
||||||
"enter_cache_ttl_min_override": "Enter minimum TTL",
|
"enter_cache_ttl_min_override": "Enter minimum TTL",
|
||||||
"enter_cache_ttl_max_override": "Enter maximum TTL",
|
"enter_cache_ttl_max_override": "Enter maximum TTL",
|
||||||
"cache_ttl_min_override_desc": "Override TTL value (minimum) received from upstream server. This value can't larger than 3600 (1 hour)",
|
"cache_ttl_min_override_desc": "Override TTL value (minimum) received from upstream server",
|
||||||
"cache_ttl_max_override_desc": "Override TTL value (maximum) received from upstream server",
|
"cache_ttl_max_override_desc": "Override TTL value (maximum) received from upstream server",
|
||||||
"min_exceeds_max_value": "Minimum value exceeds maximum value",
|
"ttl_cache_validation": "Minimum cache TTL value must be less than or equal to the maximum value",
|
||||||
"value_not_larger_than": "Value can't be larger than {{maximum}}",
|
|
||||||
"filter_category_general": "General",
|
"filter_category_general": "General",
|
||||||
"filter_category_security": "Security",
|
"filter_category_security": "Security",
|
||||||
"filter_category_regional": "Regional",
|
"filter_category_regional": "Regional",
|
||||||
|
|
|
@ -26,3 +26,10 @@
|
||||||
left: -20px;
|
left: -20px;
|
||||||
width: calc(100% + 20px);
|
width: calc(100% + 20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1279.98px) {
|
||||||
|
.table__action {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,9 @@ import {
|
||||||
renderInputField,
|
renderInputField,
|
||||||
toNumber,
|
toNumber,
|
||||||
} from '../../../helpers/form';
|
} from '../../../helpers/form';
|
||||||
import { FORM_NAME } from '../../../helpers/constants';
|
import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants';
|
||||||
import {
|
import {
|
||||||
validateIpv4,
|
validateIpv4,
|
||||||
validateIsPositiveValue,
|
|
||||||
validateRequiredValue,
|
validateRequiredValue,
|
||||||
validateIpv4RangeEnd,
|
validateIpv4RangeEnd,
|
||||||
} from '../../../helpers/validators';
|
} from '../../../helpers/validators';
|
||||||
|
@ -110,9 +109,10 @@ const FormDHCPv4 = ({
|
||||||
type="number"
|
type="number"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder={t(ipv4placeholders.lease_duration)}
|
placeholder={t(ipv4placeholders.lease_duration)}
|
||||||
validate={[validateIsPositiveValue, validateRequired]}
|
validate={validateRequired}
|
||||||
normalize={toNumber}
|
normalize={toNumber}
|
||||||
min={0}
|
min={1}
|
||||||
|
max={UINT32_RANGE.MAX}
|
||||||
disabled={!isInterfaceIncludesIpv4}
|
disabled={!isInterfaceIncludesIpv4}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,12 +8,8 @@ import {
|
||||||
renderInputField,
|
renderInputField,
|
||||||
toNumber,
|
toNumber,
|
||||||
} from '../../../helpers/form';
|
} from '../../../helpers/form';
|
||||||
import { FORM_NAME } from '../../../helpers/constants';
|
import { FORM_NAME, UINT32_RANGE } from '../../../helpers/constants';
|
||||||
import {
|
import { validateIpv6, validateRequiredValue } from '../../../helpers/validators';
|
||||||
validateIpv6,
|
|
||||||
validateIsPositiveValue,
|
|
||||||
validateRequiredValue,
|
|
||||||
} from '../../../helpers/validators';
|
|
||||||
|
|
||||||
const FormDHCPv6 = ({
|
const FormDHCPv6 = ({
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
@ -86,9 +82,10 @@ const FormDHCPv6 = ({
|
||||||
type="number"
|
type="number"
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder={t(ipv6placeholders.lease_duration)}
|
placeholder={t(ipv6placeholders.lease_duration)}
|
||||||
validate={[validateIsPositiveValue, validateRequired]}
|
validate={validateRequired}
|
||||||
normalizeOnBlur={toNumber}
|
normalizeOnBlur={toNumber}
|
||||||
min={0}
|
min={1}
|
||||||
|
max={UINT32_RANGE.MAX}
|
||||||
disabled={!isInterfaceIncludesIpv6}
|
disabled={!isInterfaceIncludesIpv6}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,32 +4,30 @@ import { Field, reduxForm } from 'redux-form';
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
import { shallowEqual, useSelector } from 'react-redux';
|
import { shallowEqual, useSelector } from 'react-redux';
|
||||||
import { renderInputField, toNumber } from '../../../../helpers/form';
|
import { renderInputField, toNumber } from '../../../../helpers/form';
|
||||||
import { validateBiggerOrEqualZeroValue, getMaxValueValidator, validateRequiredValue } from '../../../../helpers/validators';
|
import { validateRequiredValue } from '../../../../helpers/validators';
|
||||||
import { FORM_NAME, SECONDS_IN_HOUR } from '../../../../helpers/constants';
|
import { CACHE_CONFIG_FIELDS, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants';
|
||||||
|
|
||||||
const validateMaxValue3600 = getMaxValueValidator(SECONDS_IN_HOUR);
|
const getInputFields = (validateRequiredValue) => [
|
||||||
|
{
|
||||||
const getInputFields = ({ validateRequiredValue, validateMaxValue3600 }) => [{
|
name: CACHE_CONFIG_FIELDS.cache_size,
|
||||||
name: 'cache_size',
|
|
||||||
title: 'cache_size',
|
title: 'cache_size',
|
||||||
description: 'cache_size_desc',
|
description: 'cache_size_desc',
|
||||||
placeholder: 'enter_cache_size',
|
placeholder: 'enter_cache_size',
|
||||||
validate: validateRequiredValue,
|
validate: validateRequiredValue,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'cache_ttl_min',
|
name: CACHE_CONFIG_FIELDS.cache_ttl_min,
|
||||||
title: 'cache_ttl_min_override',
|
title: 'cache_ttl_min_override',
|
||||||
description: 'cache_ttl_min_override_desc',
|
description: 'cache_ttl_min_override_desc',
|
||||||
placeholder: 'enter_cache_ttl_min_override',
|
placeholder: 'enter_cache_ttl_min_override',
|
||||||
max: SECONDS_IN_HOUR,
|
|
||||||
validate: validateMaxValue3600,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'cache_ttl_max',
|
name: CACHE_CONFIG_FIELDS.cache_ttl_max,
|
||||||
title: 'cache_ttl_max_override',
|
title: 'cache_ttl_max_override',
|
||||||
description: 'cache_ttl_max_override_desc',
|
description: 'cache_ttl_max_override_desc',
|
||||||
placeholder: 'enter_cache_ttl_max_override',
|
placeholder: 'enter_cache_ttl_max_override',
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const Form = ({
|
const Form = ({
|
||||||
handleSubmit, submitting, invalid,
|
handleSubmit, submitting, invalid,
|
||||||
|
@ -41,17 +39,16 @@ const Form = ({
|
||||||
cache_ttl_max, cache_ttl_min,
|
cache_ttl_max, cache_ttl_min,
|
||||||
} = useSelector((state) => state.form[FORM_NAME.CACHE].values, shallowEqual);
|
} = useSelector((state) => state.form[FORM_NAME.CACHE].values, shallowEqual);
|
||||||
|
|
||||||
const minExceedsMax = cache_ttl_min > cache_ttl_max;
|
const minExceedsMax = typeof cache_ttl_min === 'number'
|
||||||
|
&& typeof cache_ttl_max === 'number'
|
||||||
|
&& cache_ttl_min > cache_ttl_max;
|
||||||
|
|
||||||
const INPUTS_FIELDS = getInputFields({
|
const INPUTS_FIELDS = getInputFields(validateRequiredValue);
|
||||||
validateRequiredValue,
|
|
||||||
validateMaxValue3600,
|
|
||||||
});
|
|
||||||
|
|
||||||
return <form onSubmit={handleSubmit}>
|
return <form onSubmit={handleSubmit}>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{INPUTS_FIELDS.map(({
|
{INPUTS_FIELDS.map(({
|
||||||
name, title, description, placeholder, validate, max,
|
name, title, description, placeholder, validate, min = 0, max = UINT32_RANGE.MAX,
|
||||||
}) => <div className="col-12" key={name}>
|
}) => <div className="col-12" key={name}>
|
||||||
<div className="col-12 col-md-7 p-0">
|
<div className="col-12 col-md-7 p-0">
|
||||||
<div className="form__group form__group--settings">
|
<div className="form__group form__group--settings">
|
||||||
|
@ -66,15 +63,15 @@ const Form = ({
|
||||||
disabled={processingSetConfig}
|
disabled={processingSetConfig}
|
||||||
normalize={toNumber}
|
normalize={toNumber}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
validate={[validateBiggerOrEqualZeroValue].concat(validate || [])}
|
validate={validate}
|
||||||
min={0}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>)}
|
</div>)}
|
||||||
{minExceedsMax
|
{minExceedsMax
|
||||||
&& <span className="text-danger pl-3 pb-3">{t('min_exceeds_max_value')}</span>}
|
&& <span className="text-danger pl-3 pb-3">{t('ttl_cache_validation')}</span>}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { change } from 'redux-form';
|
||||||
import Card from '../../../ui/Card';
|
import Card from '../../../ui/Card';
|
||||||
import Form from './Form';
|
import Form from './Form';
|
||||||
import { setDnsConfig } from '../../../../actions/dnsConfig';
|
import { setDnsConfig } from '../../../../actions/dnsConfig';
|
||||||
import { selectCompletedFields } from '../../../../helpers/helpers';
|
import { selectCompletedFields } from '../../../../helpers/helpers';
|
||||||
|
import { CACHE_CONFIG_FIELDS, FORM_NAME } from '../../../../helpers/constants';
|
||||||
|
|
||||||
const CacheConfig = () => {
|
const CacheConfig = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -15,6 +17,15 @@ const CacheConfig = () => {
|
||||||
|
|
||||||
const handleFormSubmit = (values) => {
|
const handleFormSubmit = (values) => {
|
||||||
const completedFields = selectCompletedFields(values);
|
const completedFields = selectCompletedFields(values);
|
||||||
|
|
||||||
|
Object.entries(completedFields).forEach(([k, v]) => {
|
||||||
|
if ((k === CACHE_CONFIG_FIELDS.cache_ttl_min
|
||||||
|
|| k === CACHE_CONFIG_FIELDS.cache_ttl_max)
|
||||||
|
&& v === 0) {
|
||||||
|
dispatch(change(FORM_NAME.CACHE, k, ''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
dispatch(setDnsConfig(completedFields));
|
dispatch(setDnsConfig(completedFields));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,11 @@ import {
|
||||||
toNumber,
|
toNumber,
|
||||||
} from '../../../../helpers/form';
|
} from '../../../../helpers/form';
|
||||||
import {
|
import {
|
||||||
validateBiggerOrEqualZeroValue,
|
|
||||||
validateIpv4,
|
validateIpv4,
|
||||||
validateIpv6,
|
validateIpv6,
|
||||||
validateRequiredValue,
|
validateRequiredValue,
|
||||||
} from '../../../../helpers/validators';
|
} from '../../../../helpers/validators';
|
||||||
import { BLOCKING_MODES, FORM_NAME } from '../../../../helpers/constants';
|
import { BLOCKING_MODES, FORM_NAME, UINT32_RANGE } from '../../../../helpers/constants';
|
||||||
|
|
||||||
const checkboxes = [
|
const checkboxes = [
|
||||||
{
|
{
|
||||||
|
@ -87,7 +86,9 @@ const Form = ({
|
||||||
className="form-control"
|
className="form-control"
|
||||||
placeholder={t('form_enter_rate_limit')}
|
placeholder={t('form_enter_rate_limit')}
|
||||||
normalize={toNumber}
|
normalize={toNumber}
|
||||||
validate={[validateRequiredValue, validateBiggerOrEqualZeroValue]}
|
validate={validateRequiredValue}
|
||||||
|
min={UINT32_RANGE.MIN}
|
||||||
|
max={UINT32_RANGE.MAX}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -506,9 +506,12 @@ export const FORM_NAME = {
|
||||||
export const SMALL_SCREEN_SIZE = 767;
|
export const SMALL_SCREEN_SIZE = 767;
|
||||||
export const MEDIUM_SCREEN_SIZE = 1023;
|
export const MEDIUM_SCREEN_SIZE = 1023;
|
||||||
|
|
||||||
export const SECONDS_IN_HOUR = 60 * 60;
|
export const SECONDS_IN_DAY = 60 * 60 * 24;
|
||||||
|
|
||||||
export const SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;
|
export const UINT32_RANGE = {
|
||||||
|
MIN: 0,
|
||||||
|
MAX: 4294967295,
|
||||||
|
};
|
||||||
|
|
||||||
export const DHCP_VALUES_PLACEHOLDERS = {
|
export const DHCP_VALUES_PLACEHOLDERS = {
|
||||||
ipv4: {
|
ipv4: {
|
||||||
|
@ -559,3 +562,9 @@ export const ADDRESS_TYPES = {
|
||||||
CIDR: 'CIDR',
|
CIDR: 'CIDR',
|
||||||
UNKNOWN: 'UNKNOWN',
|
UNKNOWN: 'UNKNOWN',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CACHE_CONFIG_FIELDS = {
|
||||||
|
cache_size: 'cache_size',
|
||||||
|
cache_ttl_min: 'cache_ttl_min',
|
||||||
|
cache_ttl_max: 'cache_ttl_max',
|
||||||
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import i18next from 'i18next';
|
|
||||||
import {
|
import {
|
||||||
MAX_PORT,
|
MAX_PORT,
|
||||||
R_CIDR,
|
R_CIDR,
|
||||||
|
@ -28,17 +27,6 @@ export const validateRequiredValue = (value) => {
|
||||||
return 'form_error_required';
|
return 'form_error_required';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param maximum {number}
|
|
||||||
* @returns {(value:number) => undefined|string}
|
|
||||||
*/
|
|
||||||
export const getMaxValueValidator = (maximum) => (value) => {
|
|
||||||
if (value && value > maximum) {
|
|
||||||
return i18next.t('value_not_larger_than', { maximum });
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value {string}
|
* @param value {string}
|
||||||
* @returns {undefined|string}
|
* @returns {undefined|string}
|
||||||
|
@ -122,17 +110,6 @@ export const validateMac = (value) => {
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param value {number}
|
|
||||||
* @returns {undefined|string}
|
|
||||||
*/
|
|
||||||
export const validateIsPositiveValue = (value) => {
|
|
||||||
if ((value || value === 0) && value <= 0) {
|
|
||||||
return 'form_error_positive';
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value {number}
|
* @param value {number}
|
||||||
* @returns {boolean|*}
|
* @returns {boolean|*}
|
||||||
|
|
|
@ -214,6 +214,9 @@ func (s *Server) initDefaultSettings() {
|
||||||
if s.conf.TCPListenAddr == nil {
|
if s.conf.TCPListenAddr == nil {
|
||||||
s.conf.TCPListenAddr = defaultValues.TCPListenAddr
|
s.conf.TCPListenAddr = defaultValues.TCPListenAddr
|
||||||
}
|
}
|
||||||
|
if len(s.conf.BlockedHosts) == 0 {
|
||||||
|
s.conf.BlockedHosts = defaultBlockedHosts
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareUpstreamSettings - prepares upstream DNS server settings
|
// prepareUpstreamSettings - prepares upstream DNS server settings
|
||||||
|
|
|
@ -31,6 +31,9 @@ var defaultDNS = []string{
|
||||||
}
|
}
|
||||||
var defaultBootstrap = []string{"9.9.9.10", "149.112.112.10", "2620:fe::10", "2620:fe::fe:10"}
|
var defaultBootstrap = []string{"9.9.9.10", "149.112.112.10", "2620:fe::10", "2620:fe::fe:10"}
|
||||||
|
|
||||||
|
// Often requested by all kinds of DNS probes
|
||||||
|
var defaultBlockedHosts = []string{"version.bind", "id.server", "hostname.bind"}
|
||||||
|
|
||||||
var webRegistered bool
|
var webRegistered bool
|
||||||
|
|
||||||
// Server is the main way to start a DNS server.
|
// Server is the main way to start a DNS server.
|
||||||
|
|
|
@ -9,13 +9,17 @@ import (
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/util"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/dhcpd"
|
"github.com/AdguardTeam/AdGuardHome/dhcpd"
|
||||||
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
|
"github.com/AdguardTeam/AdGuardHome/dnsfilter"
|
||||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||||
|
@ -664,17 +668,17 @@ func TestBlockedBySafeBrowsing(t *testing.T) {
|
||||||
func TestRewrite(t *testing.T) {
|
func TestRewrite(t *testing.T) {
|
||||||
c := dnsfilter.Config{}
|
c := dnsfilter.Config{}
|
||||||
c.Rewrites = []dnsfilter.RewriteEntry{
|
c.Rewrites = []dnsfilter.RewriteEntry{
|
||||||
dnsfilter.RewriteEntry{
|
{
|
||||||
Domain: "test.com",
|
Domain: "test.com",
|
||||||
Answer: "1.2.3.4",
|
Answer: "1.2.3.4",
|
||||||
Type: dns.TypeA,
|
Type: dns.TypeA,
|
||||||
},
|
},
|
||||||
dnsfilter.RewriteEntry{
|
{
|
||||||
Domain: "alias.test.com",
|
Domain: "alias.test.com",
|
||||||
Answer: "test.com",
|
Answer: "test.com",
|
||||||
Type: dns.TypeCNAME,
|
Type: dns.TypeCNAME,
|
||||||
},
|
},
|
||||||
dnsfilter.RewriteEntry{
|
{
|
||||||
Domain: "my.alias.example.org",
|
Domain: "my.alias.example.org",
|
||||||
Answer: "example.org",
|
Answer: "example.org",
|
||||||
Type: dns.TypeCNAME,
|
Type: dns.TypeCNAME,
|
||||||
|
@ -1066,7 +1070,7 @@ func (d *testDHCP) SetOnLeaseChanged(onLeaseChanged dhcpd.OnLeaseChangedT) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPTRResponse(t *testing.T) {
|
func TestPTRResponseFromDHCPLeases(t *testing.T) {
|
||||||
dhcp := &testDHCP{}
|
dhcp := &testDHCP{}
|
||||||
|
|
||||||
c := dnsfilter.Config{}
|
c := dnsfilter.Config{}
|
||||||
|
@ -1094,3 +1098,45 @@ func TestPTRResponse(t *testing.T) {
|
||||||
|
|
||||||
s.Close()
|
s.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPTRResponseFromHosts(t *testing.T) {
|
||||||
|
c := dnsfilter.Config{
|
||||||
|
AutoHosts: &util.AutoHosts{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare test hosts file
|
||||||
|
hf, _ := ioutil.TempFile("", "")
|
||||||
|
defer func() { _ = os.Remove(hf.Name()) }()
|
||||||
|
defer hf.Close()
|
||||||
|
|
||||||
|
_, _ = hf.WriteString(" 127.0.0.1 host # comment \n")
|
||||||
|
_, _ = hf.WriteString(" ::1 localhost#comment \n")
|
||||||
|
|
||||||
|
// Init auto hosts
|
||||||
|
c.AutoHosts.Init(hf.Name())
|
||||||
|
defer c.AutoHosts.Close()
|
||||||
|
|
||||||
|
f := dnsfilter.New(&c, nil)
|
||||||
|
s := NewServer(DNSCreateParams{DNSFilter: f})
|
||||||
|
s.conf.UDPListenAddr = &net.UDPAddr{Port: 0}
|
||||||
|
s.conf.TCPListenAddr = &net.TCPAddr{Port: 0}
|
||||||
|
s.conf.UpstreamDNS = []string{"127.0.0.1:53"}
|
||||||
|
s.conf.FilteringConfig.ProtectionEnabled = true
|
||||||
|
err := s.Prepare(nil)
|
||||||
|
assert.True(t, err == nil)
|
||||||
|
assert.Nil(t, s.Start())
|
||||||
|
|
||||||
|
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
||||||
|
req := createTestMessage("1.0.0.127.in-addr.arpa.")
|
||||||
|
req.Question[0].Qtype = dns.TypePTR
|
||||||
|
|
||||||
|
resp, err := dns.Exchange(req, addr.String())
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, len(resp.Answer))
|
||||||
|
assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype)
|
||||||
|
assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name)
|
||||||
|
ptr := resp.Answer[0].(*dns.PTR)
|
||||||
|
assert.Equal(t, "host.", ptr.Ptr)
|
||||||
|
|
||||||
|
s.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||||
return nil, errorx.Decorate(err, "dnsfilter failed to check host '%s'", host)
|
return nil, errorx.Decorate(err, "dnsfilter failed to check host '%s'", host)
|
||||||
|
|
||||||
} else if res.IsFiltered {
|
} else if res.IsFiltered {
|
||||||
// log.Tracef("Host %s is filtered, reason - '%s', matched rule: '%s'", host, res.Reason, res.Rule)
|
log.Tracef("Host %s is filtered, reason - '%s', matched rule: '%s'", host, res.Reason, res.Rule)
|
||||||
d.Res = s.genDNSFilterMessage(d, &res)
|
d.Res = s.genDNSFilterMessage(d, &res)
|
||||||
|
|
||||||
} else if res.Reason == dnsfilter.ReasonRewrite && len(res.CanonName) != 0 && len(res.IPList) == 0 {
|
} else if res.Reason == dnsfilter.ReasonRewrite && len(res.CanonName) != 0 && len(res.IPList) == 0 {
|
||||||
|
@ -59,6 +59,19 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||||
// resolve canonical name, not the original host name
|
// resolve canonical name, not the original host name
|
||||||
d.Req.Question[0].Name = dns.Fqdn(res.CanonName)
|
d.Req.Question[0].Name = dns.Fqdn(res.CanonName)
|
||||||
|
|
||||||
|
} else if res.Reason == dnsfilter.RewriteEtcHosts && len(res.ReverseHost) != 0 {
|
||||||
|
|
||||||
|
resp := s.makeResponse(req)
|
||||||
|
ptr := &dns.PTR{}
|
||||||
|
ptr.Hdr = dns.RR_Header{
|
||||||
|
Name: req.Question[0].Name,
|
||||||
|
Rrtype: dns.TypePTR,
|
||||||
|
Ttl: s.conf.BlockedResponseTTL,
|
||||||
|
Class: dns.ClassINET,
|
||||||
|
}
|
||||||
|
ptr.Ptr = res.ReverseHost
|
||||||
|
resp.Answer = append(resp.Answer, ptr)
|
||||||
|
d.Res = resp
|
||||||
} else if res.Reason == dnsfilter.ReasonRewrite || res.Reason == dnsfilter.RewriteEtcHosts {
|
} else if res.Reason == dnsfilter.ReasonRewrite || res.Reason == dnsfilter.RewriteEtcHosts {
|
||||||
resp := s.makeResponse(req)
|
resp := s.makeResponse(req)
|
||||||
|
|
||||||
|
@ -81,20 +94,6 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Res = resp
|
d.Res = resp
|
||||||
|
|
||||||
} else if res.Reason == dnsfilter.RewriteEtcHosts && len(res.ReverseHost) != 0 {
|
|
||||||
|
|
||||||
resp := s.makeResponse(req)
|
|
||||||
ptr := &dns.PTR{}
|
|
||||||
ptr.Hdr = dns.RR_Header{
|
|
||||||
Name: req.Question[0].Name,
|
|
||||||
Rrtype: dns.TypePTR,
|
|
||||||
Ttl: s.conf.BlockedResponseTTL,
|
|
||||||
Class: dns.ClassINET,
|
|
||||||
}
|
|
||||||
ptr.Ptr = res.ReverseHost
|
|
||||||
resp.Answer = append(resp.Answer, ptr)
|
|
||||||
d.Res = resp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &res, err
|
return &res, err
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdguardTeam/dnsproxy v0.32.1
|
github.com/AdguardTeam/dnsproxy v0.32.5
|
||||||
github.com/AdguardTeam/golibs v0.4.2
|
github.com/AdguardTeam/golibs v0.4.2
|
||||||
github.com/AdguardTeam/urlfilter v0.12.2
|
github.com/AdguardTeam/urlfilter v0.12.2
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
|
||||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||||
github.com/AdguardTeam/dnsproxy v0.32.1 h1:UoiFt/aT8YCBFUGe7hG8ehLRXyvoIf22mOQqeIQxhWI=
|
github.com/AdguardTeam/dnsproxy v0.32.5 h1:UiExd/uHt2UOL4tYg1+WfXXUlkxmlpnMnQiTs63PekQ=
|
||||||
github.com/AdguardTeam/dnsproxy v0.32.1/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw=
|
github.com/AdguardTeam/dnsproxy v0.32.5/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw=
|
||||||
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||||
github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o=
|
github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o=
|
||||||
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||||
|
|
|
@ -161,6 +161,9 @@ func run(args options) {
|
||||||
// configure log level and output
|
// configure log level and output
|
||||||
configureLogger(args)
|
configureLogger(args)
|
||||||
|
|
||||||
|
// Go memory hacks
|
||||||
|
memoryUsage(args)
|
||||||
|
|
||||||
// print the first message after logger is configured
|
// print the first message after logger is configured
|
||||||
log.Println(version())
|
log.Println(version())
|
||||||
log.Debug("Current working directory is %s", Context.workDir)
|
log.Debug("Current working directory is %s", Context.workDir)
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package home
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// memoryUsage implements a couple of not really beautiful hacks which purpose is to
|
||||||
|
// make OS reclaim the memory freed by AdGuard Home as soon as possible.
|
||||||
|
// See this for the details on the performance hits & gains:
|
||||||
|
// https://github.com/AdguardTeam/AdGuardHome/issues/2044#issuecomment-687042211
|
||||||
|
func memoryUsage(args options) {
|
||||||
|
if args.disableMemoryOptimization {
|
||||||
|
log.Info("Memory optimization is disabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes Go allocate heap at a slower pace
|
||||||
|
// By default we keep it at 50%
|
||||||
|
debug.SetGCPercent(50)
|
||||||
|
|
||||||
|
// madvdontneed: setting madvdontneed=1 will use MADV_DONTNEED
|
||||||
|
// instead of MADV_FREE on Linux when returning memory to the
|
||||||
|
// kernel. This is less efficient, but causes RSS numbers to drop
|
||||||
|
// more quickly.
|
||||||
|
_ = os.Setenv("GODEBUG", "madvdontneed=1")
|
||||||
|
|
||||||
|
// periodically call "debug.FreeOSMemory" so
|
||||||
|
// that the OS could reclaim the free memory
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(5 * time.Minute)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case t := <-ticker.C:
|
||||||
|
t.Second()
|
||||||
|
log.Debug("Free OS memory")
|
||||||
|
debug.FreeOSMemory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
|
@ -24,7 +24,11 @@ type options struct {
|
||||||
// runningAsService flag is set to true when options are passed from the service runner
|
// runningAsService flag is set to true when options are passed from the service runner
|
||||||
runningAsService bool
|
runningAsService bool
|
||||||
|
|
||||||
glinetMode bool // Activate GL-Inet mode
|
// disableMemoryOptimization - disables memory optimization hacks
|
||||||
|
// see memoryUsage() function for the details
|
||||||
|
disableMemoryOptimization bool
|
||||||
|
|
||||||
|
glinetMode bool // Activate GL-Inet compatibility mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// functions used for their side-effects
|
// functions used for their side-effects
|
||||||
|
@ -151,6 +155,13 @@ var noCheckUpdateArg = arg{
|
||||||
func(o options) []string { return boolSliceOrNil(o.disableUpdate) },
|
func(o options) []string { return boolSliceOrNil(o.disableUpdate) },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var disableMemoryOptimizationArg = arg{
|
||||||
|
"Disable memory optimization",
|
||||||
|
"no-mem-optimization", "",
|
||||||
|
nil, func(o options) (options, error) { o.disableMemoryOptimization = true; return o, nil }, nil,
|
||||||
|
func(o options) []string { return boolSliceOrNil(o.disableMemoryOptimization) },
|
||||||
|
}
|
||||||
|
|
||||||
var verboseArg = arg{
|
var verboseArg = arg{
|
||||||
"Enable verbose output",
|
"Enable verbose output",
|
||||||
"verbose", "v",
|
"verbose", "v",
|
||||||
|
@ -194,6 +205,7 @@ func init() {
|
||||||
pidfileArg,
|
pidfileArg,
|
||||||
checkConfigArg,
|
checkConfigArg,
|
||||||
noCheckUpdateArg,
|
noCheckUpdateArg,
|
||||||
|
disableMemoryOptimizationArg,
|
||||||
verboseArg,
|
verboseArg,
|
||||||
glinetArg,
|
glinetArg,
|
||||||
versionArg,
|
versionArg,
|
||||||
|
|
|
@ -140,6 +140,15 @@ func TestParseDisableUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseDisableMemoryOptimization(t *testing.T) {
|
||||||
|
if testParseOk(t).disableMemoryOptimization {
|
||||||
|
t.Fatal("empty is not disable update")
|
||||||
|
}
|
||||||
|
if !testParseOk(t, "--no-mem-optimization").disableMemoryOptimization {
|
||||||
|
t.Fatal("--no-mem-optimization is disable update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseService(t *testing.T) {
|
func TestParseService(t *testing.T) {
|
||||||
if testParseOk(t).serviceControlAction != "" {
|
if testParseOk(t).serviceControlAction != "" {
|
||||||
t.Fatal("empty is no service command")
|
t.Fatal("empty is no service command")
|
||||||
|
@ -226,6 +235,10 @@ func TestSerializeGLInet(t *testing.T) {
|
||||||
testSerialize(t, options{glinetMode: true}, "--glinet")
|
testSerialize(t, options{glinetMode: true}, "--glinet")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSerializeDisableMemoryOptimization(t *testing.T) {
|
||||||
|
testSerialize(t, options{disableMemoryOptimization: true}, "--no-mem-optimization")
|
||||||
|
}
|
||||||
|
|
||||||
func TestSerializeMultiple(t *testing.T) {
|
func TestSerializeMultiple(t *testing.T) {
|
||||||
testSerialize(t, options{
|
testSerialize(t, options{
|
||||||
serviceControlAction: "run",
|
serviceControlAction: "run",
|
||||||
|
@ -233,5 +246,6 @@ func TestSerializeMultiple(t *testing.T) {
|
||||||
workDir: "work",
|
workDir: "work",
|
||||||
pidFile: "pid",
|
pidFile: "pid",
|
||||||
disableUpdate: true,
|
disableUpdate: true,
|
||||||
}, "-c", "config", "-w", "work", "-s", "run", "--pidfile", "pid", "--no-check-update")
|
disableMemoryOptimization: true,
|
||||||
|
}, "-c", "config", "-w", "work", "-s", "run", "--pidfile", "pid", "--no-check-update", "--no-mem-optimization")
|
||||||
}
|
}
|
||||||
|
|
31
main.go
31
main.go
|
@ -4,10 +4,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"runtime/debug"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/home"
|
"github.com/AdguardTeam/AdGuardHome/home"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,32 +17,5 @@ var channel = "release"
|
||||||
var goarm = ""
|
var goarm = ""
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
memoryUsage()
|
|
||||||
|
|
||||||
home.Main(version, channel, goarm)
|
home.Main(version, channel, goarm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// memoryUsage implements a couple of not really beautiful hacks which purpose is to
|
|
||||||
// make OS reclaim the memory freed by AdGuard Home as soon as possible.
|
|
||||||
func memoryUsage() {
|
|
||||||
debug.SetGCPercent(10)
|
|
||||||
|
|
||||||
// madvdontneed: setting madvdontneed=1 will use MADV_DONTNEED
|
|
||||||
// instead of MADV_FREE on Linux when returning memory to the
|
|
||||||
// kernel. This is less efficient, but causes RSS numbers to drop
|
|
||||||
// more quickly.
|
|
||||||
_ = os.Setenv("GODEBUG", "madvdontneed=1")
|
|
||||||
|
|
||||||
// periodically call "debug.FreeOSMemory" so
|
|
||||||
// that the OS could reclaim the free memory
|
|
||||||
go func() {
|
|
||||||
ticker := time.NewTicker(15 * time.Second)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case t := <-ticker.C:
|
|
||||||
t.Second()
|
|
||||||
debug.FreeOSMemory()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,9 +10,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/miekg/dns"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type onChangedT func()
|
type onChangedT func()
|
||||||
|
@ -62,6 +63,9 @@ func (a *AutoHosts) Init(hostsFn string) {
|
||||||
a.hostsDirs = append(a.hostsDirs, "/tmp/hosts") // OpenWRT: "/tmp/hosts/dhcp.cfg01411c"
|
a.hostsDirs = append(a.hostsDirs, "/tmp/hosts") // OpenWRT: "/tmp/hosts/dhcp.cfg01411c"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load hosts initially
|
||||||
|
a.updateHosts()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
a.watcher, err = fsnotify.NewWatcher()
|
a.watcher, err = fsnotify.NewWatcher()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -102,6 +106,62 @@ func (a *AutoHosts) Close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process - get the list of IP addresses for the hostname
|
||||||
|
// Return nil if not found
|
||||||
|
func (a *AutoHosts) Process(host string, qtype uint16) []net.IP {
|
||||||
|
if qtype == dns.TypePTR {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ipsCopy []net.IP
|
||||||
|
a.lock.Lock()
|
||||||
|
ips, _ := a.table[host]
|
||||||
|
if len(ips) != 0 {
|
||||||
|
ipsCopy = make([]net.IP, len(ips))
|
||||||
|
copy(ipsCopy, ips)
|
||||||
|
}
|
||||||
|
a.lock.Unlock()
|
||||||
|
|
||||||
|
log.Debug("AutoHosts: answer: %s -> %v", host, ipsCopy)
|
||||||
|
return ipsCopy
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessReverse - process PTR request
|
||||||
|
// Return "" if not found or an error occurred
|
||||||
|
func (a *AutoHosts) ProcessReverse(addr string, qtype uint16) string {
|
||||||
|
if qtype != dns.TypePTR {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ipReal := DNSUnreverseAddr(addr)
|
||||||
|
if ipReal == nil {
|
||||||
|
return "" // invalid IP in question
|
||||||
|
}
|
||||||
|
ipStr := ipReal.String()
|
||||||
|
|
||||||
|
a.lock.Lock()
|
||||||
|
host := a.tableReverse[ipStr]
|
||||||
|
a.lock.Unlock()
|
||||||
|
|
||||||
|
if len(host) == 0 {
|
||||||
|
return "" // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("AutoHosts: reverse-lookup: %s -> %s", addr, host)
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
|
// List - get "IP -> hostname" table. Thread-safe.
|
||||||
|
func (a *AutoHosts) List() map[string]string {
|
||||||
|
table := make(map[string]string)
|
||||||
|
a.lock.Lock()
|
||||||
|
for k, v := range a.tableReverse {
|
||||||
|
table[k] = v
|
||||||
|
}
|
||||||
|
a.lock.Unlock()
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
// update table
|
// update table
|
||||||
func (a *AutoHosts) updateTable(table map[string][]net.IP, host string, ipAddr net.IP) {
|
func (a *AutoHosts) updateTable(table map[string][]net.IP, host string, ipAddr net.IP) {
|
||||||
ips, ok := table[host]
|
ips, ok := table[host]
|
||||||
|
@ -275,59 +335,3 @@ func (a *AutoHosts) updateHosts() {
|
||||||
|
|
||||||
a.notify()
|
a.notify()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process - get the list of IP addresses for the hostname
|
|
||||||
// Return nil if not found
|
|
||||||
func (a *AutoHosts) Process(host string, qtype uint16) []net.IP {
|
|
||||||
if qtype == dns.TypePTR {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var ipsCopy []net.IP
|
|
||||||
a.lock.Lock()
|
|
||||||
ips, _ := a.table[host]
|
|
||||||
if len(ips) != 0 {
|
|
||||||
ipsCopy = make([]net.IP, len(ips))
|
|
||||||
copy(ipsCopy, ips)
|
|
||||||
}
|
|
||||||
a.lock.Unlock()
|
|
||||||
|
|
||||||
log.Debug("AutoHosts: answer: %s -> %v", host, ipsCopy)
|
|
||||||
return ipsCopy
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessReverse - process PTR request
|
|
||||||
// Return "" if not found or an error occurred
|
|
||||||
func (a *AutoHosts) ProcessReverse(addr string, qtype uint16) string {
|
|
||||||
if qtype != dns.TypePTR {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ipReal := DNSUnreverseAddr(addr)
|
|
||||||
if ipReal == nil {
|
|
||||||
return "" // invalid IP in question
|
|
||||||
}
|
|
||||||
ipStr := ipReal.String()
|
|
||||||
|
|
||||||
a.lock.Lock()
|
|
||||||
host := a.tableReverse[ipStr]
|
|
||||||
a.lock.Unlock()
|
|
||||||
|
|
||||||
if len(host) == 0 {
|
|
||||||
return "" // not found
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug("AutoHosts: reverse-lookup: %s -> %s", addr, host)
|
|
||||||
return host
|
|
||||||
}
|
|
||||||
|
|
||||||
// List - get "IP -> hostname" table. Thread-safe.
|
|
||||||
func (a *AutoHosts) List() map[string]string {
|
|
||||||
table := make(map[string]string)
|
|
||||||
a.lock.Lock()
|
|
||||||
for k, v := range a.tableReverse {
|
|
||||||
table[k] = v
|
|
||||||
}
|
|
||||||
a.lock.Unlock()
|
|
||||||
return table
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,9 +34,6 @@ func TestAutoHostsResolution(t *testing.T) {
|
||||||
|
|
||||||
ah.Init(f.Name())
|
ah.Init(f.Name())
|
||||||
|
|
||||||
// Update from the hosts file
|
|
||||||
ah.updateHosts()
|
|
||||||
|
|
||||||
// Existing host
|
// Existing host
|
||||||
ips := ah.Process("localhost", dns.TypeA)
|
ips := ah.Process("localhost", dns.TypeA)
|
||||||
assert.NotNil(t, ips)
|
assert.NotNil(t, ips)
|
||||||
|
@ -79,7 +76,6 @@ func TestAutoHostsFSNotify(t *testing.T) {
|
||||||
// Init
|
// Init
|
||||||
_, _ = f.WriteString(" 127.0.0.1 host localhost \n")
|
_, _ = f.WriteString(" 127.0.0.1 host localhost \n")
|
||||||
ah.Init(f.Name())
|
ah.Init(f.Name())
|
||||||
ah.updateHosts()
|
|
||||||
|
|
||||||
// Unknown host
|
// Unknown host
|
||||||
ips := ah.Process("newhost", dns.TypeA)
|
ips := ah.Process("newhost", dns.TypeA)
|
||||||
|
|
Loading…
Reference in New Issue