Skip to content

Commit

Permalink
Merge branch 'master' into 2145-optimistic-cache
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Jul 1, 2021
2 parents a034eb9 + e113b27 commit f1594e7
Show file tree
Hide file tree
Showing 20 changed files with 443 additions and 111 deletions.
11 changes: 8 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to
### Added

- Optimistic cache ([#2145]).
- New possible value of `6h` for `querylog_interval` setting ([#2504]).
- Blocking access using client IDs ([#2624], [#3162]).
- `source` directives support in `/etc/network/interfaces` on Linux ([#3257]).
- RFC 9000 support in DNS-over-QUIC.
Expand All @@ -36,13 +37,15 @@ and this project adheres to
([#3185]).
- The ability to completely disable reverse DNS resolving of IPs from
locally-served networks ([#3184]).
- New flag `--local-frontend` to serve dinamically changeable frontend files
- New flag `--local-frontend` to serve dynamically changeable frontend files
from disk as opposed to the ones that were compiled into the binary.

### Changed

- `querylog_interval` setting is now formatted in hours.
- Query log search now supports internationalized domains ([#3012]).
- Internationalized domains are now shown decoded in the query log with the
original encoded version shown in request details. ([#3013]).
original encoded version shown in request details ([#3013]).
- When /etc/hosts-type rules have several IPs for one host, all IPs are now
returned instead of only the first one ([#1381]).
- The setting `rlimit_nofile` is now in the `os` block of the configuration
Expand Down Expand Up @@ -83,8 +86,10 @@ released by then.
[#2439]: https://github.com/AdguardTeam/AdGuardHome/issues/2439
[#2441]: https://github.com/AdguardTeam/AdGuardHome/issues/2441
[#2443]: https://github.com/AdguardTeam/AdGuardHome/issues/2443
[#2504]: https://github.com/AdguardTeam/AdGuardHome/issues/2504
[#2624]: https://github.com/AdguardTeam/AdGuardHome/issues/2624
[#2763]: https://github.com/AdguardTeam/AdGuardHome/issues/2763
[#3012]: https://github.com/AdguardTeam/AdGuardHome/issues/3012
[#3013]: https://github.com/AdguardTeam/AdGuardHome/issues/3013
[#3136]: https://github.com/AdguardTeam/AdGuardHome/issues/3136
[#3162]: https://github.com/AdguardTeam/AdGuardHome/issues/3162
Expand Down Expand Up @@ -149,7 +154,7 @@ released by then.
### Fixed

- Local domain name handling when the DHCP server is disabled ([#3028]).
- Normalization of perviously-saved invalid static DHCP leases ([#3027]).
- Normalization of previously-saved invalid static DHCP leases ([#3027]).
- Validation of IPv6 addresses with zones in system resolvers ([#3022]).

[#3022]: https://github.com/AdguardTeam/AdGuardHome/issues/3022
Expand Down
1 change: 1 addition & 0 deletions client/src/__locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@
"encryption_key_source_content": "Paste the private key contents",
"stats_params": "Statistics configuration",
"config_successfully_saved": "Configuration successfully saved",
"interval_6_hour": "6 hours",
"interval_24_hour": "24 hours",
"interval_days": "{{count}} day",
"interval_days_plural": "{{count}} days",
Expand Down
41 changes: 24 additions & 17 deletions client/src/components/Settings/LogsConfig/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,33 @@ import { Field, reduxForm } from 'redux-form';
import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow';

import { CheckboxField, renderRadioField, toNumber } from '../../../helpers/form';
import { CheckboxField, renderRadioField, toFloatNumber } from '../../../helpers/form';
import { FORM_NAME, QUERY_LOG_INTERVALS_DAYS } from '../../../helpers/constants';
import '../FormButton.css';

const getIntervalFields = (processing, t, toNumber) => QUERY_LOG_INTERVALS_DAYS.map((interval) => {
const title = interval === 1 ? t('interval_24_hour') : t('interval_days', { count: interval });
const getIntervalTitle = (interval, t) => {
switch (interval) {
case 0.25:
return t('interval_6_hour');
case 1:
return t('interval_24_hour');
default:
return t('interval_days', { count: interval });
}
};

return (
<Field
key={interval}
name="interval"
type="radio"
component={renderRadioField}
value={interval}
placeholder={title}
normalize={toNumber}
disabled={processing}
/>
);
});
const getIntervalFields = (processing, t, toNumber) => QUERY_LOG_INTERVALS_DAYS.map((interval) => (
<Field
key={interval}
name="interval"
type="radio"
component={renderRadioField}
value={interval}
placeholder={getIntervalTitle(interval, t)}
normalize={toNumber}
disabled={processing}
/>
));

const Form = (props) => {
const {
Expand Down Expand Up @@ -56,7 +63,7 @@ const Form = (props) => {
</label>
<div className="form__group form__group--settings">
<div className="custom-controls-stacked">
{getIntervalFields(processing, t, toNumber)}
{getIntervalFields(processing, t, toFloatNumber)}
</div>
</div>
<div className="mt-5">
Expand Down
2 changes: 1 addition & 1 deletion client/src/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ export const NOT_FILTERED = 'NotFiltered';

export const STATS_INTERVALS_DAYS = [0, 1, 7, 30, 90];

export const QUERY_LOG_INTERVALS_DAYS = [1, 7, 30, 90];
export const QUERY_LOG_INTERVALS_DAYS = [0.25, 1, 7, 30, 90];

export const FILTERS_INTERVALS_HOURS = [0, 1, 12, 24, 72, 168];

Expand Down
6 changes: 6 additions & 0 deletions client/src/helpers/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ export const ip4ToInt = (ip) => {
*/
export const toNumber = (value) => value && parseInt(value, 10);

/**
* @param value {string}
* @returns {*|number}
*/
export const toFloatNumber = (value) => value && parseFloat(value, 10);

/**
* @param value {string}
* @returns {boolean}
Expand Down
20 changes: 11 additions & 9 deletions internal/home/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"sync"
"time"

"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
Expand Down Expand Up @@ -102,11 +103,12 @@ type dnsConfig struct {
// time interval for statistics (in days)
StatsInterval uint32 `yaml:"statistics_interval"`

QueryLogEnabled bool `yaml:"querylog_enabled"` // if true, query log is enabled
QueryLogFileEnabled bool `yaml:"querylog_file_enabled"` // if true, query log will be written to a file
QueryLogInterval uint32 `yaml:"querylog_interval"` // time interval for query log (in days)
QueryLogMemSize uint32 `yaml:"querylog_size_memory"` // number of entries kept in memory before they are flushed to disk
AnonymizeClientIP bool `yaml:"anonymize_client_ip"` // anonymize clients' IP addresses in logs and stats
QueryLogEnabled bool `yaml:"querylog_enabled"` // if true, query log is enabled
QueryLogFileEnabled bool `yaml:"querylog_file_enabled"` // if true, query log will be written to a file
// QueryLogInterval is the interval for query log's files rotation.
QueryLogInterval Duration `yaml:"querylog_interval"`
QueryLogMemSize uint32 `yaml:"querylog_size_memory"` // number of entries kept in memory before they are flushed to disk
AnonymizeClientIP bool `yaml:"anonymize_client_ip"` // anonymize clients' IP addresses in logs and stats

dnsforward.FilteringConfig `yaml:",inline"`

Expand Down Expand Up @@ -185,7 +187,7 @@ var config = configuration{
},
FilteringEnabled: true, // whether or not use filter lists
FiltersUpdateIntervalHours: 24,
UpstreamTimeout: Duration{dnsforward.DefaultTimeout},
UpstreamTimeout: Duration{Duration: dnsforward.DefaultTimeout},
LocalDomainName: "lan",
ResolveClients: true,
UsePrivateRDNS: true,
Expand All @@ -212,7 +214,7 @@ func initConfig() {

config.DNS.QueryLogEnabled = true
config.DNS.QueryLogFileEnabled = true
config.DNS.QueryLogInterval = 90
config.DNS.QueryLogInterval = Duration{Duration: 90 * 24 * time.Hour}
config.DNS.QueryLogMemSize = 1000

config.DNS.CacheSize = 4 * 1024 * 1024
Expand Down Expand Up @@ -281,7 +283,7 @@ func parseConfig() error {
}

if config.DNS.UpstreamTimeout.Duration == 0 {
config.DNS.UpstreamTimeout = Duration{dnsforward.DefaultTimeout}
config.DNS.UpstreamTimeout = Duration{Duration: dnsforward.DefaultTimeout}
}

return nil
Expand Down Expand Up @@ -328,7 +330,7 @@ func (c *configuration) write() error {
Context.queryLog.WriteDiskConfig(&dc)
config.DNS.QueryLogEnabled = dc.Enabled
config.DNS.QueryLogFileEnabled = dc.FileEnabled
config.DNS.QueryLogInterval = dc.RotationIvl
config.DNS.QueryLogInterval = Duration{Duration: dc.RotationIvl}
config.DNS.QueryLogMemSize = dc.MemSize
config.DNS.AnonymizeClientIP = dc.AnonymizeClientIP
}
Expand Down
2 changes: 1 addition & 1 deletion internal/home/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func initDNSServer() error {
HTTPRegister: httpRegister,
FindClient: Context.clients.findMultiple,
BaseDir: baseDir,
RotationIvl: config.DNS.QueryLogInterval,
RotationIvl: config.DNS.QueryLogInterval.Duration,
MemSize: config.DNS.QueryLogMemSize,
Enabled: config.DNS.QueryLogEnabled,
FileEnabled: config.DNS.QueryLogFileEnabled,
Expand Down
31 changes: 31 additions & 0 deletions internal/home/duration.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,44 @@ type Duration struct {
time.Duration
}

// String implements the fmt.Stringer interface for Duration. It wraps
// time.Duration.String method and additionally cuts off non-leading zero values
// of minutes and seconds. Some values which are differ between the
// implementations:
//
// Duration: "1m", time.Duration: "1m0s"
// Duration: "1h", time.Duration: "1h0m0s"
// Duration: "1h1m", time.Duration: "1h1m0s"
//
func (d Duration) String() (str string) {
str = d.Duration.String()
secs := d.Seconds()
var secsInt int
if secsInt = int(secs); float64(secsInt) != secs || secsInt%60 != 0 {
return str
}

const (
tailMin = len(`0s`)
tailMinSec = len(`0m0s`)
)

if (secsInt%3600)/60 != 0 {
return str[:len(str)-tailMin]
}

return str[:len(str)-tailMinSec]
}

// MarshalText implements the encoding.TextMarshaler interface for Duration.
func (d Duration) MarshalText() (text []byte, err error) {
return []byte(d.String()), nil
}

// UnmarshalText implements the encoding.TextUnmarshaler interface for
// *Duration.
//
// TODO(e.burkov): Make it able to parse larger units like days.
func (d *Duration) UnmarshalText(b []byte) (err error) {
defer func() { err = errors.Annotate(err, "unmarshalling duration: %w") }()

Expand Down
44 changes: 44 additions & 0 deletions internal/home/duration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,50 @@ import (
yaml "gopkg.in/yaml.v2"
)

func TestDuration_String(t *testing.T) {
testCases := []struct {
name string
val time.Duration
}{{
name: "1s",
val: time.Second,
}, {
name: "1m",
val: time.Minute,
}, {
name: "1h",
val: time.Hour,
}, {
name: "1m1s",
val: time.Minute + time.Second,
}, {
name: "1h1m",
val: time.Hour + time.Minute,
}, {
name: "1h0m1s",
val: time.Hour + time.Second,
}, {
name: "1ms",
val: time.Millisecond,
}, {
name: "1h0m0.001s",
val: time.Hour + time.Millisecond,
}, {
name: "1.001s",
val: time.Second + time.Millisecond,
}, {
name: "1m1.001s",
val: time.Minute + time.Second + time.Millisecond,
}}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
d := Duration{Duration: tc.val}
assert.Equal(t, tc.name, d.String())
})
}
}

// durationEncodingTester is a helper struct to simplify testing different
// Duration marshalling and unmarshalling cases.
type durationEncodingTester struct {
Expand Down
44 changes: 43 additions & 1 deletion internal/home/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"runtime"
"strconv"
"strings"
"time"

"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/errors"
Expand All @@ -19,7 +20,7 @@ import (
)

// currentSchemaVersion is the current schema version.
const currentSchemaVersion = 11
const currentSchemaVersion = 12

// These aliases are provided for convenience.
type (
Expand Down Expand Up @@ -82,6 +83,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
upgradeSchema8to9,
upgradeSchema9to10,
upgradeSchema10to11,
upgradeSchema11to12,
}

n := 0
Expand Down Expand Up @@ -647,6 +649,46 @@ func upgradeSchema10to11(diskConf yobj) (err error) {
return nil
}

// upgradeSchema11to12 performs the following changes:
//
// # BEFORE:
// 'querylog_interval': 90
//
// # AFTER:
// 'querylog_interval': '2160h'
//
func upgradeSchema11to12(diskConf yobj) (err error) {
log.Printf("Upgrade yaml: 11 to 12")
diskConf["schema_version"] = 12

dnsVal, ok := diskConf["dns"]
if !ok {
return nil
}

var dns yobj
dns, ok = dnsVal.(yobj)
if !ok {
return fmt.Errorf("unexpected type of dns: %T", dnsVal)
}

const field = "querylog_interval"

// Set the initial value from home.initConfig function.
qlogIvl := 90
qlogIvlVal, ok := dns[field]
if ok {
qlogIvl, ok = qlogIvlVal.(int)
if !ok {
return fmt.Errorf("unexpected type of %s: %T", field, qlogIvlVal)
}
}

dns[field] = Duration{Duration: time.Duration(qlogIvl) * 24 * time.Hour}

return nil
}

// TODO(a.garipov): Replace with log.Output when we port it to our logging
// package.
func funcName() string {
Expand Down
Loading

0 comments on commit f1594e7

Please sign in to comment.