BREAKING CHANGE: Die alte Shell-Version muss vor der Installation der Go-Version deinstalliert werden.
643 lines
16 KiB
Go
643 lines
16 KiB
Go
package installer
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
DefaultInstallDir = "/opt/adguard-shield"
|
|
DefaultStateDir = "/var/lib/adguard-shield"
|
|
DefaultLogFile = "/var/log/adguard-shield.log"
|
|
ServiceName = "adguard-shield.service"
|
|
ServicePath = "/etc/systemd/system/adguard-shield.service"
|
|
)
|
|
|
|
type Options struct {
|
|
InstallDir string
|
|
ConfigSource string
|
|
Enable bool
|
|
SkipDeps bool
|
|
KeepConfig bool
|
|
}
|
|
|
|
type Status struct {
|
|
InstallDir string
|
|
BinaryPath string
|
|
ConfigPath string
|
|
BinaryExists bool
|
|
ConfigExists bool
|
|
ServiceExists bool
|
|
ServiceEnabled bool
|
|
ServiceActive bool
|
|
Version string
|
|
LegacyFindings []string
|
|
}
|
|
|
|
type LegacyError struct {
|
|
Findings []string
|
|
}
|
|
|
|
func (e *LegacyError) Error() string {
|
|
return "scriptbasierte AdGuard-Shield-Installation gefunden"
|
|
}
|
|
|
|
func DefaultOptions() Options {
|
|
return Options{InstallDir: DefaultInstallDir, Enable: true}
|
|
}
|
|
|
|
func Install(opts Options) error {
|
|
opts = normalize(opts)
|
|
fmt.Println("AdGuard Shield Go-Installation")
|
|
fmt.Printf("Installationspfad: %s\n", opts.InstallDir)
|
|
fmt.Println("1/8 Pruefe Betriebssystem und root-Rechte ...")
|
|
if err := requireLinuxRoot(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("2/8 Pruefe auf scriptbasierte Altinstallation ...")
|
|
if findings := DetectLegacy(opts.InstallDir); len(findings) > 0 {
|
|
return &LegacyError{Findings: findings}
|
|
}
|
|
if !opts.SkipDeps {
|
|
fmt.Println("3/8 Pruefe System-Abhaengigkeiten ...")
|
|
if err := ensureDependencies(); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
fmt.Println("3/8 System-Abhaengigkeiten uebersprungen (--skip-deps)")
|
|
}
|
|
fmt.Println("4/8 Erstelle Verzeichnisse ...")
|
|
if err := os.MkdirAll(opts.InstallDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
if err := os.MkdirAll(DefaultStateDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
if err := os.MkdirAll(filepath.Join(opts.InstallDir, "geoip"), 0755); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("5/8 Installiere Binary ...")
|
|
if err := copySelf(filepath.Join(opts.InstallDir, "adguard-shield")); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("6/8 Installiere oder migriere Konfiguration ...")
|
|
if err := ensureConfig(opts); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("7/8 Schreibe systemd-Service ...")
|
|
if err := writeService(opts.InstallDir); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("8/8 Aktualisiere systemd ...")
|
|
_ = run("systemctl", "daemon-reload")
|
|
if opts.Enable {
|
|
fmt.Println("Aktiviere Autostart ...")
|
|
if err := run("systemctl", "enable", ServiceName); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if askStartService() {
|
|
fmt.Println("Starte Service neu ...")
|
|
if err := run("systemctl", "restart", ServiceName); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
fmt.Println("Installation fertig.")
|
|
return nil
|
|
}
|
|
|
|
func Update(opts Options) error {
|
|
opts = normalize(opts)
|
|
if err := requireLinuxRoot(); err != nil {
|
|
return err
|
|
}
|
|
if findings := DetectLegacy(opts.InstallDir); len(findings) > 0 {
|
|
return &LegacyError{Findings: findings}
|
|
}
|
|
return Install(opts)
|
|
}
|
|
|
|
func Uninstall(opts Options) error {
|
|
opts = normalize(opts)
|
|
if err := requireLinuxRoot(); err != nil {
|
|
return err
|
|
}
|
|
_ = run("systemctl", "stop", ServiceName)
|
|
_ = run("systemctl", "disable", ServiceName)
|
|
if _, err := os.Stat(filepath.Join(opts.InstallDir, "adguard-shield")); err == nil {
|
|
_ = run(filepath.Join(opts.InstallDir, "adguard-shield"), "-config", filepath.Join(opts.InstallDir, "adguard-shield.conf"), "firewall-remove")
|
|
}
|
|
_ = os.Remove(ServicePath)
|
|
_ = run("systemctl", "daemon-reload")
|
|
if opts.KeepConfig {
|
|
for _, p := range []string{
|
|
filepath.Join(opts.InstallDir, "adguard-shield"),
|
|
filepath.Join(opts.InstallDir, "adguard-shield.conf.old"),
|
|
} {
|
|
_ = os.Remove(p)
|
|
}
|
|
return nil
|
|
}
|
|
_ = os.RemoveAll(opts.InstallDir)
|
|
_ = os.RemoveAll(DefaultStateDir)
|
|
_ = os.Remove(DefaultLogFile)
|
|
return nil
|
|
}
|
|
|
|
func GetStatus(installDir string) Status {
|
|
if installDir == "" {
|
|
installDir = DefaultInstallDir
|
|
}
|
|
bin := filepath.Join(installDir, "adguard-shield")
|
|
conf := filepath.Join(installDir, "adguard-shield.conf")
|
|
st := Status{
|
|
InstallDir: installDir,
|
|
BinaryPath: bin,
|
|
ConfigPath: conf,
|
|
BinaryExists: fileExists(bin),
|
|
ConfigExists: fileExists(conf),
|
|
ServiceExists: fileExists(ServicePath),
|
|
LegacyFindings: DetectLegacy(installDir),
|
|
}
|
|
if st.BinaryExists {
|
|
if out, err := exec.Command(bin, "version").Output(); err == nil {
|
|
st.Version = strings.TrimSpace(string(out))
|
|
}
|
|
}
|
|
st.ServiceEnabled = commandOK("systemctl", "is-enabled", "adguard-shield")
|
|
st.ServiceActive = commandOK("systemctl", "is-active", "adguard-shield")
|
|
return st
|
|
}
|
|
|
|
func DetectLegacy(installDir string) []string {
|
|
if installDir == "" {
|
|
installDir = DefaultInstallDir
|
|
}
|
|
var findings []string
|
|
for _, p := range []string{
|
|
"adguard-shield.sh",
|
|
"iptables-helper.sh",
|
|
"db.sh",
|
|
"external-blocklist-worker.sh",
|
|
"external-whitelist-worker.sh",
|
|
"geoip-worker.sh",
|
|
"offense-cleanup-worker.sh",
|
|
"report-generator.sh",
|
|
"unban-expired.sh",
|
|
"adguard-shield-watchdog.sh",
|
|
} {
|
|
full := filepath.Join(installDir, p)
|
|
if fileExists(full) {
|
|
findings = append(findings, full)
|
|
}
|
|
}
|
|
for _, p := range []string{
|
|
"/etc/systemd/system/adguard-shield-watchdog.service",
|
|
"/etc/systemd/system/adguard-shield-watchdog.timer",
|
|
} {
|
|
if fileExists(p) {
|
|
findings = append(findings, p)
|
|
}
|
|
}
|
|
if b, err := os.ReadFile(ServicePath); err == nil {
|
|
s := string(b)
|
|
if strings.Contains(s, ".sh") || strings.Contains(s, "/bin/bash") || strings.Contains(s, "adguard-shield-watchdog") {
|
|
findings = append(findings, ServicePath+" verweist auf Shell/Watchdog")
|
|
}
|
|
}
|
|
sort.Strings(findings)
|
|
return findings
|
|
}
|
|
|
|
func FormatLegacyMessage(err *LegacyError, installDir string) string {
|
|
if installDir == "" {
|
|
installDir = DefaultInstallDir
|
|
}
|
|
var b strings.Builder
|
|
b.WriteString("Die scriptbasierte Installation ist noch vorhanden und muss zuerst deinstalliert werden.\n\n")
|
|
b.WriteString("Gefunden:\n")
|
|
for _, f := range err.Findings {
|
|
b.WriteString(" - ")
|
|
b.WriteString(f)
|
|
b.WriteByte('\n')
|
|
}
|
|
b.WriteString("\nKonfiguration uebernehmen:\n")
|
|
b.WriteString(" 1. Backup behalten: ")
|
|
b.WriteString(filepath.Join(installDir, "adguard-shield.conf"))
|
|
b.WriteByte('\n')
|
|
b.WriteString(" 2. Alte Shell-Version mit deren uninstall.sh entfernen und die Konfiguration behalten.\n")
|
|
b.WriteString(" 3. Danach dieses Binary erneut ausfuehren: adguard-shield install\n")
|
|
return b.String()
|
|
}
|
|
|
|
func PrintStatus(st Status) string {
|
|
var b strings.Builder
|
|
b.WriteString("AdGuard Shield Installationsstatus\n")
|
|
b.WriteString(fmt.Sprintf("Installationspfad: %s\n", st.InstallDir))
|
|
b.WriteString(fmt.Sprintf("Binary: %s\n", yesNo(st.BinaryExists)))
|
|
if st.Version != "" {
|
|
b.WriteString(fmt.Sprintf("Version: %s\n", st.Version))
|
|
}
|
|
b.WriteString(fmt.Sprintf("Konfiguration: %s\n", yesNo(st.ConfigExists)))
|
|
b.WriteString(fmt.Sprintf("systemd Service: %s\n", yesNo(st.ServiceExists)))
|
|
b.WriteString(fmt.Sprintf("Autostart: %s\n", yesNo(st.ServiceEnabled)))
|
|
b.WriteString(fmt.Sprintf("Service aktiv: %s\n", yesNo(st.ServiceActive)))
|
|
if len(st.LegacyFindings) > 0 {
|
|
b.WriteString("\nScriptbasierte Altinstallation/Altartefakte gefunden:\n")
|
|
for _, f := range st.LegacyFindings {
|
|
b.WriteString(" - ")
|
|
b.WriteString(f)
|
|
b.WriteByte('\n')
|
|
}
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func normalize(opts Options) Options {
|
|
if opts.InstallDir == "" {
|
|
opts.InstallDir = DefaultInstallDir
|
|
}
|
|
return opts
|
|
}
|
|
|
|
func askStartService() bool {
|
|
fmt.Print("AdGuard Shield jetzt (neu) starten? [j/N] ")
|
|
line, err := bufio.NewReader(os.Stdin).ReadString('\n')
|
|
if err != nil && len(line) == 0 {
|
|
fmt.Println("Keine Eingabe gelesen, Service wird nicht gestartet.")
|
|
return false
|
|
}
|
|
switch strings.ToLower(strings.TrimSpace(line)) {
|
|
case "j", "ja", "y", "yes":
|
|
return true
|
|
default:
|
|
fmt.Println("Service wird nicht gestartet.")
|
|
return false
|
|
}
|
|
}
|
|
|
|
func requireLinuxRoot() error {
|
|
if runtime.GOOS != "linux" {
|
|
return fmt.Errorf("Installation ist nur auf Linux-Servern unterstuetzt")
|
|
}
|
|
if os.Geteuid() != 0 {
|
|
return fmt.Errorf("Installation muss als root ausgefuehrt werden")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ensureDependencies() error {
|
|
missing := missingCommands("iptables", "ip6tables", "ipset", "systemctl")
|
|
if len(missing) == 0 {
|
|
fmt.Println(" Alle benoetigten Befehle sind vorhanden.")
|
|
return nil
|
|
}
|
|
fmt.Printf(" Fehlende Befehle: %s\n", strings.Join(missing, ", "))
|
|
if _, err := exec.LookPath("apt-get"); err != nil {
|
|
return fmt.Errorf("fehlende Abhaengigkeiten (%s), apt-get nicht gefunden", strings.Join(missing, ", "))
|
|
}
|
|
pkgs := map[string]bool{"iptables": false, "ipset": false, "systemd": false, "ca-certificates": false}
|
|
for _, m := range missing {
|
|
switch m {
|
|
case "iptables", "ip6tables":
|
|
pkgs["iptables"] = true
|
|
case "ipset":
|
|
pkgs["ipset"] = true
|
|
case "systemctl":
|
|
pkgs["systemd"] = true
|
|
}
|
|
}
|
|
var install []string
|
|
for p, needed := range pkgs {
|
|
if needed || p == "ca-certificates" {
|
|
install = append(install, p)
|
|
}
|
|
}
|
|
sort.Strings(install)
|
|
fmt.Printf(" Installiere Pakete via apt-get: %s\n", strings.Join(install, ", "))
|
|
fmt.Println(" apt-get update ...")
|
|
if err := runStreaming("apt-get", "update"); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(" apt-get install ...")
|
|
args := append([]string{"install", "-y", "-qq"}, install...)
|
|
return runStreaming("apt-get", args...)
|
|
}
|
|
|
|
func missingCommands(names ...string) []string {
|
|
var missing []string
|
|
for _, name := range names {
|
|
if _, err := exec.LookPath(name); err != nil {
|
|
missing = append(missing, name)
|
|
}
|
|
}
|
|
return missing
|
|
}
|
|
|
|
func copySelf(dst string) error {
|
|
src, err := os.Executable()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if sameFile(src, dst) {
|
|
return os.Chmod(dst, 0755)
|
|
}
|
|
in, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer in.Close()
|
|
tmp := dst + ".tmp"
|
|
out, err := os.OpenFile(tmp, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := io.Copy(out, in); err != nil {
|
|
_ = out.Close()
|
|
return err
|
|
}
|
|
if err := out.Close(); err != nil {
|
|
return err
|
|
}
|
|
if err := os.Chmod(tmp, 0755); err != nil {
|
|
return err
|
|
}
|
|
return os.Rename(tmp, dst)
|
|
}
|
|
|
|
func sameFile(a, b string) bool {
|
|
aa, errA := filepath.Abs(a)
|
|
bb, errB := filepath.Abs(b)
|
|
if errA == nil && errB == nil && aa == bb {
|
|
return true
|
|
}
|
|
ai, errA := os.Stat(a)
|
|
bi, errB := os.Stat(b)
|
|
return errA == nil && errB == nil && os.SameFile(ai, bi)
|
|
}
|
|
|
|
func ensureConfig(opts Options) error {
|
|
target := filepath.Join(opts.InstallDir, "adguard-shield.conf")
|
|
defaults := []byte(defaultConfig)
|
|
if opts.ConfigSource != "" {
|
|
b, err := os.ReadFile(opts.ConfigSource)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defaults = b
|
|
}
|
|
if !fileExists(target) {
|
|
if err := os.WriteFile(target, defaults, 0600); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
current, err := os.ReadFile(target)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
merged, changed := mergeConfig(current, []byte(defaultConfig))
|
|
if !changed {
|
|
return os.Chmod(target, 0600)
|
|
}
|
|
if err := os.WriteFile(target+".old", current, 0600); err != nil {
|
|
return err
|
|
}
|
|
if err := os.WriteFile(target, merged, 0600); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func mergeConfig(current, defaults []byte) ([]byte, bool) {
|
|
existing := configKeys(current)
|
|
var add [][]byte
|
|
for _, block := range configBlocks(defaults) {
|
|
key := blockKey(block)
|
|
if key == "" || existing[key] {
|
|
continue
|
|
}
|
|
add = append(add, block)
|
|
}
|
|
if len(add) == 0 {
|
|
return current, false
|
|
}
|
|
out := bytes.TrimRight(current, "\r\n")
|
|
out = append(out, '\n', '\n')
|
|
out = append(out, []byte("# Neue Parameter aus der Go-Version\n")...)
|
|
for _, block := range add {
|
|
out = append(out, bytes.Trim(block, "\r\n")...)
|
|
out = append(out, '\n')
|
|
}
|
|
return out, true
|
|
}
|
|
|
|
func configKeys(data []byte) map[string]bool {
|
|
keys := map[string]bool{}
|
|
for _, line := range bytes.Split(data, []byte{'\n'}) {
|
|
line = bytes.TrimSpace(line)
|
|
if len(line) == 0 || line[0] == '#' {
|
|
continue
|
|
}
|
|
if i := bytes.IndexByte(line, '='); i > 0 {
|
|
keys[string(bytes.TrimSpace(line[:i]))] = true
|
|
}
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func configBlocks(data []byte) [][]byte {
|
|
lines := bytes.Split(data, []byte{'\n'})
|
|
var blocks [][]byte
|
|
var comments [][]byte
|
|
for _, line := range lines {
|
|
trim := bytes.TrimSpace(line)
|
|
if len(trim) == 0 || trim[0] == '#' {
|
|
comments = append(comments, append([]byte(nil), line...))
|
|
continue
|
|
}
|
|
block := bytes.Join(append(comments, line), []byte{'\n'})
|
|
blocks = append(blocks, block)
|
|
comments = nil
|
|
}
|
|
return blocks
|
|
}
|
|
|
|
func blockKey(block []byte) string {
|
|
for _, line := range bytes.Split(block, []byte{'\n'}) {
|
|
line = bytes.TrimSpace(line)
|
|
if len(line) == 0 || line[0] == '#' {
|
|
continue
|
|
}
|
|
if i := bytes.IndexByte(line, '='); i > 0 {
|
|
return string(bytes.TrimSpace(line[:i]))
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func writeService(installDir string) error {
|
|
service := fmt.Sprintf(`[Unit]
|
|
Description=AdGuard Shield - Go DNS Rate-Limit Monitor
|
|
After=network.target AdGuardHome.service
|
|
Wants=AdGuardHome.service
|
|
StartLimitBurst=5
|
|
StartLimitIntervalSec=300
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=%s/adguard-shield -config %s/adguard-shield.conf run
|
|
ExecReload=/bin/kill -HUP $MAINPID
|
|
Restart=on-failure
|
|
RestartSec=30
|
|
ProtectSystem=full
|
|
ReadWritePaths=/var/log /var/lib/adguard-shield /var/run %s/geoip
|
|
ProtectHome=true
|
|
NoNewPrivileges=false
|
|
PrivateTmp=true
|
|
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
|
|
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_KILL CAP_SETUID CAP_SETGID CAP_CHOWN
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
SyslogIdentifier=adguard-shield
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`, installDir, installDir, installDir)
|
|
return os.WriteFile(ServicePath, []byte(service), 0644)
|
|
}
|
|
|
|
func run(name string, args ...string) error {
|
|
cmd := exec.Command(name, args...)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("%s %s: %w\n%s", name, strings.Join(args, " "), err, strings.TrimSpace(string(out)))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func runStreaming(name string, args ...string) error {
|
|
cmd := exec.Command(name, args...)
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("%s %s: %w", name, strings.Join(args, " "), err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func commandOK(name string, args ...string) bool {
|
|
return exec.Command(name, args...).Run() == nil
|
|
}
|
|
|
|
func fileExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil
|
|
}
|
|
|
|
func yesNo(ok bool) string {
|
|
if ok {
|
|
return "ja"
|
|
}
|
|
return "nein"
|
|
}
|
|
|
|
func IsLegacyError(err error) (*LegacyError, bool) {
|
|
var le *LegacyError
|
|
if errors.As(err, &le) {
|
|
return le, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
const defaultConfig = `# AdGuard Shield Konfiguration
|
|
|
|
ADGUARD_URL="https://dns1.domain.com"
|
|
ADGUARD_USER="admin"
|
|
ADGUARD_PASS='changeme'
|
|
|
|
RATE_LIMIT_MAX_REQUESTS=30
|
|
RATE_LIMIT_WINDOW=60
|
|
CHECK_INTERVAL=10
|
|
API_QUERY_LIMIT=500
|
|
|
|
SUBDOMAIN_FLOOD_ENABLED=true
|
|
SUBDOMAIN_FLOOD_MAX_UNIQUE=50
|
|
SUBDOMAIN_FLOOD_WINDOW=60
|
|
|
|
DNS_FLOOD_WATCHLIST_ENABLED=false
|
|
DNS_FLOOD_WATCHLIST=""
|
|
|
|
BAN_DURATION=3600
|
|
IPTABLES_CHAIN="ADGUARD_SHIELD"
|
|
BLOCKED_PORTS="53 443 853"
|
|
FIREWALL_BACKEND="ipset"
|
|
FIREWALL_MODE="host"
|
|
DRY_RUN=false
|
|
|
|
WHITELIST="127.0.0.1,::1"
|
|
|
|
LOG_FILE="/var/log/adguard-shield.log"
|
|
LOG_LEVEL="INFO"
|
|
STATE_DIR="/var/lib/adguard-shield"
|
|
PID_FILE="/var/run/adguard-shield.pid"
|
|
|
|
NOTIFY_ENABLED=false
|
|
NOTIFY_TYPE="ntfy"
|
|
NOTIFY_WEBHOOK_URL=""
|
|
NTFY_SERVER_URL="https://ntfy.sh"
|
|
NTFY_TOPIC=""
|
|
NTFY_TOKEN=""
|
|
NTFY_PRIORITY="4"
|
|
|
|
REPORT_ENABLED=false
|
|
REPORT_INTERVAL="weekly"
|
|
REPORT_TIME="08:00"
|
|
REPORT_EMAIL_TO="admin@example.com"
|
|
REPORT_EMAIL_FROM="adguard-shield@example.com"
|
|
REPORT_FORMAT="html"
|
|
REPORT_MAIL_CMD="msmtp"
|
|
REPORT_BUSIEST_DAY_RANGE=30
|
|
|
|
EXTERNAL_WHITELIST_ENABLED=false
|
|
EXTERNAL_WHITELIST_URLS=""
|
|
EXTERNAL_WHITELIST_INTERVAL=300
|
|
EXTERNAL_WHITELIST_CACHE_DIR="/var/lib/adguard-shield/external-whitelist"
|
|
|
|
EXTERNAL_BLOCKLIST_ENABLED=false
|
|
EXTERNAL_BLOCKLIST_URLS=""
|
|
EXTERNAL_BLOCKLIST_INTERVAL=300
|
|
EXTERNAL_BLOCKLIST_BAN_DURATION=0
|
|
EXTERNAL_BLOCKLIST_AUTO_UNBAN=true
|
|
EXTERNAL_BLOCKLIST_NOTIFY=false
|
|
EXTERNAL_BLOCKLIST_CACHE_DIR="/var/lib/adguard-shield/external-blocklist"
|
|
|
|
PROGRESSIVE_BAN_ENABLED=true
|
|
PROGRESSIVE_BAN_MULTIPLIER=2
|
|
PROGRESSIVE_BAN_MAX_LEVEL=5
|
|
PROGRESSIVE_BAN_RESET_AFTER=86400
|
|
|
|
ABUSEIPDB_ENABLED=false
|
|
ABUSEIPDB_API_KEY=""
|
|
ABUSEIPDB_CATEGORIES="4"
|
|
|
|
GEOIP_ENABLED=false
|
|
GEOIP_MODE="blocklist"
|
|
GEOIP_COUNTRIES=""
|
|
GEOIP_CHECK_INTERVAL=0
|
|
GEOIP_NOTIFY=true
|
|
GEOIP_SKIP_PRIVATE=true
|
|
GEOIP_LICENSE_KEY=""
|
|
GEOIP_MMDB_PATH=""
|
|
GEOIP_CACHE_TTL=86400
|
|
`
|