Compare commits
8 Commits
1383-devic
...
102-dns-re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9efc39306 | ||
|
|
f924523f6a | ||
|
|
6e6ee9697a | ||
|
|
aff09211b2 | ||
|
|
bad1c6acdc | ||
|
|
fcb582679e | ||
|
|
6b60598025 | ||
|
|
b338bf9b3f |
@@ -11,7 +11,7 @@ fi
|
||||
found=0
|
||||
git diff --cached --name-only | grep -q '.go$' && found=1
|
||||
if [ $found == 1 ]; then
|
||||
make go-lint || exit 1
|
||||
make lint-go || exit 1
|
||||
go test ./... || exit 1
|
||||
fi
|
||||
|
||||
|
||||
15
.github/workflows/lint.yml
vendored
15
.github/workflows/lint.yml
vendored
@@ -1,4 +1,4 @@
|
||||
'name': 'lint'
|
||||
'name': 'golangci-lint'
|
||||
'on':
|
||||
'push':
|
||||
'tags':
|
||||
@@ -7,13 +7,16 @@
|
||||
- '*'
|
||||
'pull_request':
|
||||
'jobs':
|
||||
'go-lint':
|
||||
'golangci':
|
||||
'runs-on': 'ubuntu-latest'
|
||||
'steps':
|
||||
- 'uses': 'actions/checkout@v2'
|
||||
- 'name': 'run-lint'
|
||||
'run': >
|
||||
make go-install-tools go-lint
|
||||
- 'name': 'golangci-lint'
|
||||
'uses': 'golangci/golangci-lint-action@v2.3.0'
|
||||
'with':
|
||||
# This field is required. Don't set the patch version to always use
|
||||
# the latest patch version.
|
||||
'version': 'v1.32'
|
||||
'eslint':
|
||||
'runs-on': 'ubuntu-latest'
|
||||
'steps':
|
||||
@@ -24,7 +27,7 @@
|
||||
'run': 'npm --prefix client run lint'
|
||||
'notify':
|
||||
'needs':
|
||||
- 'go-lint'
|
||||
- 'golangci'
|
||||
- 'eslint'
|
||||
# Secrets are not passed to workflows that are triggered by a pull request
|
||||
# from a fork.
|
||||
|
||||
47
.gitignore
vendored
47
.gitignore
vendored
@@ -1,22 +1,31 @@
|
||||
# Please, DO NOT put your text editors' temporary files here. The more are
|
||||
# added, the harder it gets to maintain and manage projects' gitignores. Put
|
||||
# them into your global gitignore file instead.
|
||||
#
|
||||
# See https://stackoverflow.com/a/7335487/1892060.
|
||||
#
|
||||
# Only build, run, and test outputs here. Sorted.
|
||||
*-packr.go
|
||||
*.db
|
||||
*.snap
|
||||
/bin/
|
||||
/build/
|
||||
.DS_Store
|
||||
/.vscode
|
||||
.idea
|
||||
/AdGuardHome
|
||||
/AdGuardHome.exe
|
||||
/AdGuardHome.yaml
|
||||
/AdGuardHome.log
|
||||
/data/
|
||||
/build/
|
||||
/dist/
|
||||
/dnsfilter/tests/dnsfilter.TestLotsOfRules*.pprof
|
||||
/dnsfilter/tests/top-1m.csv
|
||||
/launchpad_credentials
|
||||
/querylog.json*
|
||||
/snapcraft_login
|
||||
AdGuardHome*
|
||||
/client/node_modules/
|
||||
/querylog.json
|
||||
/querylog.json.1
|
||||
coverage.txt
|
||||
node_modules/
|
||||
leases.db
|
||||
|
||||
# Test output
|
||||
dnsfilter/tests/top-1m.csv
|
||||
dnsfilter/tests/dnsfilter.TestLotsOfRules*.pprof
|
||||
|
||||
# Snapcraft build temporary files
|
||||
*.snap
|
||||
launchpad_credentials
|
||||
snapcraft_login
|
||||
snapcraft.yaml.bak
|
||||
|
||||
# IntelliJ IDEA project files
|
||||
*.iml
|
||||
|
||||
# Packr
|
||||
*-packr.go
|
||||
|
||||
77
.golangci.yml
Normal file
77
.golangci.yml
Normal file
@@ -0,0 +1,77 @@
|
||||
# options for analysis running
|
||||
'run':
|
||||
# default concurrency is a available CPU number
|
||||
'concurrency': 4
|
||||
|
||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||
'deadline': '2m'
|
||||
|
||||
# which files to skip: they will be analyzed, but issues from them
|
||||
# won't be reported. Default value is empty list, but there is
|
||||
# no need to include all autogenerated files, we confidently recognize
|
||||
# autogenerated files. If it's not please let us know.
|
||||
'skip-files':
|
||||
- '.*generated.*'
|
||||
- 'dnsfilter/rule_to_regexp.go'
|
||||
- 'util/pprof.go'
|
||||
- '.*_test.go'
|
||||
- 'client/.*'
|
||||
- 'build/.*'
|
||||
- 'dist/.*'
|
||||
|
||||
# all available settings of specific linters
|
||||
'linters-settings':
|
||||
'errcheck':
|
||||
# [deprecated] comma-separated list of pairs of the form pkg:regex
|
||||
# the regex is used to ignore names within pkg. (default "fmt:.*").
|
||||
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
|
||||
'ignore': 'fmt:.*,net:SetReadDeadline,net/http:^Write'
|
||||
'gocyclo':
|
||||
'min-complexity': 20
|
||||
'lll':
|
||||
'line-length': 200
|
||||
|
||||
'linters':
|
||||
'enable':
|
||||
- 'bodyclose'
|
||||
- 'deadcode'
|
||||
- 'depguard'
|
||||
- 'dupl'
|
||||
- 'errcheck'
|
||||
- 'gocyclo'
|
||||
- 'goimports'
|
||||
- 'golint'
|
||||
- 'gosec'
|
||||
- 'govet'
|
||||
- 'ineffassign'
|
||||
- 'misspell'
|
||||
- 'staticcheck'
|
||||
- 'stylecheck'
|
||||
- 'unconvert'
|
||||
- 'unused'
|
||||
- 'varcheck'
|
||||
'disable-all': true
|
||||
'fast': true
|
||||
|
||||
'issues':
|
||||
# List of regexps of issue texts to exclude, empty list by default.
|
||||
# But independently from this option we use default exclude patterns,
|
||||
# it can be disabled by `exclude-use-default: false`. To list all
|
||||
# excluded by default patterns execute `golangci-lint run --help`
|
||||
'exclude':
|
||||
# structcheck cannot detect usages while they're there
|
||||
- '.parentalServer. is unused'
|
||||
- '.safeBrowsingServer. is unused'
|
||||
# errcheck
|
||||
- 'Error return value of .s.closeConn. is not checked'
|
||||
- 'Error return value of ..*.Shutdown.'
|
||||
# goconst
|
||||
- 'string .forcesafesearch.google.com. has 3 occurrences'
|
||||
# gosec: Profiling endpoint is automatically exposed on /debug/pprof
|
||||
- 'G108'
|
||||
# gosec: Subprocess launched with function call as argument or cmd arguments
|
||||
- 'G204'
|
||||
# gosec: Potential DoS vulnerability via decompression bomb
|
||||
- 'G110'
|
||||
# gosec: Expect WriteFile permissions to be 0600 or less
|
||||
- 'G306'
|
||||
@@ -105,11 +105,3 @@
|
||||
|
||||
'checksum':
|
||||
'name_template': 'checksums.txt'
|
||||
|
||||
'snapshot':
|
||||
# TODO(a.garipov): A temporary solution to trim the prerelease versions.
|
||||
# A real solution would consist of making a better versioning scheme that also
|
||||
# doesn't break SemVer or Snapcraft.
|
||||
#
|
||||
# See https://github.com/AdguardTeam/AdGuardHome/issues/2412.
|
||||
'name_template': '{{ slice .Tag 0 8 }}-SNAPSHOT-{{ .ShortCommit }}'
|
||||
|
||||
@@ -1558,6 +1558,7 @@ Strict matching can be enabled by enclosing the value in double quotes: e.g. `"a
|
||||
* blocked_services - blocked services
|
||||
* blocked_safebrowsing - blocked by safebrowsing
|
||||
* blocked_parental - blocked by parental control
|
||||
* blocked_dns_rebinding - blocked by DNS rebinding protection
|
||||
* whitelisted - whitelisted
|
||||
* rewritten - all kinds of rewrites
|
||||
* safe_search - enforced safe search
|
||||
|
||||
@@ -31,16 +31,14 @@ and this project adheres to
|
||||
|
||||
### Changed
|
||||
|
||||
- Post-updating relaunch possibility is now determined OS-dependently ([#2231],
|
||||
[#2391]).
|
||||
- Post-updating relaunch possibility is now determined OS-dependently ([#2231], [#2391]).
|
||||
- Made the mobileconfig HTTP API more robust and predictable, add parameters and
|
||||
improve error response ([#2358]).
|
||||
- Improved HTTP requests handling and timeouts ([#2343]).
|
||||
- Our snap package now uses the `core20` image as its base ([#2306]).
|
||||
- Various internal improvements ([#2267], [#2271], [#2297]).
|
||||
- Various internal improvements ([#2271], [#2297]).
|
||||
|
||||
[#2231]: https://github.com/AdguardTeam/AdGuardHome/issues/2231
|
||||
[#2267]: https://github.com/AdguardTeam/AdGuardHome/issues/2267
|
||||
[#2271]: https://github.com/AdguardTeam/AdGuardHome/issues/2271
|
||||
[#2297]: https://github.com/AdguardTeam/AdGuardHome/issues/2297
|
||||
[#2306]: https://github.com/AdguardTeam/AdGuardHome/issues/2306
|
||||
|
||||
30
HACKING.md
30
HACKING.md
@@ -1,9 +1,9 @@
|
||||
# *AdGuardHome* Developer Guidelines
|
||||
|
||||
As of **December 2020**, this document is partially a work-in-progress, but
|
||||
should still be followed. Some of the rules aren't enforced as thoroughly or
|
||||
remain broken in old code, but this is still the place to find out about what we
|
||||
**want** our code to look like.
|
||||
As of **2020-11-27**, this document is a work-in-progress, but should still be
|
||||
followed. Some of the rules aren't enforced as thoroughly or remain broken in
|
||||
old code, but this is still the place to find out about what we **want** our
|
||||
code to look like.
|
||||
|
||||
The rules are mostly sorted in the alphabetical order.
|
||||
|
||||
@@ -32,11 +32,6 @@ The rules are mostly sorted in the alphabetical order.
|
||||
|
||||
## *Go*
|
||||
|
||||
> Not Golang, not GO, not GOLANG, not GoLang. It is Go in natural language,
|
||||
> golang for others.
|
||||
|
||||
— [@rakyll](https://twitter.com/rakyll/status/1229850223184269312)
|
||||
|
||||
### Code And Naming
|
||||
|
||||
* Avoid `goto`.
|
||||
@@ -117,6 +112,8 @@ The rules are mostly sorted in the alphabetical order.
|
||||
|
||||
* Use `gofumpt --extra -s`.
|
||||
|
||||
**TODO(a.garipov):** Add to the linters.
|
||||
|
||||
* Write slices of struct like this:
|
||||
|
||||
```go
|
||||
@@ -144,21 +141,6 @@ The rules are mostly sorted in the alphabetical order.
|
||||
|
||||
* **TODO(a.garipov):** Define our *Markdown* conventions.
|
||||
|
||||
## Shell Scripting
|
||||
|
||||
* Avoid bashisms, prefer *POSIX* features only.
|
||||
|
||||
* Prefer `'raw strings'` to `"double quoted strings"` whenever possible.
|
||||
|
||||
* Put spaces within `$( cmd )`, `$(( expr ))`, and `{ cmd; }`.
|
||||
|
||||
* `snake_case`, not `camelCase`.
|
||||
|
||||
* Use `set -e -f -u` and also `set -x` in verbose mode.
|
||||
|
||||
* Use the `"$var"` form instead of the `$var` form, unless word splitting is
|
||||
required.
|
||||
|
||||
## Text, Including Comments
|
||||
|
||||
* End sentences with appropriate punctuation.
|
||||
|
||||
43
Makefile
43
Makefile
@@ -26,8 +26,7 @@
|
||||
# * DOCKER_IMAGE_NAME - adguard/adguard-home
|
||||
# * DOCKER_OUTPUT - type=image,name=adguard/adguard-home,push=true
|
||||
|
||||
GO := go
|
||||
GOPATH := $(shell $(GO) env GOPATH)
|
||||
GOPATH := $(shell go env GOPATH)
|
||||
PWD := $(shell pwd)
|
||||
TARGET=AdGuardHome
|
||||
BASE_URL="https://static.adguard.com/adguardhome/$(CHANNEL)"
|
||||
@@ -66,9 +65,7 @@ endif
|
||||
|
||||
# Version properties
|
||||
COMMIT=$(shell git rev-parse --short HEAD)
|
||||
# TODO(a.garipov): The cut call is a temporary solution to trim
|
||||
# prerelease versions. See the comment in .goreleaser.yml.
|
||||
TAG_NAME=$(shell git describe --abbrev=0 | cut -c 1-8)
|
||||
TAG_NAME=$(shell git describe --abbrev=0)
|
||||
RELEASE_VERSION=$(TAG_NAME)
|
||||
SNAPSHOT_VERSION=$(RELEASE_VERSION)-SNAPSHOT-$(COMMIT)
|
||||
|
||||
@@ -125,9 +122,9 @@ init:
|
||||
git config core.hooksPath .githooks
|
||||
|
||||
build: client_with_deps
|
||||
$(GO) mod download
|
||||
PATH=$(GOPATH)/bin:$(PATH) $(GO) generate ./...
|
||||
CGO_ENABLED=0 $(GO) build -ldflags="-s -w -X main.version=$(VERSION) -X main.channel=$(CHANNEL) -X main.goarm=$(GOARM)"
|
||||
go mod download
|
||||
PATH=$(GOPATH)/bin:$(PATH) go generate ./...
|
||||
CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=$(VERSION) -X main.channel=$(CHANNEL) -X main.goarm=$(GOARM)"
|
||||
PATH=$(GOPATH)/bin:$(PATH) packr clean
|
||||
|
||||
client:
|
||||
@@ -154,40 +151,38 @@ docker:
|
||||
@echo Now you can run the docker image:
|
||||
@echo docker run --name "adguard-home" -p 53:53/tcp -p 53:53/udp -p 80:80/tcp -p 443:443/tcp -p 853:853/tcp -p 3000:3000/tcp $(DOCKER_IMAGE_NAME)
|
||||
|
||||
lint: js-lint go-lint
|
||||
lint: lint-js lint-go
|
||||
|
||||
js-lint: dependencies
|
||||
lint-js: dependencies
|
||||
@echo Running js linter
|
||||
npm --prefix client run lint
|
||||
|
||||
go-install-tools:
|
||||
env GO=$(GO) sh ./scripts/go-install-tools.sh
|
||||
lint-go:
|
||||
@echo Running go linter
|
||||
golangci-lint run
|
||||
|
||||
go-lint:
|
||||
env GO=$(GO) PATH="$$PWD/bin:$$PATH" sh ./scripts/go-lint.sh
|
||||
test: test-js test-go
|
||||
|
||||
test: js-test go-test
|
||||
|
||||
js-test:
|
||||
test-js:
|
||||
npm run test --prefix client
|
||||
|
||||
go-test:
|
||||
$(GO) test $(TEST_FLAGS) --coverprofile coverage.txt ./...
|
||||
test-go:
|
||||
go test $(TEST_FLAGS) --coverprofile coverage.txt ./...
|
||||
|
||||
ci: client_with_deps
|
||||
$(GO) mod download
|
||||
go mod download
|
||||
$(MAKE) test
|
||||
|
||||
dependencies:
|
||||
npm --prefix client ci
|
||||
$(GO) mod download
|
||||
go mod download
|
||||
|
||||
clean:
|
||||
rm -f ./AdGuardHome ./AdGuardHome.exe ./coverage.txt
|
||||
rm -f -r ./build/ ./client/node_modules/ ./data/ ./$(DIST_DIR)/
|
||||
rm -f -r ./build/ ./client/node_modules/ ./data/ $(DIST_DIR)
|
||||
# Set the GOPATH explicitly in case make clean is called from under sudo
|
||||
# after a Docker build.
|
||||
env PATH="$(GOPATH)/bin:$$PATH" packr clean
|
||||
rm -f -r ./bin/
|
||||
|
||||
docker-multi-arch:
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled \
|
||||
@@ -205,7 +200,7 @@ docker-multi-arch:
|
||||
@echo docker run --name "adguard-home" -p 53:53/tcp -p 53:53/udp -p 80:80/tcp -p 443:443/tcp -p 853:853/tcp -p 3000:3000/tcp $(DOCKER_IMAGE_NAME)
|
||||
|
||||
release: client_with_deps
|
||||
$(GO) mod download
|
||||
go mod download
|
||||
@echo Starting release build: version $(VERSION), channel $(CHANNEL)
|
||||
CHANNEL=$(CHANNEL) $(GORELEASER_COMMAND)
|
||||
$(call write_version_file,$(VERSION))
|
||||
|
||||
@@ -171,6 +171,9 @@ You will need this to build AdGuard Home:
|
||||
* [node.js](https://nodejs.org/en/download/) v10.16.2 or later.
|
||||
* [npm](https://www.npmjs.com/) v6.14 or later.
|
||||
|
||||
Optionally, for Go devs:
|
||||
* [golangci-lint](https://github.com/golangci/golangci-lint)
|
||||
|
||||
### Building
|
||||
|
||||
Open Terminal and execute these commands:
|
||||
@@ -183,7 +186,7 @@ make
|
||||
|
||||
Check the [`Makefile`](https://github.com/AdguardTeam/AdGuardHome/blob/master/Makefile) to learn about other commands.
|
||||
|
||||
**Building for a different platform.** You can build AdGuard for any OS/ARCH just like any other Go project.
|
||||
**Building for a different platform.** You can build AdGuard for any OS/ARCH just like any other Golang project.
|
||||
In order to do this, specify `GOOS` and `GOARCH` env variables before running make.
|
||||
|
||||
For example:
|
||||
@@ -328,4 +331,4 @@ For a full list of all node.js packages in use, please take a look at [client/pa
|
||||
<a id="privacy"></a>
|
||||
## Privacy
|
||||
|
||||
Our main idea is that you are the one, who should be in control of your data. So it is only natural, that AdGuard Home does not collect any usage statistics, and does not use any web services unless you configure it to do so. Full policy with every bit that _could in theory be_ sent by AdGuard Home is available [here](https://adguard.com/en/privacy/home.html).
|
||||
Our main idea is that you are the one, who should be in control of your data. So it is only natural, that AdGuard Home does not collect any usage statistics, and does not use any web services unless you configure it to do so. Full policy with every bit that _could in theory be_ sent by AdGuard Home is available [here](https://adguard.com/en/privacy/home.html).
|
||||
12
client/package-lock.json
generated
vendored
12
client/package-lock.json
generated
vendored
@@ -3066,6 +3066,12 @@
|
||||
"pkg-up": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001062",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001062.tgz",
|
||||
"integrity": "sha512-ei9ZqeOnN7edDrb24QfJ0OZicpEbsWxv7WusOiQGz/f2SfvBgHHbOEwBJ8HKGVSyx8Z6ndPjxzR6m0NQq+0bfw==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.30",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.30.tgz",
|
||||
@@ -3922,9 +3928,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001165",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001165.tgz",
|
||||
"integrity": "sha512-8cEsSMwXfx7lWSUMA2s08z9dIgsnR5NAqjXP23stdsU3AUWkCr/rr4s4OFtHXn5XXr6+7kam3QFVoYyXNPdJPA==",
|
||||
"version": "1.0.30001059",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001059.tgz",
|
||||
"integrity": "sha512-oOrc+jPJWooKIA0IrNZ5sYlsXc7NP7KLhNWrSGEJhnfSzDvDJ0zd3i6HXsslExY9bbu+x0FQ5C61LcqmPt7bOQ==",
|
||||
"dev": true
|
||||
},
|
||||
"capture-exit": {
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
"form_error_ip_format": "Invalid IP format",
|
||||
"form_error_mac_format": "Invalid MAC format",
|
||||
"form_error_client_id_format": "Invalid client ID format",
|
||||
"form_error_server_name": "Invalid server name or wildcard certificate",
|
||||
"form_error_positive": "Must be greater than 0",
|
||||
"form_error_negative": "Must be equal to 0 or greater",
|
||||
"range_end_error": "Must be greater than range start",
|
||||
@@ -332,7 +331,7 @@
|
||||
"encryption_config_saved": "Encryption config saved",
|
||||
"encryption_server": "Server name",
|
||||
"encryption_server_enter": "Enter your domain name",
|
||||
"encryption_server_desc": "In order to use HTTPS, you need to enter the server name that matches your SSL certificate or wildcard certificate. If the field is not set, it will accept TLS connections for any domain.",
|
||||
"encryption_server_desc": "In order to use HTTPS, you need to enter the server name that matches your SSL certificate.",
|
||||
"encryption_redirect": "Redirect to HTTPS automatically",
|
||||
"encryption_redirect_desc": "If checked, AdGuard Home will automatically redirect you from HTTP to HTTPS addresses.",
|
||||
"encryption_https": "HTTPS port",
|
||||
@@ -388,7 +387,7 @@
|
||||
"client_edit": "Edit Client",
|
||||
"client_identifier": "Identifier",
|
||||
"ip_address": "IP address",
|
||||
"client_identifier_desc": "Clients can be identified by the IP address, CIDR, MAC address or domain. Please note that using MAC as identifier is possible only if AdGuard Home is also a <0>DHCP server</0>",
|
||||
"client_identifier_desc": "Clients can be identified by the IP address, CIDR, MAC address. Please note that using MAC as identifier is possible only if AdGuard Home is also a <0>DHCP server</0>",
|
||||
"form_enter_ip": "Enter IP",
|
||||
"form_enter_mac": "Enter MAC",
|
||||
"form_enter_id": "Enter identifier",
|
||||
@@ -588,5 +587,12 @@
|
||||
"port_53_faq_link": "Port 53 is often occupied by \"DNSStubListener\" or \"systemd-resolved\" services. Please read <0>this instruction</0> on how to resolve this.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client.",
|
||||
"client_not_in_allowed_clients": "The client is not allowed because it is not in the \"Allowed clients\" list.",
|
||||
"experimental": "Experimental"
|
||||
"experimental": "Experimental",
|
||||
"rebinding_title": "DNS Rebinding Protection",
|
||||
"rebinding_desc": "Here you can configure protection against DNS rebinding attacks",
|
||||
"rebinding_protection_enabled": "Enable protection from DNS rebinding attacks",
|
||||
"rebinding_protection_enabled_desc": "If enabled, AdGuard Home will block responses containing host on the local network.",
|
||||
"rebinding_allowed_hosts_title": "Allowed domains",
|
||||
"rebinding_allowed_hosts_desc": "A list of domains. If configured, AdGuard Home will allow responses containing host on the local network from these domains. Here you can specify the exact domain names, wildcards and urlfilter-rules, e.g. 'example.org', '*.example.org' or '||example.org^'.",
|
||||
"blocked_dns_rebinding": "Blocked DNS rebinding"
|
||||
}
|
||||
|
||||
@@ -273,15 +273,15 @@ describe('sortIp', () => {
|
||||
});
|
||||
});
|
||||
describe('invalid input', () => {
|
||||
const originalWarn = console.warn;
|
||||
const originalError = console.error;
|
||||
|
||||
beforeEach(() => {
|
||||
console.warn = jest.fn();
|
||||
console.error = jest.fn();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
expect(console.warn).toHaveBeenCalled();
|
||||
console.warn = originalWarn;
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
console.error = originalError;
|
||||
});
|
||||
|
||||
test('invalid strings', () => {
|
||||
|
||||
@@ -37,6 +37,10 @@ export const setDnsConfig = (config) => async (dispatch) => {
|
||||
data.upstream_dns = splitByNewLine(config.upstream_dns);
|
||||
hasDnsSettings = true;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(data, 'rebinding_allowed_hosts')) {
|
||||
data.rebinding_allowed_hosts = splitByNewLine(config.rebinding_allowed_hosts);
|
||||
hasDnsSettings = true;
|
||||
}
|
||||
|
||||
await apiClient.setDnsConfig(data);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactTable from 'react-table';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { sortIp } from '../../../helpers/helpers';
|
||||
|
||||
class Table extends Component {
|
||||
cellWrap = ({ value }) => (
|
||||
@@ -22,7 +21,6 @@ class Table extends Component {
|
||||
{
|
||||
Header: this.props.t('answer'),
|
||||
accessor: 'answer',
|
||||
sortMethod: sortIp,
|
||||
Cell: this.cellWrap,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -259,7 +259,7 @@ let Form = (props) => {
|
||||
</div>
|
||||
<div className="form__desc mt-0 mb-2">
|
||||
<Trans components={[
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://github.com/AdguardTeam/AdGuardHome/wiki/Hosts-Blocklists#ctag"
|
||||
<a href="https://github.com/AdguardTeam/AdGuardHome/wiki/Hosts-Blocklists#ctag"
|
||||
key="0">link</a>,
|
||||
]}>
|
||||
tags_desc
|
||||
|
||||
@@ -113,6 +113,9 @@ const Dhcp = () => {
|
||||
const enteredSomeValue = enteredSomeV4Value || enteredSomeV6Value || interfaceName;
|
||||
|
||||
const getToggleDhcpButton = () => {
|
||||
const otherDhcpFound = check && (check.v4.other_server.found === STATUS_RESPONSE.YES
|
||||
|| check.v6.other_server.found === STATUS_RESPONSE.YES);
|
||||
|
||||
const filledConfig = interface_name && (Object.values(v4)
|
||||
.every(Boolean) || Object.values(v6)
|
||||
.every(Boolean));
|
||||
@@ -138,7 +141,7 @@ const Dhcp = () => {
|
||||
className={className}
|
||||
onClick={enabled ? onClickDisable : onClickEnable}
|
||||
disabled={processingDhcp || processingConfig
|
||||
|| (!enabled && (!filledConfig || !check))}
|
||||
|| (!enabled && (!filledConfig || !check || otherDhcpFound))}
|
||||
>
|
||||
<Trans>{enabled ? 'dhcp_disable' : 'dhcp_enable'}</Trans>
|
||||
</button>;
|
||||
|
||||
91
client/src/components/Settings/Dns/Rebinding/Form.js
Normal file
91
client/src/components/Settings/Dns/Rebinding/Form.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Field, reduxForm } from 'redux-form';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { renderTextareaField, CheckboxField } from '../../../../helpers/form';
|
||||
import { removeEmptyLines } from '../../../../helpers/helpers';
|
||||
import { FORM_NAME } from '../../../../helpers/constants';
|
||||
|
||||
const fields = [
|
||||
{
|
||||
id: 'rebinding_allowed_hosts',
|
||||
title: 'rebinding_allowed_hosts_title',
|
||||
subtitle: 'rebinding_allowed_hosts_desc',
|
||||
normalizeOnBlur: removeEmptyLines,
|
||||
},
|
||||
];
|
||||
|
||||
const Form = ({
|
||||
handleSubmit, submitting, invalid,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const processingSetConfig = useSelector((state) => state.dnsConfig.processingSetConfig);
|
||||
|
||||
const renderField = ({
|
||||
id, title, subtitle, disabled = processingSetConfig, normalizeOnBlur,
|
||||
}) => <div key={id} className="form__group mb-5">
|
||||
<label className="form__label form__label--with-desc" htmlFor={id}>
|
||||
<Trans>{title}</Trans>
|
||||
</label>
|
||||
<div className="form__desc form__desc--top">
|
||||
<Trans>{subtitle}</Trans>
|
||||
</div>
|
||||
<Field
|
||||
id={id}
|
||||
name={id}
|
||||
component={renderTextareaField}
|
||||
type="text"
|
||||
className="form-control form-control--textarea font-monospace"
|
||||
disabled={disabled}
|
||||
normalizeOnBlur={normalizeOnBlur}
|
||||
/>
|
||||
</div>;
|
||||
|
||||
renderField.propTypes = {
|
||||
id: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
subtitle: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
normalizeOnBlur: PropTypes.func,
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="col-12">
|
||||
<div className="form__group form__group--settings">
|
||||
<Field
|
||||
name={'rebinding_protection_enabled'}
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={t('rebinding_protection_enabled')}
|
||||
subtitle={t('rebinding_protection_enabled_desc')}
|
||||
disabled={processingSetConfig}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{fields.map(renderField)}
|
||||
|
||||
<div className="card-actions">
|
||||
<div className="btn-list">
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-success btn-standard"
|
||||
disabled={submitting || invalid || processingSetConfig}
|
||||
>
|
||||
<Trans>save_config</Trans>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
Form.propTypes = {
|
||||
handleSubmit: PropTypes.func.isRequired,
|
||||
submitting: PropTypes.bool.isRequired,
|
||||
invalid: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default reduxForm({ form: FORM_NAME.REBINDING })(Form);
|
||||
36
client/src/components/Settings/Dns/Rebinding/index.js
Normal file
36
client/src/components/Settings/Dns/Rebinding/index.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import Form from './Form';
|
||||
import Card from '../../../ui/Card';
|
||||
import { setDnsConfig } from '../../../../actions/dnsConfig';
|
||||
|
||||
const RebindingConfig = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
rebinding_protection_enabled, rebinding_allowed_hosts,
|
||||
} = useSelector((state) => state.dnsConfig, shallowEqual);
|
||||
|
||||
const handleFormSubmit = (values) => {
|
||||
dispatch(setDnsConfig(values));
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={t('rebinding_title')}
|
||||
subtitle={t('rebinding_desc')}
|
||||
bodyType="card-body box-body--settings"
|
||||
>
|
||||
<Form
|
||||
initialValues={{
|
||||
rebinding_protection_enabled,
|
||||
rebinding_allowed_hosts,
|
||||
}}
|
||||
onSubmit={handleFormSubmit}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default RebindingConfig;
|
||||
@@ -8,6 +8,7 @@ import Config from './Config';
|
||||
import PageTitle from '../../ui/PageTitle';
|
||||
import Loading from '../../ui/Loading';
|
||||
import CacheConfig from './Cache';
|
||||
import RebindingConfig from './Rebinding';
|
||||
import { getDnsConfig } from '../../../actions/dnsConfig';
|
||||
import { getAccessList } from '../../../actions/access';
|
||||
|
||||
@@ -33,6 +34,7 @@ const Dns = () => {
|
||||
<Config />
|
||||
<CacheConfig />
|
||||
<Access />
|
||||
<RebindingConfig />
|
||||
</>}
|
||||
</>;
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ const CertificateStatus = ({
|
||||
{dnsNames && (
|
||||
<li>
|
||||
<Trans>encryption_hostnames</Trans>:
|
||||
{dnsNames.join(', ')}
|
||||
{dnsNames}
|
||||
</li>
|
||||
)}
|
||||
</Fragment>
|
||||
@@ -65,7 +65,7 @@ CertificateStatus.propTypes = {
|
||||
subject: PropTypes.string,
|
||||
issuer: PropTypes.string,
|
||||
notAfter: PropTypes.string,
|
||||
dnsNames: PropTypes.arrayOf(PropTypes.string),
|
||||
dnsNames: PropTypes.string,
|
||||
};
|
||||
|
||||
export default withTranslation()(CertificateStatus);
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
toNumber,
|
||||
} from '../../../helpers/form';
|
||||
import {
|
||||
validateServerName, validateIsSafePort, validatePort, validatePortQuic, validatePortTLS,
|
||||
validateIsSafePort, validatePort, validatePortQuic, validatePortTLS,
|
||||
} from '../../../helpers/validators';
|
||||
import i18n from '../../../i18n';
|
||||
import KeyStatus from './KeyStatus';
|
||||
@@ -127,7 +127,6 @@ let Form = (props) => {
|
||||
placeholder={t('encryption_server_enter')}
|
||||
onChange={handleChange}
|
||||
disabled={!isEnabled}
|
||||
validate={validateServerName}
|
||||
/>
|
||||
<div className="form__desc">
|
||||
<Trans>encryption_server_desc</Trans>
|
||||
@@ -233,7 +232,7 @@ let Form = (props) => {
|
||||
<Trans
|
||||
values={{ link: 'letsencrypt.org' }}
|
||||
components={[
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://letsencrypt.org/" key="0">
|
||||
<a href="https://letsencrypt.org/" key="0">
|
||||
link
|
||||
</a>,
|
||||
]}
|
||||
@@ -414,7 +413,7 @@ Form.propTypes = {
|
||||
valid_key: PropTypes.bool,
|
||||
valid_cert: PropTypes.bool,
|
||||
valid_pair: PropTypes.bool,
|
||||
dns_names: PropTypes.arrayOf(PropTypes.string),
|
||||
dns_names: PropTypes.string,
|
||||
key_type: PropTypes.string,
|
||||
issuer: PropTypes.string,
|
||||
subject: PropTypes.string,
|
||||
|
||||
@@ -7,7 +7,7 @@ import flow from 'lodash/flow';
|
||||
import { CheckboxField, toNumber } from '../../../helpers/form';
|
||||
import {
|
||||
FILTERS_INTERVALS_HOURS,
|
||||
FILTERS_RELATIVE_LINK,
|
||||
FILTERS_LINK,
|
||||
FORM_NAME,
|
||||
} from '../../../helpers/constants';
|
||||
|
||||
@@ -45,7 +45,7 @@ const Form = (props) => {
|
||||
} = props;
|
||||
|
||||
const components = {
|
||||
a: <a href={FILTERS_RELATIVE_LINK} rel="noopener noreferrer" />,
|
||||
a: <a href={FILTERS_LINK} rel="noopener noreferrer" />,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,50 +6,6 @@ import { useSelector } from 'react-redux';
|
||||
import Topline from './Topline';
|
||||
import { EMPTY_DATE } from '../../helpers/constants';
|
||||
|
||||
const EXPIRATION_ENUM = {
|
||||
VALID: 'VALID',
|
||||
EXPIRED: 'EXPIRED',
|
||||
EXPIRING: 'EXPIRING',
|
||||
};
|
||||
|
||||
const EXPIRATION_STATE = {
|
||||
[EXPIRATION_ENUM.EXPIRED]: {
|
||||
toplineType: 'danger',
|
||||
i18nKey: 'topline_expired_certificate',
|
||||
},
|
||||
[EXPIRATION_ENUM.EXPIRING]: {
|
||||
toplineType: 'warning',
|
||||
i18nKey: 'topline_expiring_certificate',
|
||||
},
|
||||
};
|
||||
|
||||
const getExpirationFlags = (not_after) => {
|
||||
const DAYS_BEFORE_EXPIRATION = 5;
|
||||
|
||||
const now = Date.now();
|
||||
const isExpiring = isAfter(addDays(now, DAYS_BEFORE_EXPIRATION), not_after);
|
||||
const isExpired = isAfter(now, not_after);
|
||||
|
||||
return {
|
||||
isExpiring,
|
||||
isExpired,
|
||||
};
|
||||
};
|
||||
|
||||
const getExpirationEnumKey = (not_after) => {
|
||||
const { isExpiring, isExpired } = getExpirationFlags(not_after);
|
||||
|
||||
if (isExpired) {
|
||||
return EXPIRATION_ENUM.EXPIRED;
|
||||
}
|
||||
|
||||
if (isExpiring) {
|
||||
return EXPIRATION_ENUM.EXPIRING;
|
||||
}
|
||||
|
||||
return EXPIRATION_ENUM.VALID;
|
||||
};
|
||||
|
||||
const EncryptionTopline = () => {
|
||||
const not_after = useSelector((state) => state.encryption.not_after);
|
||||
|
||||
@@ -57,21 +13,30 @@ const EncryptionTopline = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const expirationStateKey = getExpirationEnumKey(not_after);
|
||||
const isAboutExpire = isAfter(addDays(Date.now(), 30), not_after);
|
||||
const isExpired = isAfter(Date.now(), not_after);
|
||||
|
||||
if (expirationStateKey === EXPIRATION_ENUM.VALID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { toplineType, i18nKey } = EXPIRATION_STATE[expirationStateKey];
|
||||
|
||||
return (
|
||||
<Topline type={toplineType}>
|
||||
if (isExpired) {
|
||||
return (
|
||||
<Topline type="danger">
|
||||
<Trans components={[<a href="#encryption" key="0">link</a>]}>
|
||||
{i18nKey}
|
||||
topline_expired_certificate
|
||||
</Trans>
|
||||
</Topline>
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
if (isAboutExpire) {
|
||||
return (
|
||||
<Topline type="warning">
|
||||
<Trans components={[<a href="#encryption" key="0">link</a>]}>
|
||||
topline_expiring_certificate
|
||||
</Trans>
|
||||
</Topline>
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export default EncryptionTopline;
|
||||
|
||||
@@ -11,17 +11,15 @@ const MOBILE_CONFIG_LINKS = {
|
||||
DOT: '/apple/dot.mobileconfig',
|
||||
DOH: '/apple/doh.mobileconfig',
|
||||
};
|
||||
|
||||
/* FIXME: find out `client_id` */
|
||||
const renderMobileconfigInfo = ({ label, components, server_name }) => <li key={label}>
|
||||
<Trans components={components}>{label}</Trans>
|
||||
<ul>
|
||||
<li>
|
||||
<a href={getPathWithQueryString(MOBILE_CONFIG_LINKS.DOT, { host: server_name, client_id: 'client_id' })}
|
||||
<a href={getPathWithQueryString(MOBILE_CONFIG_LINKS.DOT, { host: server_name })}
|
||||
download>{i18next.t('download_mobileconfig_dot')}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={getPathWithQueryString(MOBILE_CONFIG_LINKS.DOH, { host: server_name, client_id: 'client_id' })}
|
||||
<a href={getPathWithQueryString(MOBILE_CONFIG_LINKS.DOH, { host: server_name })}
|
||||
download>{i18next.t('download_mobileconfig_doh')}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -13,10 +13,6 @@ export const R_MAC = /^((([a-fA-F0-9][a-fA-F0-9]+[-]){5}|([a-fA-F0-9][a-fA-F0-9]
|
||||
|
||||
export const R_CIDR_IPV6 = /^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$/;
|
||||
|
||||
export const R_DOMAIN = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/;
|
||||
|
||||
export const R_SERVER_NAME = /^(\*\.)?[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/;
|
||||
|
||||
export const R_PATH_LAST_PART = /\/[^/]*$/;
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
@@ -57,9 +53,9 @@ export const REPOSITORY = {
|
||||
export const PRIVACY_POLICY_LINK = 'https://adguard.com/privacy/home.html';
|
||||
export const PORT_53_FAQ_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#bindinuse';
|
||||
export const UPSTREAM_CONFIGURATION_WIKI_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams';
|
||||
export const GETTING_STARTED_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#update';
|
||||
export const FILTERS_LINK = '#filters';
|
||||
|
||||
export const FILTERS_RELATIVE_LINK = '#filters';
|
||||
export const GETTING_STARTED_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#update';
|
||||
|
||||
export const ADDRESS_IN_USE_TEXT = 'address already in use';
|
||||
|
||||
@@ -345,6 +341,7 @@ export const FILTERED_STATUS = {
|
||||
REWRITE_HOSTS: 'RewriteEtcHosts',
|
||||
FILTERED_SAFE_SEARCH: 'FilteredSafeSearch',
|
||||
FILTERED_SAFE_BROWSING: 'FilteredSafeBrowsing',
|
||||
FILTERED_REBIND: 'FilteredRebind',
|
||||
FILTERED_PARENTAL: 'FilteredParental',
|
||||
};
|
||||
|
||||
@@ -377,6 +374,10 @@ export const RESPONSE_FILTER = {
|
||||
QUERY: 'blocked_parental',
|
||||
LABEL: 'blocked_adult_websites',
|
||||
},
|
||||
BLOCKED_DNS_REBINDING: {
|
||||
QUERY: 'blocked_dns_rebinding',
|
||||
LABEL: 'blocked_dns_rebinding',
|
||||
},
|
||||
ALLOWED: {
|
||||
QUERY: 'whitelisted',
|
||||
LABEL: 'allowed',
|
||||
@@ -418,6 +419,10 @@ export const FILTERED_STATUS_TO_META_MAP = {
|
||||
LABEL: 'blocked_service',
|
||||
COLOR: QUERY_STATUS_COLORS.RED,
|
||||
},
|
||||
[FILTERED_STATUS.FILTERED_REBIND]: {
|
||||
LABEL: RESPONSE_FILTER.BLOCKED_DNS_REBINDING.LABEL,
|
||||
COLOR: QUERY_STATUS_COLORS.RED,
|
||||
},
|
||||
[FILTERED_STATUS.FILTERED_SAFE_SEARCH]: {
|
||||
LABEL: RESPONSE_FILTER.SAFE_SEARCH.LABEL,
|
||||
COLOR: QUERY_STATUS_COLORS.YELLOW,
|
||||
@@ -513,6 +518,7 @@ export const FORM_NAME = {
|
||||
INSTALL: 'install',
|
||||
LOGIN: 'login',
|
||||
CACHE: 'cache',
|
||||
REBINDING: 'rebinding',
|
||||
...DHCP_FORM_NAMES,
|
||||
};
|
||||
|
||||
|
||||
@@ -687,7 +687,7 @@ export const sortIp = (a, b) => {
|
||||
|
||||
return 0;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
console.error(e);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,8 +9,6 @@ import {
|
||||
R_URL_REQUIRES_PROTOCOL,
|
||||
STANDARD_WEB_PORT,
|
||||
UNSAFE_PORTS,
|
||||
R_DOMAIN,
|
||||
R_SERVER_NAME,
|
||||
} from './constants';
|
||||
import { getLastIpv4Octet, isValidAbsolutePath } from './form';
|
||||
|
||||
@@ -73,28 +71,12 @@ export const validateClientId = (value) => {
|
||||
|| R_MAC.test(formattedValue)
|
||||
|| R_CIDR.test(formattedValue)
|
||||
|| R_CIDR_IPV6.test(formattedValue)
|
||||
|| R_DOMAIN.test(formattedValue)
|
||||
)) {
|
||||
return 'form_error_client_id_format';
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param value {string}
|
||||
* @returns {undefined|string}
|
||||
*/
|
||||
export const validateServerName = (value) => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
const formattedValue = value ? value.trim() : value;
|
||||
if (formattedValue && !R_SERVER_NAME.test(formattedValue)) {
|
||||
return 'form_error_server_name';
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param value {string}
|
||||
* @returns {undefined|string}
|
||||
|
||||
@@ -12,7 +12,7 @@ const renderItem = ({
|
||||
|
||||
return <li key={ip}>{isDns
|
||||
? <strong>{dnsAddress}</strong>
|
||||
: <a href={webAddress} target="_blank" rel="noopener noreferrer">{webAddress}</a>
|
||||
: <a href={webAddress}>{webAddress}</a>
|
||||
}
|
||||
</li>;
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@ const dnsConfig = handleActions(
|
||||
blocking_ipv6,
|
||||
upstream_dns,
|
||||
bootstrap_dns,
|
||||
rebinding_allowed_hosts,
|
||||
...values
|
||||
} = payload;
|
||||
|
||||
@@ -24,8 +25,9 @@ const dnsConfig = handleActions(
|
||||
...values,
|
||||
blocking_ipv4: blocking_ipv4 || DEFAULT_BLOCKING_IPV4,
|
||||
blocking_ipv6: blocking_ipv6 || DEFAULT_BLOCKING_IPV6,
|
||||
upstream_dns: (upstream_dns && upstream_dns.join('\n')) || '',
|
||||
bootstrap_dns: (bootstrap_dns && bootstrap_dns.join('\n')) || '',
|
||||
upstream_dns: upstream_dns?.join('\n') || '',
|
||||
bootstrap_dns: bootstrap_dns?.join('\n') || '',
|
||||
rebinding_allowed_hosts: rebinding_allowed_hosts?.join('\n') || '',
|
||||
processingGetConfig: false,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -65,9 +65,3 @@ func (e *manyError) Unwrap() error {
|
||||
|
||||
return e.underlying[0]
|
||||
}
|
||||
|
||||
// wrapper is a copy of the hidden errors.wrapper interface for tests, linting,
|
||||
// etc.
|
||||
type wrapper interface {
|
||||
Unwrap() error
|
||||
}
|
||||
|
||||
@@ -41,8 +41,6 @@ func TestError_Error(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestError_Unwrap(t *testing.T) {
|
||||
var _ wrapper = &manyError{}
|
||||
|
||||
const (
|
||||
errSimple = iota
|
||||
errWrapped
|
||||
|
||||
@@ -129,6 +129,8 @@ const (
|
||||
NotFilteredNotFound Reason = iota
|
||||
// NotFilteredWhiteList - the host is explicitly whitelisted
|
||||
NotFilteredWhiteList
|
||||
// NotFilteredError - there was a transitive error during check
|
||||
NotFilteredError
|
||||
|
||||
// reasons for filtering
|
||||
|
||||
@@ -144,6 +146,8 @@ const (
|
||||
FilteredSafeSearch
|
||||
// FilteredBlockedService - the host is blocked by "blocked services" settings
|
||||
FilteredBlockedService
|
||||
// FilteredRebind - the request was blocked due to DNS rebinding protection
|
||||
FilteredRebind
|
||||
|
||||
// ReasonRewrite - rewrite rule was applied
|
||||
ReasonRewrite
|
||||
@@ -163,6 +167,7 @@ var reasonNames = []string{
|
||||
"FilteredInvalid",
|
||||
"FilteredSafeSearch",
|
||||
"FilteredBlockedService",
|
||||
"FilteredRebind",
|
||||
|
||||
"Rewrite",
|
||||
"RewriteEtcHosts",
|
||||
@@ -775,3 +780,12 @@ func (d *Dnsfilter) Start() {
|
||||
d.registerBlockedServicesHandlers()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// stats
|
||||
//
|
||||
|
||||
// GetStats return dns filtering stats since startup.
|
||||
func (d *Dnsfilter) GetStats() Stats {
|
||||
return gctx.stats
|
||||
}
|
||||
|
||||
@@ -76,6 +76,11 @@ type FilteringConfig struct {
|
||||
CacheMinTTL uint32 `yaml:"cache_ttl_min"` // override TTL value (minimum) received from upstream server
|
||||
CacheMaxTTL uint32 `yaml:"cache_ttl_max"` // override TTL value (maximum) received from upstream server
|
||||
|
||||
// DNS rebinding protection settings
|
||||
// --
|
||||
RebindingProtectionEnabled bool `yaml:"rebinding_protection_enabled"`
|
||||
RebindingAllowedHosts []string `yaml:"rebinding_allowed_hosts"`
|
||||
|
||||
// Other settings
|
||||
// --
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error {
|
||||
processFilteringBeforeRequest,
|
||||
processUpstream,
|
||||
processDNSSECAfterResponse,
|
||||
processRebindingFilteringAfterResponse,
|
||||
processFilteringAfterResponse,
|
||||
s.ipset.process,
|
||||
processQueryLogsAndStats,
|
||||
|
||||
@@ -53,6 +53,7 @@ type Server struct {
|
||||
queryLog querylog.QueryLog // Query log instance
|
||||
stats stats.Stats
|
||||
access *accessCtx
|
||||
rebinding *dnsRebindChecker
|
||||
|
||||
ipset ipsetCtx
|
||||
|
||||
@@ -122,6 +123,7 @@ func (s *Server) WriteDiskConfig(c *FilteringConfig) {
|
||||
c.DisallowedClients = stringArrayDup(sc.DisallowedClients)
|
||||
c.BlockedHosts = stringArrayDup(sc.BlockedHosts)
|
||||
c.UpstreamDNS = stringArrayDup(sc.UpstreamDNS)
|
||||
c.RebindingAllowedHosts = stringArrayDup(sc.RebindingAllowedHosts)
|
||||
s.RUnlock()
|
||||
}
|
||||
|
||||
@@ -221,6 +223,13 @@ func (s *Server) Prepare(config *ServerConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize DNS rebinding module
|
||||
// --
|
||||
s.rebinding, err = newRebindChecker(s.conf.RebindingAllowedHosts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Register web handlers if necessary
|
||||
// --
|
||||
if !webRegistered && s.conf.HTTPRegister != nil {
|
||||
|
||||
@@ -738,6 +738,100 @@ func TestRewrite(t *testing.T) {
|
||||
_ = s.Stop()
|
||||
}
|
||||
|
||||
func TestBlockedDNSRebinding(t *testing.T) {
|
||||
s := createTestServer(t)
|
||||
|
||||
err := s.Start()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start server: %s", err)
|
||||
}
|
||||
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
|
||||
|
||||
//
|
||||
// DNS rebinding protection
|
||||
//
|
||||
req := dns.Msg{}
|
||||
req.Id = dns.Id()
|
||||
req.RecursionDesired = true
|
||||
req.Question = []dns.Question{
|
||||
{Name: "192-168-1-250.nip.io.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
s.conf.RebindingProtectionEnabled = true
|
||||
s.Unlock()
|
||||
|
||||
reply, err := dns.Exchange(&req, addr.String())
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't talk to server %s: %s", addr, err)
|
||||
}
|
||||
|
||||
if len(reply.Answer) != 1 {
|
||||
t.Fatalf("DNS server %s returned reply with wrong number of answers - %d", addr, len(reply.Answer))
|
||||
}
|
||||
|
||||
a, ok := reply.Answer[0].(*dns.A)
|
||||
if !ok {
|
||||
t.Fatalf("DNS server %s returned wrong answer type instead of A: %v", addr, reply.Answer[0])
|
||||
}
|
||||
|
||||
if !net.IPv4zero.Equal(a.A) {
|
||||
t.Fatalf("DNS server %s returned wrong answer instead of 0.0.0.0: %v", addr, a.A)
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
s.conf.RebindingProtectionEnabled = false
|
||||
s.Unlock()
|
||||
|
||||
reply, err = dns.Exchange(&req, addr.String())
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't talk to server %s: %s", addr, err)
|
||||
}
|
||||
|
||||
if len(reply.Answer) != 1 {
|
||||
t.Fatalf("DNS server %s returned reply with wrong number of answers - %d", addr, len(reply.Answer))
|
||||
}
|
||||
|
||||
a, ok = reply.Answer[0].(*dns.A)
|
||||
if !ok {
|
||||
t.Fatalf("DNS server %s returned wrong answer type instead of A: %v", addr, reply.Answer[0])
|
||||
}
|
||||
|
||||
if !net.IPv4(192, 168, 1, 250).Equal(a.A) {
|
||||
t.Fatalf("DNS server %s returned wrong answer instead of 192.168.1.250: %v", addr, a.A)
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
s.conf.RebindingProtectionEnabled = true
|
||||
s.rebinding, _ = newRebindChecker([]string{
|
||||
"||nip.io^",
|
||||
})
|
||||
s.Unlock()
|
||||
|
||||
reply, err = dns.Exchange(&req, addr.String())
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't talk to server %s: %s", addr, err)
|
||||
}
|
||||
|
||||
if len(reply.Answer) != 1 {
|
||||
t.Fatalf("DNS server %s returned reply with wrong number of answers - %d", addr, len(reply.Answer))
|
||||
}
|
||||
|
||||
a, ok = reply.Answer[0].(*dns.A)
|
||||
if !ok {
|
||||
t.Fatalf("DNS server %s returned wrong answer type instead of A: %v", addr, reply.Answer[0])
|
||||
}
|
||||
|
||||
if !net.IPv4(192, 168, 1, 250).Equal(a.A) {
|
||||
t.Fatalf("DNS server %s returned wrong answer instead of 192.168.1.250: %v", addr, a.A)
|
||||
}
|
||||
|
||||
err = s.Stop()
|
||||
if err != nil {
|
||||
t.Fatalf("DNS server failed to stop: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func createTestServer(t *testing.T) *Server {
|
||||
rules := `||nxdomain.example.org
|
||||
||null.example.org^
|
||||
|
||||
@@ -113,8 +113,8 @@ func (s *Server) filterDNSResponse(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||
|
||||
switch v := a.(type) {
|
||||
case *dns.CNAME:
|
||||
log.Debug("DNSFwd: Checking CNAME %s for %s", v.Target, v.Hdr.Name)
|
||||
host = strings.TrimSuffix(v.Target, ".")
|
||||
log.Debug("DNSFwd: Checking CNAME %s for %s", v.Target, v.Hdr.Name)
|
||||
|
||||
case *dns.A:
|
||||
host = v.A.String()
|
||||
|
||||
@@ -37,6 +37,9 @@ type dnsConfig struct {
|
||||
CacheSize *uint32 `json:"cache_size"`
|
||||
CacheMinTTL *uint32 `json:"cache_ttl_min"`
|
||||
CacheMaxTTL *uint32 `json:"cache_ttl_max"`
|
||||
|
||||
RebindingProtectionEnabled *bool `json:"rebinding_protection_enabled"`
|
||||
RebindingAllowedHosts *[]string `json:"rebinding_allowed_hosts"`
|
||||
}
|
||||
|
||||
func (s *Server) getDNSConfig() dnsConfig {
|
||||
@@ -61,23 +64,27 @@ func (s *Server) getDNSConfig() dnsConfig {
|
||||
} else if s.conf.AllServers {
|
||||
upstreamMode = "parallel"
|
||||
}
|
||||
rebindingEnabled := s.conf.RebindingProtectionEnabled
|
||||
rebindingAllowedHosts := stringArrayDup(s.conf.RebindingAllowedHosts)
|
||||
s.RUnlock()
|
||||
return dnsConfig{
|
||||
Upstreams: &upstreams,
|
||||
UpstreamsFile: &upstreamFile,
|
||||
Bootstraps: &bootstraps,
|
||||
ProtectionEnabled: &protectionEnabled,
|
||||
BlockingMode: &blockingMode,
|
||||
BlockingIPv4: &BlockingIPv4,
|
||||
BlockingIPv6: &BlockingIPv6,
|
||||
RateLimit: &Ratelimit,
|
||||
EDNSCSEnabled: &EnableEDNSClientSubnet,
|
||||
DNSSECEnabled: &EnableDNSSEC,
|
||||
DisableIPv6: &AAAADisabled,
|
||||
CacheSize: &CacheSize,
|
||||
CacheMinTTL: &CacheMinTTL,
|
||||
CacheMaxTTL: &CacheMaxTTL,
|
||||
UpstreamMode: &upstreamMode,
|
||||
Upstreams: &upstreams,
|
||||
UpstreamsFile: &upstreamFile,
|
||||
Bootstraps: &bootstraps,
|
||||
ProtectionEnabled: &protectionEnabled,
|
||||
BlockingMode: &blockingMode,
|
||||
BlockingIPv4: &BlockingIPv4,
|
||||
BlockingIPv6: &BlockingIPv6,
|
||||
RateLimit: &Ratelimit,
|
||||
EDNSCSEnabled: &EnableEDNSClientSubnet,
|
||||
DNSSECEnabled: &EnableDNSSEC,
|
||||
DisableIPv6: &AAAADisabled,
|
||||
CacheSize: &CacheSize,
|
||||
CacheMinTTL: &CacheMinTTL,
|
||||
CacheMaxTTL: &CacheMaxTTL,
|
||||
UpstreamMode: &upstreamMode,
|
||||
RebindingProtectionEnabled: &rebindingEnabled,
|
||||
RebindingAllowedHosts: &rebindingAllowedHosts,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +308,8 @@ func (s *Server) setConfig(dc dnsConfig) (restart bool) {
|
||||
s.conf.FastestAddr = false
|
||||
}
|
||||
}
|
||||
|
||||
restart = restart || s.setRebindingConfig(dc)
|
||||
s.Unlock()
|
||||
s.conf.ConfigModified()
|
||||
return restart
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
|
||||
conf: func() ServerConfig {
|
||||
return defaultConf
|
||||
},
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "fastest_addr",
|
||||
conf: func() ServerConfig {
|
||||
@@ -37,7 +37,7 @@ func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
|
||||
conf.FastestAddr = true
|
||||
return conf
|
||||
},
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "parallel",
|
||||
conf: func() ServerConfig {
|
||||
@@ -45,7 +45,7 @@ func TestDNSForwardHTTTP_handleGetConfig(t *testing.T) {
|
||||
conf.AllServers = true
|
||||
return conf
|
||||
},
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
want: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -73,7 +73,7 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
const defaultConfJSON = "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n"
|
||||
const defaultConfJSON = "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n"
|
||||
testCases := []struct {
|
||||
name string
|
||||
req string
|
||||
@@ -83,52 +83,52 @@ func TestDNSForwardHTTTP_handleSetConfig(t *testing.T) {
|
||||
name: "upstream_dns",
|
||||
req: "{\"upstream_dns\":[\"8.8.8.8:77\",\"8.8.4.4:77\"]}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:77\",\"8.8.4.4:77\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:77\",\"8.8.4.4:77\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "bootstraps",
|
||||
req: "{\"bootstrap_dns\":[\"9.9.9.10\"]}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "blocking_mode_good",
|
||||
req: "{\"blocking_mode\":\"refused\"}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"refused\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"refused\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "blocking_mode_bad",
|
||||
req: "{\"blocking_mode\":\"custom_ip\"}",
|
||||
wantSet: "blocking_mode: incorrect value\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "ratelimit",
|
||||
req: "{\"ratelimit\":6}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":6,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":6,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "edns_cs_enabled",
|
||||
req: "{\"edns_cs_enabled\":true}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":true,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":true,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "dnssec_enabled",
|
||||
req: "{\"dnssec_enabled\":true}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":true,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":true,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "cache_size",
|
||||
req: "{\"cache_size\":1024}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":1024,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"\",\"cache_size\":1024,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "upstream_mode_parallel",
|
||||
req: "{\"upstream_mode\":\"parallel\"}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"parallel\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "upstream_mode_fastest_addr",
|
||||
req: "{\"upstream_mode\":\"fastest_addr\"}",
|
||||
wantSet: "",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0}\n",
|
||||
wantGet: "{\"upstream_dns\":[\"8.8.8.8:53\",\"8.8.4.4:53\"],\"upstream_dns_file\":\"\",\"bootstrap_dns\":[\"9.9.9.10\",\"149.112.112.10\",\"2620:fe::10\",\"2620:fe::fe:10\"],\"protection_enabled\":true,\"ratelimit\":0,\"blocking_mode\":\"\",\"blocking_ipv4\":\"\",\"blocking_ipv6\":\"\",\"edns_cs_enabled\":false,\"dnssec_enabled\":false,\"disable_ipv6\":false,\"upstream_mode\":\"fastest_addr\",\"cache_size\":0,\"cache_ttl_min\":0,\"cache_ttl_max\":0,\"rebinding_protection_enabled\":false,\"rebinding_allowed_hosts\":[]}\n",
|
||||
}, {
|
||||
name: "upstream_dns_bad",
|
||||
req: "{\"upstream_dns\":[\"\"]}",
|
||||
|
||||
227
internal/dnsforward/rebind.go
Normal file
227
internal/dnsforward/rebind.go
Normal file
@@ -0,0 +1,227 @@
|
||||
// DNS Rebinding protection
|
||||
|
||||
package dnsforward
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsfilter"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/urlfilter"
|
||||
"github.com/AdguardTeam/urlfilter/filterlist"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type dnsRebindChecker struct {
|
||||
allowDomainEngine *urlfilter.DNSEngine
|
||||
}
|
||||
|
||||
func newRebindChecker(allowedHosts []string) (*dnsRebindChecker, error) {
|
||||
buf := strings.Builder{}
|
||||
for _, s := range allowedHosts {
|
||||
buf.WriteString(s)
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
||||
rulesStorage, err := filterlist.NewRuleStorage([]filterlist.RuleList{
|
||||
&filterlist.StringRuleList{
|
||||
ID: int(0),
|
||||
RulesText: buf.String(),
|
||||
IgnoreCosmetic: true,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dnsRebindChecker{
|
||||
allowDomainEngine: urlfilter.NewDNSEngine(rulesStorage),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *dnsRebindChecker) isAllowedDomain(domain string) bool {
|
||||
_, ok := c.allowDomainEngine.Match(domain)
|
||||
return ok
|
||||
}
|
||||
|
||||
// IsPrivate reports whether ip is a private address, according to
|
||||
// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).
|
||||
func (*dnsRebindChecker) isPrivate(ip net.IP) bool {
|
||||
//TODO: remove once https://github.com/golang/go/pull/42793 makes it to stdlib
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return ip4[0] == 10 ||
|
||||
(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
|
||||
(ip4[0] == 192 && ip4[1] == 168)
|
||||
}
|
||||
return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc
|
||||
}
|
||||
|
||||
func (c *dnsRebindChecker) isRebindHost(host string) bool {
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
return c.isRebindIP(ip)
|
||||
}
|
||||
|
||||
return host == "localhost"
|
||||
}
|
||||
|
||||
func (c *dnsRebindChecker) isLocalNetworkV4(ip4 net.IP) bool {
|
||||
switch {
|
||||
case ip4[0] == 0:
|
||||
/* 0.0.0.0/8 (RFC 5735 section 3. "here" network) */
|
||||
case ip4[0] == 10:
|
||||
/* 10.0.0.0/8 (private) */
|
||||
case ip4[0] == 172 && ip4[1]&0x10 == 0x10:
|
||||
/* 172.16.0.0/12 (private) */
|
||||
case ip4[0] == 169 && ip4[1] == 254:
|
||||
/* 169.254.0.0/16 (zeroconf) */
|
||||
case ip4[0] == 192 && ip4[1] == 0 && ip4[2] == 2:
|
||||
/* 192.0.2.0/24 (test-net) */
|
||||
case ip4[0] == 198 && ip4[1] == 51 && ip4[2] == 100:
|
||||
/* 198.51.100.0/24(test-net) */
|
||||
case ip4[0] == 203 && ip4[1] == 0 && ip4[2] == 113:
|
||||
/* 203.0.113.0/24 (test-net) */
|
||||
case ip4.Equal(net.IPv4bcast):
|
||||
/* 255.255.255.255/32 (broadcast)*/
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *dnsRebindChecker) isLocalNetworkV6(ip6 net.IP) bool {
|
||||
return ip6.Equal(net.IPv6zero) ||
|
||||
ip6.Equal(net.IPv6unspecified) ||
|
||||
ip6.Equal(net.IPv6interfacelocalallnodes) ||
|
||||
ip6.Equal(net.IPv6linklocalallnodes) ||
|
||||
ip6.Equal(net.IPv6linklocalallrouters)
|
||||
}
|
||||
|
||||
func (c *dnsRebindChecker) isRebindIP(ip net.IP) bool {
|
||||
// This is compatible with dnsmasq definition
|
||||
// See: https://github.com/imp/dnsmasq/blob/4e7694d7107d2299f4aaededf8917fceb5dfb924/src/rfc1035.c#L412
|
||||
|
||||
rebind := false
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
rebind = c.isLocalNetworkV4(ip4)
|
||||
} else {
|
||||
rebind = c.isLocalNetworkV6(ip)
|
||||
}
|
||||
|
||||
return rebind || c.isPrivate(ip) || ip.IsLoopback()
|
||||
}
|
||||
|
||||
// Checks DNS rebinding attacks
|
||||
// Note both whitelisted and cached hosts will bypass rebinding check (see: processFilteringAfterResponse()).
|
||||
func (s *Server) isResponseRebind(domain, host string) bool {
|
||||
if !s.conf.RebindingProtectionEnabled {
|
||||
return false
|
||||
}
|
||||
|
||||
if log.GetLevel() >= log.DEBUG {
|
||||
timer := log.StartTimer()
|
||||
defer timer.LogElapsed("DNS Rebinding check for %s -> %s", domain, host)
|
||||
}
|
||||
|
||||
if s.rebinding.isAllowedDomain(domain) {
|
||||
return false
|
||||
}
|
||||
|
||||
return s.rebinding.isRebindHost(host)
|
||||
}
|
||||
|
||||
func processRebindingFilteringAfterResponse(ctx *dnsContext) int {
|
||||
s := ctx.srv
|
||||
d := ctx.proxyCtx
|
||||
res := ctx.result
|
||||
var err error
|
||||
|
||||
if !ctx.responseFromUpstream || res.Reason == dnsfilter.ReasonRewrite {
|
||||
return resultDone
|
||||
}
|
||||
|
||||
originalRes := d.Res
|
||||
ctx.result, err = s.preventRebindResponse(ctx)
|
||||
if err != nil {
|
||||
ctx.err = err
|
||||
return resultError
|
||||
}
|
||||
if ctx.result != nil {
|
||||
ctx.origResp = originalRes // matched by response
|
||||
} else {
|
||||
ctx.result = &dnsfilter.Result{}
|
||||
}
|
||||
|
||||
return resultDone
|
||||
}
|
||||
|
||||
func (s *Server) setRebindingConfig(dc dnsConfig) bool {
|
||||
restart := false
|
||||
|
||||
if dc.RebindingProtectionEnabled != nil {
|
||||
s.conf.RebindingProtectionEnabled = *dc.RebindingProtectionEnabled
|
||||
}
|
||||
|
||||
if dc.RebindingAllowedHosts != nil {
|
||||
s.conf.RebindingAllowedHosts = *dc.RebindingAllowedHosts
|
||||
restart = true
|
||||
}
|
||||
|
||||
return restart
|
||||
}
|
||||
|
||||
func (s *Server) preventRebindResponse(ctx *dnsContext) (*dnsfilter.Result, error) {
|
||||
d := ctx.proxyCtx
|
||||
|
||||
for _, a := range d.Res.Answer {
|
||||
m := ""
|
||||
domainName := ""
|
||||
host := ""
|
||||
|
||||
switch v := a.(type) {
|
||||
case *dns.CNAME:
|
||||
host = strings.TrimSuffix(v.Target, ".")
|
||||
domainName = v.Hdr.Name
|
||||
m = fmt.Sprintf("DNSRebind: Checking CNAME %s for %s", v.Target, v.Hdr.Name)
|
||||
|
||||
case *dns.A:
|
||||
host = v.A.String()
|
||||
domainName = v.Hdr.Name
|
||||
m = fmt.Sprintf("DNSRebind: Checking record A (%s) for %s", host, v.Hdr.Name)
|
||||
|
||||
case *dns.AAAA:
|
||||
host = v.AAAA.String()
|
||||
domainName = v.Hdr.Name
|
||||
m = fmt.Sprintf("DNSRebind: Checking record AAAA (%s) for %s", host, v.Hdr.Name)
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
s.RLock()
|
||||
if !s.conf.RebindingProtectionEnabled {
|
||||
s.RUnlock()
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug(m)
|
||||
blocked := s.isResponseRebind(strings.TrimSuffix(domainName, "."), host)
|
||||
s.RUnlock()
|
||||
|
||||
if blocked {
|
||||
res := &dnsfilter.Result{
|
||||
IsFiltered: true,
|
||||
Reason: dnsfilter.FilteredRebind,
|
||||
Rule: "adguard-rebind-protection",
|
||||
}
|
||||
|
||||
d.Res = s.genDNSFilterMessage(d, res)
|
||||
log.Debug("DNSRebind: Matched %s by response: %s", d.Req.Question[0].Name, host)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
113
internal/dnsforward/rebind_test.go
Normal file
113
internal/dnsforward/rebind_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package dnsforward
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRebindingPrivateAddresses(t *testing.T) {
|
||||
c, _ := newRebindChecker(nil)
|
||||
|
||||
r1 := byte(rand.Int31() & 0xFE)
|
||||
r2 := byte(rand.Int31() & 0xFE)
|
||||
r3 := byte(rand.Int31() & 0xFE)
|
||||
|
||||
for _, ip := range []net.IP{
|
||||
net.IPv4(0, r1, r2, r3), /* 0.0.0.0/8 (RFC 5735 section 3. "here" network) */
|
||||
net.IPv4(127, r1, r2, r3), /* 127.0.0.0/8 (loopback) */
|
||||
net.IPv4(10, r1, r2, r3), /* 10.0.0.0/8 (private) */
|
||||
net.IPv4(172, 0x10|byte(1&rand.Int31()), r2, r3), /* 172.16.0.0/12 (private) */
|
||||
net.IPv4(192, 168, r2, r3), /* 192.168.0.0/16 (private) */
|
||||
net.IPv4(169, 254, r2, r3), /* 169.254.0.0/16 (zeroconf) */
|
||||
net.IPv4(192, 0, 2, r3), /* 192.0.2.0/24 (test-net) */
|
||||
net.IPv4(198, 51, 100, r3), /* 198.51.100.0/24(test-net) */
|
||||
net.IPv4(203, 0, 113, r3), /* 203.0.113.0/24 (test-net) */
|
||||
net.IPv4(255, 255, 255, 255), /* 255.255.255.255/32 (broadcast)*/
|
||||
|
||||
/* RFC 6303 4.3 (unspecified & loopback) */
|
||||
net.IPv6zero,
|
||||
net.IPv6unspecified,
|
||||
|
||||
/* RFC 6303 4.4 */
|
||||
/* RFC 6303 4.5 */
|
||||
/* RFC 6303 4.6 */
|
||||
net.IPv6interfacelocalallnodes,
|
||||
net.IPv6linklocalallnodes,
|
||||
net.IPv6linklocalallrouters,
|
||||
|
||||
/* (TODO) Check IPv4-mapped IPv6 addresses */
|
||||
} {
|
||||
assert.Truef(t, c.isRebindIP(ip), "%s is not a rebind", ip)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRebindLocalhost(t *testing.T) {
|
||||
c := &dnsRebindChecker{}
|
||||
assert.False(t, c.isRebindHost("example.com"))
|
||||
assert.False(t, c.isRebindHost("200.0.0.1"))
|
||||
assert.True(t, c.isRebindHost("127.0.0.1"))
|
||||
assert.True(t, c.isRebindHost("localhost"))
|
||||
}
|
||||
|
||||
func TestIsResponseRebind(t *testing.T) {
|
||||
c, _ := newRebindChecker([]string{
|
||||
"||totally-safe.com^",
|
||||
})
|
||||
s := &Server{
|
||||
rebinding: c,
|
||||
}
|
||||
|
||||
for _, host := range []string{
|
||||
"0.1.2.3", /* 0.0.0.0/8 (RFC 5735 section 3. "here" network) */
|
||||
"127.1.2.3", /* 127.0.0.0/8 (loopback) */
|
||||
"10.1.2.3", /* 10.0.0.0/8 (private) */
|
||||
"172.16.2.3", /* 172.16.0.0/12 (private) */
|
||||
"192.168.2.3", /* 192.168.0.0/16 (private) */
|
||||
"169.254.2.3", /* 169.254.0.0/16 (zeroconf) */
|
||||
"192.0.2.3", /* 192.0.2.0/24 (test-net) */
|
||||
"198.51.100.3", /* 198.51.100.0/24(test-net) */
|
||||
"203.0.113.3", /* 203.0.113.0/24 (test-net) */
|
||||
"255.255.255.255", /* 255.255.255.255/32 (broadcast)*/
|
||||
|
||||
/* RFC 6303 4.3 (unspecified & loopback) */
|
||||
net.IPv6zero.String(),
|
||||
net.IPv6unspecified.String(),
|
||||
|
||||
/* RFC 6303 4.4 */
|
||||
/* RFC 6303 4.5 */
|
||||
/* RFC 6303 4.6 */
|
||||
net.IPv6interfacelocalallnodes.String(),
|
||||
net.IPv6linklocalallnodes.String(),
|
||||
net.IPv6linklocalallrouters.String(),
|
||||
|
||||
"localhost",
|
||||
} {
|
||||
s.conf.RebindingProtectionEnabled = true
|
||||
assert.Truef(t, s.isResponseRebind("example.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("totally-safe.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("absolutely.totally-safe.com", host), "host: %s", host)
|
||||
|
||||
s.conf.RebindingProtectionEnabled = false
|
||||
assert.Falsef(t, s.isResponseRebind("example.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("totally-safe.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("absolutely.totally-safe.com", host), "host: %s", host)
|
||||
}
|
||||
|
||||
for _, host := range []string{
|
||||
"200.168.2.3",
|
||||
"another-example.com",
|
||||
} {
|
||||
s.conf.RebindingProtectionEnabled = true
|
||||
assert.Falsef(t, s.isResponseRebind("example.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("totally-safe.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("absolutely.totally-legit.com", host), "host: %s", host)
|
||||
|
||||
s.conf.RebindingProtectionEnabled = false
|
||||
assert.Falsef(t, s.isResponseRebind("example.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("totally-safe.com", host), "host: %s", host)
|
||||
assert.Falsef(t, s.isResponseRebind("absolutely.totally-legit.com", host), "host: %s", host)
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,15 @@ const (
|
||||
filteringStatusAll = "all"
|
||||
filteringStatusFiltered = "filtered" // all kinds of filtering
|
||||
|
||||
filteringStatusBlocked = "blocked" // blocked or blocked services
|
||||
filteringStatusBlockedService = "blocked_services" // blocked
|
||||
filteringStatusBlockedSafebrowsing = "blocked_safebrowsing" // blocked by safebrowsing
|
||||
filteringStatusBlockedParental = "blocked_parental" // blocked by parental control
|
||||
filteringStatusWhitelisted = "whitelisted" // whitelisted
|
||||
filteringStatusRewritten = "rewritten" // all kinds of rewrites
|
||||
filteringStatusSafeSearch = "safe_search" // enforced safe search
|
||||
filteringStatusProcessed = "processed" // not blocked, not white-listed entries
|
||||
filteringStatusBlocked = "blocked" // blocked or blocked services
|
||||
filteringStatusBlockedService = "blocked_services" // blocked
|
||||
filteringStatusBlockedSafebrowsing = "blocked_safebrowsing" // blocked by safebrowsing
|
||||
filteringStatusBlockedParental = "blocked_parental" // blocked by parental control
|
||||
filteringStatusBlockedRebind = "blocked_dns_rebinding" // blocked by DNS rebinding protection
|
||||
filteringStatusWhitelisted = "whitelisted" // whitelisted
|
||||
filteringStatusRewritten = "rewritten" // all kinds of rewrites
|
||||
filteringStatusSafeSearch = "safe_search" // enforced safe search
|
||||
filteringStatusProcessed = "processed" // not blocked, not white-listed entries
|
||||
)
|
||||
|
||||
// filteringStatusValues -- array with all possible filteringStatus values
|
||||
@@ -32,7 +33,7 @@ var filteringStatusValues = []string{
|
||||
filteringStatusAll, filteringStatusFiltered, filteringStatusBlocked,
|
||||
filteringStatusBlockedService, filteringStatusBlockedSafebrowsing, filteringStatusBlockedParental,
|
||||
filteringStatusWhitelisted, filteringStatusRewritten, filteringStatusSafeSearch,
|
||||
filteringStatusProcessed,
|
||||
filteringStatusProcessed, filteringStatusBlockedRebind,
|
||||
}
|
||||
|
||||
// searchCriteria - every search request may contain a list of different search criteria
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
package sysutil
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log/syslog"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
func configureSyslog(serviceName string) error {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
package sysutil
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
)
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
module github.com/AdguardTeam/AdGuardHome/internal/tools
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 // indirect
|
||||
github.com/client9/misspell v0.3.4 // indirect
|
||||
github.com/fzipp/gocyclo v0.3.1
|
||||
github.com/golangci/misspell v0.3.5
|
||||
github.com/google/go-cmp v0.5.4 // indirect
|
||||
github.com/gookit/color v1.3.3 // indirect
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063
|
||||
github.com/kisielk/errcheck v1.4.0
|
||||
github.com/kyoh86/looppointer v0.1.7
|
||||
github.com/kyoh86/nolint v0.0.1 // indirect
|
||||
github.com/securego/gosec/v2 v2.5.0
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b
|
||||
golang.org/x/mod v0.4.0 // indirect
|
||||
golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
honnef.co/go/tools v0.0.1-2020.1.6
|
||||
mvdan.cc/gofumpt v0.0.0-20201129102820-5c11c50e9475
|
||||
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7
|
||||
)
|
||||
@@ -1,164 +0,0 @@
|
||||
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 h1:o4lAkfETerCnr1kF9/qwkwjICnU+YLHNDCM8h2xj7as=
|
||||
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363/go.mod h1:WG7q7swWsS2f9PYpt5DoEP/EBYWx8We5UoRltn9vJl8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc=
|
||||
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo=
|
||||
github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/gookit/color v1.3.1 h1:PPD/C7sf8u2L8XQPdPgsWRoAiLQGZEZOzU3cf5IYYUk=
|
||||
github.com/gookit/color v1.3.1/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ=
|
||||
github.com/gookit/color v1.3.3 h1:6IAwxWCdABGNc4gI+YFBMYw0Hz8g5+lpYeKRAaALQoQ=
|
||||
github.com/gookit/color v1.3.3/go.mod h1:GqqLKF1le3EfrbHbYsYa5WdLqfc/PHMdMRbt6tMnqIc=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063 h1:dKprcOvlsvqfWn/iGvz+oYuC2axESeSMuF8dDrWMNsE=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/kisielk/errcheck v1.4.0 h1:ueN6QYA+c7eDQo7ebpNdYR8mUJZThiGz9PEoJEMGPzA=
|
||||
github.com/kisielk/errcheck v1.4.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kyoh86/looppointer v0.1.7 h1:q5sZOhFvmvQ6ZoZxvPB/Mjj2croWX7L49BBuI4XQWCM=
|
||||
github.com/kyoh86/looppointer v0.1.7/go.mod h1:l0cRF49N6xDPx8IuBGC/imZo8Yn1BBLJY0vzI+4fepc=
|
||||
github.com/kyoh86/nolint v0.0.0-20200711045849-7a7b0d649b7a h1:WKwgzTn8xp2JuhOUsTbi+h+QygLZSfVGwaYZUejGMMw=
|
||||
github.com/kyoh86/nolint v0.0.0-20200711045849-7a7b0d649b7a/go.mod h1:hPeUNhNOZ22wXzQKMzeYKXVFTBjJ9czxjeIDyI1ueVM=
|
||||
github.com/kyoh86/nolint v0.0.1 h1:GjNxDEkVn2wAxKHtP7iNTrRxytRZ1wXxLV5j4XzGfRU=
|
||||
github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ewq9gtI=
|
||||
github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
|
||||
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
|
||||
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0=
|
||||
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/securego/gosec/v2 v2.5.0 h1:kjfXLeKdk98gBe2+eYRFMpC4+mxmQQtbidpiiOQ69Qc=
|
||||
github.com/securego/gosec/v2 v2.5.0/go.mod h1:L/CDXVntIff5ypVHIkqPXbtRpJiNCh6c6Amn68jXDjo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7 h1:2OSu5vYyX4LVqZAtqZXnFEcN26SDKIJYlEVIRl1tj8U=
|
||||
golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc=
|
||||
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
|
||||
mvdan.cc/gofumpt v0.0.0-20201129102820-5c11c50e9475 h1:5ZmJGYyuTlhdlIpRxSFhdJqkXQweXETFCEaLhRAX3e8=
|
||||
mvdan.cc/gofumpt v0.0.0-20201129102820-5c11c50e9475/go.mod h1:E4LOcu9JQEtnYXtB1Y51drqh2Qr2Ngk9J3YrRCwcbd0=
|
||||
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7 h1:kAREL6MPwpsk1/PQPFD3Eg7WAQR5mPTWZJaBiG5LDbY=
|
||||
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc=
|
||||
@@ -1,22 +0,0 @@
|
||||
// +build tools
|
||||
|
||||
// Package tools and its main module are a nested internal module containing our
|
||||
// development tool dependencies.
|
||||
//
|
||||
// See https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module.
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "github.com/fzipp/gocyclo/cmd/gocyclo"
|
||||
_ "github.com/golangci/misspell/cmd/misspell"
|
||||
_ "github.com/gordonklaus/ineffassign"
|
||||
_ "github.com/kisielk/errcheck"
|
||||
_ "github.com/kyoh86/looppointer"
|
||||
_ "github.com/securego/gosec/v2/cmd/gosec"
|
||||
_ "golang.org/x/lint/golint"
|
||||
_ "golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness"
|
||||
_ "golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow"
|
||||
_ "honnef.co/go/tools/cmd/staticcheck"
|
||||
_ "mvdan.cc/gofumpt/gofumports"
|
||||
_ "mvdan.cc/unparam"
|
||||
)
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
@@ -40,6 +41,13 @@ func RunCommand(command string, arguments ...string) (int, string, error) {
|
||||
return cmd.ProcessState.ExitCode(), string(out), nil
|
||||
}
|
||||
|
||||
func FuncName() string {
|
||||
pc := make([]uintptr, 10) // at least 1 entry needed
|
||||
runtime.Callers(2, pc)
|
||||
f := runtime.FuncForPC(pc[0])
|
||||
return path.Base(f.Name())
|
||||
}
|
||||
|
||||
// SplitNext - split string by a byte and return the first chunk
|
||||
// Skip empty chunks
|
||||
// Whitespace is trimmed
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -18,6 +19,6 @@ func TestGetValidNetInterfacesForWeb(t *testing.T) {
|
||||
t.Fatalf("No addresses found for %s", iface.Name)
|
||||
}
|
||||
|
||||
t.Logf("%v", iface)
|
||||
log.Printf("%v", iface)
|
||||
}
|
||||
}
|
||||
@@ -190,6 +190,7 @@
|
||||
- 'blocked'
|
||||
- 'blocked_safebrowsing'
|
||||
- 'blocked_parental'
|
||||
- 'blocked_dns_rebinding'
|
||||
- 'whitelisted'
|
||||
- 'rewritten'
|
||||
- 'safe_search'
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
test "$VERBOSE" = '1' && set -x
|
||||
set -e -f -u
|
||||
|
||||
# TODO(a.garipov): Add goconst?
|
||||
|
||||
env GOBIN="${PWD}/bin" "$GO" install --modfile=./internal/tools/go.mod\
|
||||
github.com/fzipp/gocyclo/cmd/gocyclo\
|
||||
github.com/golangci/misspell/cmd/misspell\
|
||||
github.com/gordonklaus/ineffassign\
|
||||
github.com/kisielk/errcheck\
|
||||
github.com/kyoh86/looppointer/cmd/looppointer\
|
||||
github.com/securego/gosec/v2/cmd/gosec\
|
||||
golang.org/x/lint/golint\
|
||||
golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness\
|
||||
golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow\
|
||||
honnef.co/go/tools/cmd/staticcheck\
|
||||
mvdan.cc/gofumpt\
|
||||
mvdan.cc/unparam\
|
||||
;
|
||||
@@ -1,115 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Verbosity levels:
|
||||
# 0 = Don't print anything except for errors.
|
||||
# 1 = Print commands, but not nested commands.
|
||||
# 2 = Print everything.
|
||||
test "${VERBOSE:=0}" -gt '0' && set -x
|
||||
|
||||
# Set $EXITONERROR to zero to see all errors.
|
||||
test "${EXITONERROR:=1}" = '0' && set +e || set -e
|
||||
|
||||
# We don't need glob expansions and we want to see errors about unset
|
||||
# variables.
|
||||
set -f -u
|
||||
|
||||
not_found_msg='
|
||||
looks like a binary not found error.
|
||||
make sure you have installed the linter binaries using:
|
||||
|
||||
$ make go-install-tools
|
||||
'
|
||||
|
||||
not_found() {
|
||||
if [ "$?" = '127' ]
|
||||
then
|
||||
# Code 127 is the exit status a shell uses when
|
||||
# a command or a file is not found, according to the
|
||||
# Bash Hackers wiki.
|
||||
#
|
||||
# See https://wiki.bash-hackers.org/dict/terms/exit_status.
|
||||
echo "$not_found_msg" 1>&2
|
||||
fi
|
||||
}
|
||||
trap not_found EXIT
|
||||
|
||||
# blocklist_imports is a simple check against unwanted packages.
|
||||
# Currently it only looks for package log which is replaced by our own
|
||||
# package github.com/AdguardTeam/golibs/log.
|
||||
blocklist_imports() {
|
||||
git grep -F -e '"log"' -- '*.go' || exit 0;
|
||||
}
|
||||
|
||||
# underscores is a simple check against Go filenames with underscores.
|
||||
underscores() {
|
||||
git ls-files '*_*.go' | { grep -F -e '_darwin.go' \
|
||||
-e '_freebsd.go' -e '_linux.go' -e '_others.go' \
|
||||
-e '_test.go' -e '_unix.go' -e '_windows.go' \
|
||||
-v || exit 0; }
|
||||
}
|
||||
|
||||
# exit_on_output exits with a nonzero exit code if there is anything in
|
||||
# the command's combined output.
|
||||
exit_on_output() {
|
||||
test "$VERBOSE" -lt '2' && set +x
|
||||
|
||||
cmd="$1"
|
||||
shift
|
||||
|
||||
exitcode='0'
|
||||
output="$("$cmd" "$@" 2>&1)"
|
||||
if [ "$output" != '' ]
|
||||
then
|
||||
if [ "$*" != '' ]
|
||||
then
|
||||
echo "combined output of '$cmd $@':"
|
||||
else
|
||||
echo "combined output of '$cmd':"
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
|
||||
exitcode='1'
|
||||
fi
|
||||
|
||||
test "$VERBOSE" -gt '0' && set -x
|
||||
|
||||
return "$exitcode"
|
||||
}
|
||||
|
||||
exit_on_output blocklist_imports
|
||||
|
||||
exit_on_output underscores
|
||||
|
||||
exit_on_output gofumpt --extra -l -s .
|
||||
|
||||
golint --set_exit_status ./...
|
||||
|
||||
"$GO" vet ./...
|
||||
|
||||
gocyclo --over 20 .
|
||||
|
||||
gosec --quiet .
|
||||
|
||||
ineffassign .
|
||||
|
||||
unparam ./...
|
||||
|
||||
misspell --error ./...
|
||||
|
||||
looppointer ./...
|
||||
|
||||
nilness ./...
|
||||
|
||||
# TODO(a.garipov): Enable shadow after fixing all of the shadowing.
|
||||
# shadow --strict ./...
|
||||
|
||||
# TODO(a.garipov): Enable errcheck fully after handling all errors,
|
||||
# including the deferred ones, properly. Also, perhaps, enable --blank.
|
||||
# errcheck ./...
|
||||
exit_on_output sh -c '
|
||||
errcheck --asserts ./... |\
|
||||
{ grep -e "defer" -e "_test\.go:" -v || exit 0; }
|
||||
'
|
||||
|
||||
staticcheck --checks='all' ./...
|
||||
Reference in New Issue
Block a user