Golangcilint in build pipeline and fix lint errors

- Fix bad permissions bits for files
- VPNSP is 'private internet access' instead of 'pia' (retro compatible)
- Check errors of deferred unsetEnv functions in params package
-  Other lint errors fixing and code simplifications
This commit is contained in:
Quentin McGaw
2020-04-12 20:05:28 +00:00
parent 8f6b6306d6
commit 768147095f
43 changed files with 2742 additions and 2598 deletions
+58 -7
View File
@@ -1,10 +1,14 @@
{ {
"name": "pia-dev", "name": "pia-dev",
"dockerComposeFile": ["docker-compose.yml"], "dockerComposeFile": [
"docker-compose.yml"
],
"service": "vscode", "service": "vscode",
"runServices": ["vscode"], "runServices": [
"vscode"
],
"shutdownAction": "stopCompose", "shutdownAction": "stopCompose",
// "postCreateCommand": "go mod download", "postCreateCommand": "go mod download",
"workspaceFolder": "/workspace", "workspaceFolder": "/workspace",
"extensions": [ "extensions": [
"ms-vscode.go", "ms-vscode.go",
@@ -38,10 +42,54 @@
"deepCompletion": true, "deepCompletion": true,
"usePlaceholders": false "usePlaceholders": false
}, },
"go.lintTool": "golangci-lint",
"go.lintFlags": [
"--fast",
"--enable",
"staticcheck",
"--enable",
"bodyclose",
"--enable",
"dogsled",
"--enable",
"gochecknoglobals",
"--enable",
"gochecknoinits",
"--enable",
"gocognit",
"--enable",
"goconst",
"--enable",
"gocritic",
"--enable",
"gocyclo",
"--enable",
"golint",
"--enable",
"gosec",
"--enable",
"interfacer",
"--enable",
"maligned",
"--enable",
"misspell",
"--enable",
"nakedret",
"--enable",
"prealloc",
"--enable",
"scopelint",
"--enable",
"unconvert",
"--enable",
"unparam",
"--enable",
"whitespace"
],
// Golang on save // Golang on save
"go.buildOnSave": "package", "go.buildOnSave": "workspace",
"go.lintOnSave": "package", "go.lintOnSave": "workspace",
"go.vetOnSave": "package", "go.vetOnSave": "workspace",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"[go]": { "[go]": {
"editor.codeActionsOnSave": { "editor.codeActionsOnSave": {
@@ -56,7 +104,10 @@
"GOFLAGS": "-tags=integration" "GOFLAGS": "-tags=integration"
}, },
"go.testEnvVars": {}, "go.testEnvVars": {},
"go.testFlags": ["-v"], "go.testFlags": [
"-v",
// "-race"
],
"go.testTimeout": "600s" "go.testTimeout": "600s"
} }
} }
+50
View File
@@ -0,0 +1,50 @@
linters-settings:
maligned:
suggest-new: true
misspell:
locale: US
linters:
disable-all: true
enable:
- bodyclose
- deadcode
- dogsled
- dupl
- errcheck
- gochecknoglobals
- gochecknoinits
- gocognit
- goconst
- gocritic
- gocyclo
- goimports
- golint
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- maligned
- misspell
- nakedret
- prealloc
- rowserrcheck
- scopelint
- staticcheck
- structcheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
run:
skip-dirs:
- .devcontainer
- .github
- postgres
service:
golangci-lint-version: 1.24.x # use the fixed version to not introduce new linters unexpectedly
+6 -2
View File
@@ -3,13 +3,17 @@ ARG GO_VERSION=1.14
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder
RUN apk --update add git RUN apk --update add git
WORKDIR /tmp/gobuild
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
ARG GOLANGCI_LINT_VERSION=v1.24.0
RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s ${GOLANGCI_LINT_VERSION}
WORKDIR /tmp/gobuild
COPY .golangci.yml .
COPY go.mod go.sum ./ COPY go.mod go.sum ./
RUN go mod download 2>&1 RUN go mod download 2>&1
COPY cmd/main.go . COPY cmd/main.go .
COPY internal/ ./internal/ COPY internal/ ./internal/
RUN go test ./... RUN go test ./...
RUN golangci-lint run --timeout=10m
RUN go build -ldflags="-s -w" -o entrypoint main.go RUN go build -ldflags="-s -w" -o entrypoint main.go
FROM alpine:${ALPINE_VERSION} FROM alpine:${ALPINE_VERSION}
@@ -29,7 +33,7 @@ LABEL \
org.opencontainers.image.source="https://github.com/qdm12/private-internet-access-docker" \ org.opencontainers.image.source="https://github.com/qdm12/private-internet-access-docker" \
org.opencontainers.image.title="PIA client" \ org.opencontainers.image.title="PIA client" \
org.opencontainers.image.description="VPN client to tunnel to private internet access servers using OpenVPN, IPtables, DNS over TLS and Alpine Linux" org.opencontainers.image.description="VPN client to tunnel to private internet access servers using OpenVPN, IPtables, DNS over TLS and Alpine Linux"
ENV VPNSP=pia \ ENV VPNSP="private internet access" \
USER= \ USER= \
PROTOCOL=udp \ PROTOCOL=udp \
OPENVPN_VERBOSITY=1 \ OPENVPN_VERBOSITY=1 \
+1 -1
View File
@@ -113,7 +113,7 @@ docker run --rm --network=container:pia alpine:3.11 wget -qO- https://ipinfo.io
| Environment variable | Default | Properties | PIA | Mullvad | Windscribe | Description | Choices | | Environment variable | Default | Properties | PIA | Mullvad | Windscribe | Description | Choices |
| --- | --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- | --- |
| `VPNSP` | `pia` | | ✅ | ✅ | ✅ | VPN Service Provider | `pia`, `mullvad`, `windscribe` | | `VPNSP` | `private internet access` | | ✅ | ✅ | ✅ | VPN Service Provider | `private internet access`, `mullvad`, `windscribe` |
| `REGION` | `Austria` | | ✅ | ❌ | ✅ | VPN server region | One of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) or of the [Windscribe regions](https://windscribe.com/status) | | `REGION` | `Austria` | | ✅ | ❌ | ✅ | VPN server region | One of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) or of the [Windscribe regions](https://windscribe.com/status) |
| `COUNTRY` | `Sweden` | Optional | ❌ | ✅ | ❌ | VPN server country | One of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) | | `COUNTRY` | `Sweden` | Optional | ❌ | ✅ | ❌ | VPN server country | One of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) |
| `CITY` | | Optional | ❌ | ✅ | ❌ | VPN server city | One of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) | | `CITY` | | Optional | ❌ | ✅ | ❌ | VPN server city | One of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) |
+325 -325
View File
@@ -1,325 +1,325 @@
package main package main
import ( import (
"context" "context"
"fmt" "fmt"
"net" "net"
"os" "os"
"strings" "strings"
"time" "time"
"github.com/qdm12/golibs/command" "github.com/qdm12/golibs/command"
"github.com/qdm12/golibs/files" "github.com/qdm12/golibs/files"
libhealthcheck "github.com/qdm12/golibs/healthcheck" libhealthcheck "github.com/qdm12/golibs/healthcheck"
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/network"
"github.com/qdm12/golibs/signals" "github.com/qdm12/golibs/signals"
"github.com/qdm12/private-internet-access-docker/internal/alpine" "github.com/qdm12/private-internet-access-docker/internal/alpine"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
"github.com/qdm12/private-internet-access-docker/internal/dns" "github.com/qdm12/private-internet-access-docker/internal/dns"
"github.com/qdm12/private-internet-access-docker/internal/env" "github.com/qdm12/private-internet-access-docker/internal/env"
"github.com/qdm12/private-internet-access-docker/internal/firewall" "github.com/qdm12/private-internet-access-docker/internal/firewall"
"github.com/qdm12/private-internet-access-docker/internal/healthcheck" "github.com/qdm12/private-internet-access-docker/internal/healthcheck"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/mullvad" "github.com/qdm12/private-internet-access-docker/internal/mullvad"
"github.com/qdm12/private-internet-access-docker/internal/openvpn" "github.com/qdm12/private-internet-access-docker/internal/openvpn"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
"github.com/qdm12/private-internet-access-docker/internal/pia" "github.com/qdm12/private-internet-access-docker/internal/pia"
"github.com/qdm12/private-internet-access-docker/internal/routing" "github.com/qdm12/private-internet-access-docker/internal/routing"
"github.com/qdm12/private-internet-access-docker/internal/settings" "github.com/qdm12/private-internet-access-docker/internal/settings"
"github.com/qdm12/private-internet-access-docker/internal/shadowsocks" "github.com/qdm12/private-internet-access-docker/internal/shadowsocks"
"github.com/qdm12/private-internet-access-docker/internal/splash" "github.com/qdm12/private-internet-access-docker/internal/splash"
"github.com/qdm12/private-internet-access-docker/internal/tinyproxy" "github.com/qdm12/private-internet-access-docker/internal/tinyproxy"
"github.com/qdm12/private-internet-access-docker/internal/windscribe" "github.com/qdm12/private-internet-access-docker/internal/windscribe"
) )
func main() { func main() {
logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel, -1) logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel, -1)
if err != nil { if err != nil {
panic(err) panic(err)
} }
if libhealthcheck.Mode(os.Args) { if libhealthcheck.Mode(os.Args) {
if err := healthcheck.HealthCheck(); err != nil { if err := healthcheck.HealthCheck(); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
os.Exit(0) os.Exit(0)
} }
paramsReader := params.NewParamsReader(logger) paramsReader := params.NewReader(logger)
fmt.Println(splash.Splash(paramsReader)) fmt.Println(splash.Splash(paramsReader))
e := env.New(logger) e := env.New(logger)
client := network.NewClient(15 * time.Second) client := network.NewClient(15 * time.Second)
// Create configurators // Create configurators
fileManager := files.NewFileManager() fileManager := files.NewFileManager()
alpineConf := alpine.NewConfigurator(fileManager) alpineConf := alpine.NewConfigurator(fileManager)
ovpnConf := openvpn.NewConfigurator(logger, fileManager) ovpnConf := openvpn.NewConfigurator(logger, fileManager)
dnsConf := dns.NewConfigurator(logger, client, fileManager) dnsConf := dns.NewConfigurator(logger, client, fileManager)
firewallConf := firewall.NewConfigurator(logger) firewallConf := firewall.NewConfigurator(logger)
routingConf := routing.NewRouting(logger, fileManager) routingConf := routing.NewRouting(logger, fileManager)
piaConf := pia.NewConfigurator(client, fileManager, firewallConf, logger) piaConf := pia.NewConfigurator(client, fileManager, firewallConf, logger)
mullvadConf := mullvad.NewConfigurator(fileManager, logger) mullvadConf := mullvad.NewConfigurator(fileManager, logger)
windscribeConf := windscribe.NewConfigurator(fileManager) windscribeConf := windscribe.NewConfigurator(fileManager)
tinyProxyConf := tinyproxy.NewConfigurator(fileManager, logger) tinyProxyConf := tinyproxy.NewConfigurator(fileManager, logger)
shadowsocksConf := shadowsocks.NewConfigurator(fileManager, logger) shadowsocksConf := shadowsocks.NewConfigurator(fileManager, logger)
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
streamMerger := command.NewStreamMerger(ctx) streamMerger := command.NewStreamMerger(ctx)
e.PrintVersion("OpenVPN", ovpnConf.Version) e.PrintVersion("OpenVPN", ovpnConf.Version)
e.PrintVersion("Unbound", dnsConf.Version) e.PrintVersion("Unbound", dnsConf.Version)
e.PrintVersion("IPtables", firewallConf.Version) e.PrintVersion("IPtables", firewallConf.Version)
e.PrintVersion("TinyProxy", tinyProxyConf.Version) e.PrintVersion("TinyProxy", tinyProxyConf.Version)
e.PrintVersion("ShadowSocks", shadowsocksConf.Version) e.PrintVersion("ShadowSocks", shadowsocksConf.Version)
allSettings, err := settings.GetAllSettings(paramsReader) allSettings, err := settings.GetAllSettings(paramsReader)
e.FatalOnError(err) e.FatalOnError(err)
logger.Info(allSettings.String()) logger.Info(allSettings.String())
err = alpineConf.CreateUser("nonrootuser", allSettings.System.UID) err = alpineConf.CreateUser("nonrootuser", allSettings.System.UID)
e.FatalOnError(err) e.FatalOnError(err)
err = fileManager.SetOwnership("/etc/unbound", allSettings.System.UID, allSettings.System.GID) err = fileManager.SetOwnership("/etc/unbound", allSettings.System.UID, allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = fileManager.SetOwnership("/etc/tinyproxy", allSettings.System.UID, allSettings.System.GID) err = fileManager.SetOwnership("/etc/tinyproxy", allSettings.System.UID, allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
if err := ovpnConf.CheckTUN(); err != nil { if err := ovpnConf.CheckTUN(); err != nil {
logger.Warn(err) logger.Warn(err)
err = ovpnConf.CreateTUN() err = ovpnConf.CreateTUN()
e.FatalOnError(err) e.FatalOnError(err)
} }
var openVPNUser, openVPNPassword string var openVPNUser, openVPNPassword string
switch allSettings.VPNSP { switch allSettings.VPNSP {
case "pia": case constants.PrivateInternetAccess:
openVPNUser = allSettings.PIA.User openVPNUser = allSettings.PIA.User
openVPNPassword = allSettings.PIA.Password openVPNPassword = allSettings.PIA.Password
case "mullvad": case constants.Mullvad:
openVPNUser = allSettings.Mullvad.User openVPNUser = allSettings.Mullvad.User
openVPNPassword = "m" openVPNPassword = "m"
case "windscribe": case constants.Windscribe:
openVPNUser = allSettings.Windscribe.User openVPNUser = allSettings.Windscribe.User
openVPNPassword = allSettings.Windscribe.Password openVPNPassword = allSettings.Windscribe.Password
} }
err = ovpnConf.WriteAuthFile(openVPNUser, openVPNPassword, allSettings.System.UID, allSettings.System.GID) err = ovpnConf.WriteAuthFile(openVPNUser, openVPNPassword, allSettings.System.UID, allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
defaultInterface, defaultGateway, defaultSubnet, err := routingConf.DefaultRoute() defaultInterface, defaultGateway, defaultSubnet, err := routingConf.DefaultRoute()
e.FatalOnError(err) e.FatalOnError(err)
// Temporarily reset chain policies allowing Kubernetes sidecar to // Temporarily reset chain policies allowing Kubernetes sidecar to
// successfully restart the container. Without this, the existing rules will // successfully restart the container. Without this, the existing rules will
// pre-exist, preventing the nslookup of the PIA region address. These will // pre-exist, preventing the nslookup of the PIA region address. These will
// simply be redundant at Docker runtime as they will already be set this way // simply be redundant at Docker runtime as they will already be set this way
// Thanks to @npawelek https://github.com/npawelek // Thanks to @npawelek https://github.com/npawelek
err = firewallConf.AcceptAll() err = firewallConf.AcceptAll()
e.FatalOnError(err) e.FatalOnError(err)
go func() { go func() {
// Blocking line merging reader for all programs: openvpn, tinyproxy, unbound and shadowsocks // Blocking line merging paramsReader for all programs: openvpn, tinyproxy, unbound and shadowsocks
logger.Info("Launching standard output merger") logger.Info("Launching standard output merger")
err = streamMerger.CollectLines(func(line string) { err = streamMerger.CollectLines(func(line string) {
logger.Info(line) logger.Info(line)
if strings.Contains(line, "Initialization Sequence Completed") { if strings.Contains(line, "Initialization Sequence Completed") {
onConnected(logger, routingConf, fileManager, piaConf, onConnected(logger, routingConf, fileManager, piaConf,
defaultInterface, defaultInterface,
allSettings.VPNSP, allSettings.VPNSP,
allSettings.PIA.PortForwarding.Enabled, allSettings.PIA.PortForwarding.Enabled,
allSettings.PIA.PortForwarding.Filepath, allSettings.PIA.PortForwarding.Filepath,
allSettings.System.IPStatusFilepath, allSettings.System.IPStatusFilepath,
allSettings.System.UID, allSettings.System.UID,
allSettings.System.GID) allSettings.System.GID)
} }
}) })
e.FatalOnError(err) e.FatalOnError(err)
}() }()
if allSettings.DNS.Enabled { if allSettings.DNS.Enabled {
initialDNSToUse := constants.DNSProviderMapping()[allSettings.DNS.Providers[0]] initialDNSToUse := constants.DNSProviderMapping()[allSettings.DNS.Providers[0]]
dnsConf.UseDNSInternally(initialDNSToUse.IPs[0]) dnsConf.UseDNSInternally(initialDNSToUse.IPs[0])
err = dnsConf.DownloadRootHints(allSettings.System.UID, allSettings.System.GID) err = dnsConf.DownloadRootHints(allSettings.System.UID, allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = dnsConf.DownloadRootKey(allSettings.System.UID, allSettings.System.GID) err = dnsConf.DownloadRootKey(allSettings.System.UID, allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = dnsConf.MakeUnboundConf(allSettings.DNS, allSettings.System.UID, allSettings.System.GID) err = dnsConf.MakeUnboundConf(allSettings.DNS, allSettings.System.UID, allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
stream, waitFn, err := dnsConf.Start(allSettings.DNS.VerbosityDetailsLevel) stream, waitFn, err := dnsConf.Start(allSettings.DNS.VerbosityDetailsLevel)
e.FatalOnError(err) e.FatalOnError(err)
go func() { go func() {
e.FatalOnError(waitFn()) e.FatalOnError(waitFn())
}() }()
go streamMerger.Merge("unbound", stream) go streamMerger.Merge("unbound", stream)
dnsConf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound dnsConf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound
err = dnsConf.UseDNSSystemWide(net.IP{127, 0, 0, 1}) // use Unbound err = dnsConf.UseDNSSystemWide(net.IP{127, 0, 0, 1}) // use Unbound
e.FatalOnError(err) e.FatalOnError(err)
err = dnsConf.WaitForUnbound() err = dnsConf.WaitForUnbound()
e.FatalOnError(err) e.FatalOnError(err)
} }
var connections []models.OpenVPNConnection var connections []models.OpenVPNConnection
switch allSettings.VPNSP { switch allSettings.VPNSP {
case "pia": case constants.PrivateInternetAccess:
connections, err = piaConf.GetOpenVPNConnections( connections, err = piaConf.GetOpenVPNConnections(
allSettings.PIA.Region, allSettings.PIA.Region,
allSettings.OpenVPN.NetworkProtocol, allSettings.OpenVPN.NetworkProtocol,
allSettings.PIA.Encryption, allSettings.PIA.Encryption,
allSettings.OpenVPN.TargetIP) allSettings.OpenVPN.TargetIP)
e.FatalOnError(err) e.FatalOnError(err)
err = piaConf.BuildConf( err = piaConf.BuildConf(
connections, connections,
allSettings.PIA.Encryption, allSettings.PIA.Encryption,
allSettings.OpenVPN.Verbosity, allSettings.OpenVPN.Verbosity,
allSettings.System.UID, allSettings.System.UID,
allSettings.System.GID, allSettings.System.GID,
allSettings.OpenVPN.Root, allSettings.OpenVPN.Root,
allSettings.OpenVPN.Cipher, allSettings.OpenVPN.Cipher,
allSettings.OpenVPN.Auth) allSettings.OpenVPN.Auth)
e.FatalOnError(err) e.FatalOnError(err)
case "mullvad": case constants.Mullvad:
connections, err = mullvadConf.GetOpenVPNConnections( connections, err = mullvadConf.GetOpenVPNConnections(
allSettings.Mullvad.Country, allSettings.Mullvad.Country,
allSettings.Mullvad.City, allSettings.Mullvad.City,
allSettings.Mullvad.ISP, allSettings.Mullvad.ISP,
allSettings.OpenVPN.NetworkProtocol, allSettings.OpenVPN.NetworkProtocol,
allSettings.Mullvad.Port, allSettings.Mullvad.Port,
allSettings.OpenVPN.TargetIP) allSettings.OpenVPN.TargetIP)
e.FatalOnError(err) e.FatalOnError(err)
err = mullvadConf.BuildConf( err = mullvadConf.BuildConf(
connections, connections,
allSettings.OpenVPN.Verbosity, allSettings.OpenVPN.Verbosity,
allSettings.System.UID, allSettings.System.UID,
allSettings.System.GID, allSettings.System.GID,
allSettings.OpenVPN.Root, allSettings.OpenVPN.Root,
allSettings.OpenVPN.Cipher) allSettings.OpenVPN.Cipher)
e.FatalOnError(err) e.FatalOnError(err)
case "windscribe": case constants.Windscribe:
connections, err = windscribeConf.GetOpenVPNConnections( connections, err = windscribeConf.GetOpenVPNConnections(
allSettings.Windscribe.Region, allSettings.Windscribe.Region,
allSettings.OpenVPN.NetworkProtocol, allSettings.OpenVPN.NetworkProtocol,
allSettings.Windscribe.Port, allSettings.Windscribe.Port,
allSettings.OpenVPN.TargetIP) allSettings.OpenVPN.TargetIP)
e.FatalOnError(err) e.FatalOnError(err)
err = windscribeConf.BuildConf( err = windscribeConf.BuildConf(
connections, connections,
allSettings.OpenVPN.Verbosity, allSettings.OpenVPN.Verbosity,
allSettings.System.UID, allSettings.System.UID,
allSettings.System.GID, allSettings.System.GID,
allSettings.OpenVPN.Root, allSettings.OpenVPN.Root,
allSettings.OpenVPN.Cipher, allSettings.OpenVPN.Cipher,
allSettings.OpenVPN.Auth) allSettings.OpenVPN.Auth)
e.FatalOnError(err) e.FatalOnError(err)
} }
err = routingConf.AddRoutesVia(allSettings.Firewall.AllowedSubnets, defaultGateway, defaultInterface) err = routingConf.AddRoutesVia(allSettings.Firewall.AllowedSubnets, defaultGateway, defaultInterface)
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.Clear() err = firewallConf.Clear()
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.BlockAll() err = firewallConf.BlockAll()
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.CreateGeneralRules() err = firewallConf.CreateGeneralRules()
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.CreateVPNRules(constants.TUN, defaultInterface, connections) err = firewallConf.CreateVPNRules(constants.TUN, defaultInterface, connections)
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.CreateLocalSubnetsRules(defaultSubnet, allSettings.Firewall.AllowedSubnets, defaultInterface) err = firewallConf.CreateLocalSubnetsRules(defaultSubnet, allSettings.Firewall.AllowedSubnets, defaultInterface)
e.FatalOnError(err) e.FatalOnError(err)
if allSettings.TinyProxy.Enabled { if allSettings.TinyProxy.Enabled {
err = tinyProxyConf.MakeConf( err = tinyProxyConf.MakeConf(
allSettings.TinyProxy.LogLevel, allSettings.TinyProxy.LogLevel,
allSettings.TinyProxy.Port, allSettings.TinyProxy.Port,
allSettings.TinyProxy.User, allSettings.TinyProxy.User,
allSettings.TinyProxy.Password, allSettings.TinyProxy.Password,
allSettings.System.UID, allSettings.System.UID,
allSettings.System.GID) allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.AllowAnyIncomingOnPort(allSettings.TinyProxy.Port) err = firewallConf.AllowAnyIncomingOnPort(allSettings.TinyProxy.Port)
e.FatalOnError(err) e.FatalOnError(err)
stream, waitFn, err := tinyProxyConf.Start() stream, waitFn, err := tinyProxyConf.Start()
e.FatalOnError(err) e.FatalOnError(err)
go func() { go func() {
if err := waitFn(); err != nil { if err := waitFn(); err != nil {
logger.Error(err) logger.Error(err)
} }
}() }()
go streamMerger.Merge("tinyproxy", stream) go streamMerger.Merge("tinyproxy", stream)
} }
if allSettings.ShadowSocks.Enabled { if allSettings.ShadowSocks.Enabled {
err = shadowsocksConf.MakeConf( err = shadowsocksConf.MakeConf(
allSettings.ShadowSocks.Port, allSettings.ShadowSocks.Port,
allSettings.ShadowSocks.Password, allSettings.ShadowSocks.Password,
allSettings.ShadowSocks.Method, allSettings.ShadowSocks.Method,
allSettings.System.UID, allSettings.System.UID,
allSettings.System.GID) allSettings.System.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.AllowAnyIncomingOnPort(allSettings.ShadowSocks.Port) err = firewallConf.AllowAnyIncomingOnPort(allSettings.ShadowSocks.Port)
e.FatalOnError(err) e.FatalOnError(err)
stream, waitFn, err := shadowsocksConf.Start("0.0.0.0", allSettings.ShadowSocks.Port, allSettings.ShadowSocks.Password, allSettings.ShadowSocks.Log) stream, waitFn, err := shadowsocksConf.Start("0.0.0.0", allSettings.ShadowSocks.Port, allSettings.ShadowSocks.Password, allSettings.ShadowSocks.Log)
e.FatalOnError(err) e.FatalOnError(err)
go func() { go func() {
if err := waitFn(); err != nil { if err := waitFn(); err != nil {
logger.Error(err) logger.Error(err)
} }
}() }()
go streamMerger.Merge("shadowsocks", stream) go streamMerger.Merge("shadowsocks", stream)
} }
stream, waitFn, err := ovpnConf.Start() stream, waitFn, err := ovpnConf.Start()
e.FatalOnError(err) e.FatalOnError(err)
go streamMerger.Merge("openvpn", stream) go streamMerger.Merge("openvpn", stream)
go signals.WaitForExit(func(signal string) int { go signals.WaitForExit(func(signal string) int {
logger.Warn("Caught OS signal %s, shutting down", signal) logger.Warn("Caught OS signal %s, shutting down", signal)
if allSettings.VPNSP == "pia" && allSettings.PIA.PortForwarding.Enabled { if allSettings.VPNSP == "pia" && allSettings.PIA.PortForwarding.Enabled {
if err := piaConf.ClearPortForward(allSettings.PIA.PortForwarding.Filepath, allSettings.System.UID, allSettings.System.GID); err != nil { if err := piaConf.ClearPortForward(allSettings.PIA.PortForwarding.Filepath, allSettings.System.UID, allSettings.System.GID); err != nil {
logger.Error(err) logger.Error(err)
} }
} }
time.Sleep(100 * time.Millisecond) // wait for other processes to exit time.Sleep(100 * time.Millisecond) // wait for other processes to exit
return 0 return 0
}) })
e.FatalOnError(waitFn()) e.FatalOnError(waitFn())
} }
func onConnected( func onConnected(
logger logging.Logger, logger logging.Logger,
routingConf routing.Routing, routingConf routing.Routing,
fileManager files.FileManager, fileManager files.FileManager,
piaConf pia.Configurator, piaConf pia.Configurator,
defaultInterface string, defaultInterface string,
VPNSP string, vpnsp models.VPNProvider,
portForwarding bool, portForwarding bool,
portForwardingFilepath models.Filepath, portForwardingFilepath models.Filepath,
ipStatusFilepath models.Filepath, ipStatusFilepath models.Filepath,
uid, gid int, uid, gid int,
) { ) {
ip, err := routingConf.CurrentPublicIP(defaultInterface) ip, err := routingConf.CurrentPublicIP(defaultInterface)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} else { } else {
logger.Info("Tunnel IP is %s, see more information at https://ipinfo.io/%s", ip, ip) logger.Info("Tunnel IP is %s, see more information at https://ipinfo.io/%s", ip, ip)
err := fileManager.WriteLinesToFile( err := fileManager.WriteLinesToFile(
string(ipStatusFilepath), string(ipStatusFilepath),
[]string{ip.String()}, []string{ip.String()},
files.Ownership(uid, gid), files.Ownership(uid, gid),
files.Permissions(400)) files.Permissions(0400))
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
} }
if VPNSP != "pia" || !portForwarding { if vpnsp != constants.PrivateInternetAccess || !portForwarding {
return return
} }
port, err := piaConf.GetPortForward() port, err := piaConf.GetPortForward()
if err != nil { if err != nil {
logger.Error("port forwarding:", err) logger.Error("port forwarding:", err)
return return
} }
logger.Info("port forwarding: Port %d", port) logger.Info("port forwarding: Port %d", port)
if err := piaConf.WritePortForward(portForwardingFilepath, port, uid, gid); err != nil { if err := piaConf.WritePortForward(portForwardingFilepath, port, uid, gid); err != nil {
logger.Error("port forwarding:", err) logger.Error("port forwarding:", err)
return return
} }
if err := piaConf.AllowPortForwardFirewall(constants.TUN, port); err != nil { if err := piaConf.AllowPortForwardFirewall(constants.TUN, port); err != nil {
logger.Error("port forwarding:", err) logger.Error("port forwarding:", err)
return return
} }
} }
+1 -1
View File
@@ -14,7 +14,7 @@ services:
# command: # command:
environment: environment:
# More variables are available, see the readme table # More variables are available, see the readme table
- VPNSP=pia - VPNSP=private internet access
- USER=js89ds7 - USER=js89ds7
- PROTOCOL=udp - PROTOCOL=udp
- OPENVPN_VERBOSITY=1 - OPENVPN_VERBOSITY=1
+89 -89
View File
@@ -1,89 +1,89 @@
package constants package constants
import ( import (
"net" "net"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
const ( const (
// Cloudflare is a DNS over TLS provider // Cloudflare is a DNS over TLS provider
Cloudflare models.DNSProvider = "cloudflare" Cloudflare models.DNSProvider = "cloudflare"
// Google is a DNS over TLS provider // Google is a DNS over TLS provider
Google models.DNSProvider = "google" Google models.DNSProvider = "google"
// Quad9 is a DNS over TLS provider // Quad9 is a DNS over TLS provider
Quad9 models.DNSProvider = "quad9" Quad9 models.DNSProvider = "quad9"
// Quadrant is a DNS over TLS provider // Quadrant is a DNS over TLS provider
Quadrant models.DNSProvider = "quadrant" Quadrant models.DNSProvider = "quadrant"
// CleanBrowsing is a DNS over TLS provider // CleanBrowsing is a DNS over TLS provider
CleanBrowsing models.DNSProvider = "cleanbrowsing" CleanBrowsing models.DNSProvider = "cleanbrowsing"
// SecureDNS is a DNS over TLS provider // SecureDNS is a DNS over TLS provider
SecureDNS models.DNSProvider = "securedns" SecureDNS models.DNSProvider = "securedns"
// LibreDNS is a DNS over TLS provider // LibreDNS is a DNS over TLS provider
LibreDNS models.DNSProvider = "libredns" LibreDNS models.DNSProvider = "libredns"
) )
// DNSProviderMapping returns a constant mapping of dns provider name // DNSProviderMapping returns a constant mapping of dns provider name
// to their data such as IP addresses or TLS host name. // to their data such as IP addresses or TLS host name.
func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData { func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData {
return map[models.DNSProvider]models.DNSProviderData{ return map[models.DNSProvider]models.DNSProviderData{
Cloudflare: models.DNSProviderData{ Cloudflare: {
IPs: []net.IP{{1, 1, 1, 1}, {1, 0, 0, 1}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x01}}, IPs: []net.IP{{1, 1, 1, 1}, {1, 0, 0, 1}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x01}},
SupportsTLS: true, SupportsTLS: true,
SupportsIPv6: true, SupportsIPv6: true,
Host: models.DNSHost("cloudflare-dns.com"), Host: models.DNSHost("cloudflare-dns.com"),
}, },
Google: models.DNSProviderData{ Google: {
IPs: []net.IP{{8, 8, 8, 8}, {8, 8, 4, 4}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x88}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x44}}, IPs: []net.IP{{8, 8, 8, 8}, {8, 8, 4, 4}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x88}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x44}},
SupportsTLS: true, SupportsTLS: true,
SupportsIPv6: true, SupportsIPv6: true,
Host: models.DNSHost("dns.google"), Host: models.DNSHost("dns.google"),
}, },
Quad9: models.DNSProviderData{ Quad9: {
IPs: []net.IP{{9, 9, 9, 9}, {149, 112, 112, 112}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9}}, IPs: []net.IP{{9, 9, 9, 9}, {149, 112, 112, 112}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9}},
SupportsTLS: true, SupportsTLS: true,
SupportsIPv6: true, SupportsIPv6: true,
Host: models.DNSHost("dns.quad9.net"), Host: models.DNSHost("dns.quad9.net"),
}, },
Quadrant: models.DNSProviderData{ Quadrant: {
IPs: []net.IP{{12, 159, 2, 159}, {0x20, 0x1, 0x18, 0x90, 0x14, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x59}}, IPs: []net.IP{{12, 159, 2, 159}, {0x20, 0x1, 0x18, 0x90, 0x14, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x59}},
SupportsTLS: true, SupportsTLS: true,
SupportsIPv6: true, SupportsIPv6: true,
Host: models.DNSHost("dns-tls.qis.io"), Host: models.DNSHost("dns-tls.qis.io"),
}, },
CleanBrowsing: models.DNSProviderData{ CleanBrowsing: {
IPs: []net.IP{{185, 228, 168, 9}, {185, 228, 169, 9}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}}, IPs: []net.IP{{185, 228, 168, 9}, {185, 228, 169, 9}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}},
SupportsTLS: true, SupportsTLS: true,
SupportsIPv6: true, SupportsIPv6: true,
Host: models.DNSHost("security-filter-dns.cleanbrowsing.org"), Host: models.DNSHost("security-filter-dns.cleanbrowsing.org"),
}, },
SecureDNS: models.DNSProviderData{ SecureDNS: {
IPs: []net.IP{{146, 185, 167, 43}, {0x2a, 0x3, 0xb0, 0xc0, 0x0, 0x0, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0xe, 0x9a, 0x30, 0x1}}, IPs: []net.IP{{146, 185, 167, 43}, {0x2a, 0x3, 0xb0, 0xc0, 0x0, 0x0, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0xe, 0x9a, 0x30, 0x1}},
SupportsTLS: true, SupportsTLS: true,
SupportsIPv6: true, SupportsIPv6: true,
Host: models.DNSHost("dot.securedns.eu"), Host: models.DNSHost("dot.securedns.eu"),
}, },
LibreDNS: models.DNSProviderData{ LibreDNS: {
IPs: []net.IP{{116, 203, 115, 192}}, IPs: []net.IP{{116, 203, 115, 192}},
SupportsTLS: true, SupportsTLS: true,
Host: models.DNSHost("dot.libredns.gr"), Host: models.DNSHost("dot.libredns.gr"),
}, },
} }
} }
// Block lists URLs // Block lists URLs
const ( const (
AdsBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-hostnames.updated" AdsBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-hostnames.updated"
AdsBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-ips.updated" AdsBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/ads-ips.updated"
MaliciousBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/malicious-hostnames.updated" MaliciousBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/malicious-hostnames.updated"
MaliciousBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/malicious-ips.updated" MaliciousBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/malicious-ips.updated"
SurveillanceBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/surveillance-hostnames.updated" SurveillanceBlockListHostnamesURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/surveillance-hostnames.updated"
SurveillanceBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/surveillance-ips.updated" SurveillanceBlockListIPsURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/surveillance-ips.updated"
) )
// DNS certificates to fetch // DNS certificates to fetch
// TODO obtain from source directly, see qdm12/updated) // TODO obtain from source directly, see qdm12/updated)
const ( const (
NamedRootURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/named.root.updated" NamedRootURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/named.root.updated"
RootKeyURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/root.key.updated" RootKeyURL models.URL = "https://raw.githubusercontent.com/qdm12/files/master/root.key.updated"
) )
+85 -85
View File
@@ -1,85 +1,85 @@
package constants package constants
import ( import (
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
const ( const (
// PIAEncryptionNormal is the normal level of encryption for communication with PIA servers // PIAEncryptionNormal is the normal level of encryption for communication with PIA servers
PIAEncryptionNormal models.PIAEncryption = "normal" PIAEncryptionNormal models.PIAEncryption = "normal"
// PIAEncryptionStrong is the strong level of encryption for communication with PIA servers // PIAEncryptionStrong is the strong level of encryption for communication with PIA servers
PIAEncryptionStrong models.PIAEncryption = "strong" PIAEncryptionStrong models.PIAEncryption = "strong"
) )
const ( const (
PIAX509CRL_NORMAL = "MIICWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAQEAQZo9X97ci8EcPYu/uK2HB152OZbeZCINmYyluLDOdcSvg6B5jI+ffKN3laDvczsG6CxmY3jNyc79XVpEYUnq4rT3FfveW1+Ralf+Vf38HdpwB8EWB4hZlQ205+21CALLvZvR8HcPxC9KEnev1mU46wkTiov0EKc+EdRxkj5yMgv0V2Reze7AP+NQ9ykvDScH4eYCsmufNpIjBLhpLE2cuZZXBLcPhuRzVoU3l7A9lvzG9mjA5YijHJGHNjlWFqyrn1CfYS6koa4TGEPngBoAziWRbDGdhEgJABHrpoaFYaL61zqyMR6jC0K2ps9qyZAN74LEBedEfK7tBOzWMwr58A==" PiaX509CRLNormal = "MIICWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAQEAQZo9X97ci8EcPYu/uK2HB152OZbeZCINmYyluLDOdcSvg6B5jI+ffKN3laDvczsG6CxmY3jNyc79XVpEYUnq4rT3FfveW1+Ralf+Vf38HdpwB8EWB4hZlQ205+21CALLvZvR8HcPxC9KEnev1mU46wkTiov0EKc+EdRxkj5yMgv0V2Reze7AP+NQ9ykvDScH4eYCsmufNpIjBLhpLE2cuZZXBLcPhuRzVoU3l7A9lvzG9mjA5YijHJGHNjlWFqyrn1CfYS6koa4TGEPngBoAziWRbDGdhEgJABHrpoaFYaL61zqyMR6jC0K2ps9qyZAN74LEBedEfK7tBOzWMwr58A=="
PIAX509CRL_STRONG = "MIIDWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAgEAppFfEpGsasjB1QgJcosGpzbf2kfRhM84o2TlqY1ua+Gi5TMdKydA3LJcNTjlI9a0TYAJfeRX5IkpoglSUuHuJgXhP3nEvX10mjXDpcu/YvM8TdE5JV2+EGqZ80kFtBeOq94WcpiVKFTR4fO+VkOK9zwspFfb1cNs9rHvgJ1QMkRUF8PpLN6AkntHY0+6DnigtSaKqldqjKTDTv2OeH3nPoh80SGrt0oCOmYKfWTJGpggMGKvIdvU3vH9+EuILZKKIskt+1dwdfA5Bkz1GLmiQG7+9ZZBQUjBG9Dos4hfX/rwJ3eU8oUIm4WoTz9rb71SOEuUUjP5NPy9HNx2vx+cVvLsTF4ZDZaUztW9o9JmIURDtbeyqxuHN3prlPWB6aj73IIm2dsDQvs3XXwRIxs8NwLbJ6CyEuvEOVCskdM8rdADWx1J0lRNlOJ0Z8ieLLEmYAA834VN1SboB6wJIAPxQU3rcBhXqO9y8aa2oRMg8NxZ5gr+PnKVMqag1x0IxbIgLxtkXQvxXxQHEMSODzvcOfK/nBRBsqTj30P+R87sU8titOoxNeRnBDRNhdEy/QGAqGh62ShPpQUCJdnKRiRTjnil9hMQHevoSuFKeEMO30FQL7BZyo37GFU+q1WPCplVZgCP9hC8Rn5K2+f6KLFo5bhtowSmu+GY1yZtg+RTtsA=" PiaX509CRLStrong = "MIIDWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAgEAppFfEpGsasjB1QgJcosGpzbf2kfRhM84o2TlqY1ua+Gi5TMdKydA3LJcNTjlI9a0TYAJfeRX5IkpoglSUuHuJgXhP3nEvX10mjXDpcu/YvM8TdE5JV2+EGqZ80kFtBeOq94WcpiVKFTR4fO+VkOK9zwspFfb1cNs9rHvgJ1QMkRUF8PpLN6AkntHY0+6DnigtSaKqldqjKTDTv2OeH3nPoh80SGrt0oCOmYKfWTJGpggMGKvIdvU3vH9+EuILZKKIskt+1dwdfA5Bkz1GLmiQG7+9ZZBQUjBG9Dos4hfX/rwJ3eU8oUIm4WoTz9rb71SOEuUUjP5NPy9HNx2vx+cVvLsTF4ZDZaUztW9o9JmIURDtbeyqxuHN3prlPWB6aj73IIm2dsDQvs3XXwRIxs8NwLbJ6CyEuvEOVCskdM8rdADWx1J0lRNlOJ0Z8ieLLEmYAA834VN1SboB6wJIAPxQU3rcBhXqO9y8aa2oRMg8NxZ5gr+PnKVMqag1x0IxbIgLxtkXQvxXxQHEMSODzvcOfK/nBRBsqTj30P+R87sU8titOoxNeRnBDRNhdEy/QGAqGh62ShPpQUCJdnKRiRTjnil9hMQHevoSuFKeEMO30FQL7BZyo37GFU+q1WPCplVZgCP9hC8Rn5K2+f6KLFo5bhtowSmu+GY1yZtg+RTtsA="
PIACertificate_NORMAL = "MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXDL1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzXlH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWpcdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RCOfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tLy8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZOsqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpMb3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2VzczEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5jb22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAna5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xUryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK37pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyCGohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUtYDQ8z9v+DMO6iwyIDRiU" PIACertificateNormal = "MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXDL1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzXlH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWpcdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RCOfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tLy8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZOsqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpMb3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2VzczEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5jb22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAna5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xUryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK37pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyCGohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUtYDQ8z9v+DMO6iwyIDRiU"
PIACertificate_STRONG = "MIIHqzCCBZOgAwIBAgIJAJ0u+vODZJntMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzQwMzNaFw0zNDA0MTIxNzQwMzNaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVkhjumaqBbL8aSgj6xbX1QPTfTd1qHsAZd2B97m8Vw31c/2yQgZNf5qZY0+jOIHULNDe4R9TIvyBEbvnAg/OkPw8n/+ScgYOeH876VUXzjLDBnDb8DLr/+w9oVsuDeFJ9KV2UFM1OYX0SnkHnrYAN2QLF98ESK4NCSU01h5zkcgmQ+qKSfA9Ny0/UpsKPBFqsQ25NvjDWFhCpeqCHKUJ4Be27CDbSl7lAkBuHMPHJs8f8xPgAbHRXZOxVCpayZ2SNDfCwsnGWpWFoMGvdMbygngCn6jA/W1VSFOlRlfLuuGe7QFfDwA0jaLCxuWt/BgZylp7tAzYKR8lnWmtUCPm4+BtjyVDYtDCiGBD9Z4P13RFWvJHw5aapx/5W/CuvVyI7pKwvc2IT+KPxCUhH1XI8ca5RN3C9NoPJJf6qpg4g0rJH3aaWkoMRrYvQ+5PXXYUzjtRHImghRGd/ydERYoAZXuGSbPkm9Y/p2X8unLcW+F0xpJD98+ZI+tzSsI99Zs5wijSUGYr9/j18KHFTMQ8n+1jauc5bCCegN27dPeKXNSZ5riXFL2XX6BkY68y58UaNzmeGMiUL9BOV1iV+PMb7B7PYs7oFLjAhh0EdyvfHkrh/ZV9BEhtFa7yXp8XR0J6vz1YV9R6DYJmLjOEbhU8N0gc3tZm4Qz39lIIG6w3FDAgMBAAGjggFUMIIBUDAdBgNVHQ4EFgQUrsRtyWJftjpdRM0+925Y6Cl08SUwggEfBgNVHSMEggEWMIIBEoAUrsRtyWJftjpdRM0+925Y6Cl08SWhge6kgeswgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tggkAnS7684Nkme0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOCAgEAJsfhsPk3r8kLXLxY+v+vHzbr4ufNtqnL9/1Uuf8NrsCtpXAoyZ0YqfbkWx3NHTZ7OE9ZRhdMP/RqHQE1p4N4Sa1nZKhTKasV6KhHDqSCt/dvEm89xWm2MVA7nyzQxVlHa9AkcBaemcXEiyT19XdpiXOP4Vhs+J1R5m8zQOxZlV1GtF9vsXmJqWZpOVPmZ8f35BCsYPvv4yMewnrtAC8PFEK/bOPeYcKN50bol22QYaZuLfpkHfNiFTnfMh8sl/ablPyNY7DUNiP5DRcMdIwmfGQxR5WEQoHL3yPJ42LkB5zs6jIm26DGNXfwura/mi105+ENH1CaROtRYwkiHb08U6qLXXJz80mWJkT90nr8Asj35xN2cUppg74nG3YVav/38P48T56hG1NHbYF5uOCske19F6wi9maUoto/3vEr0rnXJUp2KODmKdvBI7co245lHBABWikk8VfejQSlCtDBXn644ZMtAdoxKNfR2WTFVEwJiyd1Fzx0yujuiXDROLhISLQDRjVVAvawrAtLZWYK31bY7KlezPlQnl/D9Asxe85l8jO5+0LdJ6VyOs/Hd4w52alDW/MFySDZSfQHMTIc30hLBJ8OnCEIvluVQQ2UQvoW+no177N9L2Y+M9TcTA62ZyMXShHQGeh20rb4kK8f+iFX8NxtdHVSkxMEFSfDDyQ=" PIACertificateStrong = "MIIHqzCCBZOgAwIBAgIJAJ0u+vODZJntMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzQwMzNaFw0zNDA0MTIxNzQwMzNaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVkhjumaqBbL8aSgj6xbX1QPTfTd1qHsAZd2B97m8Vw31c/2yQgZNf5qZY0+jOIHULNDe4R9TIvyBEbvnAg/OkPw8n/+ScgYOeH876VUXzjLDBnDb8DLr/+w9oVsuDeFJ9KV2UFM1OYX0SnkHnrYAN2QLF98ESK4NCSU01h5zkcgmQ+qKSfA9Ny0/UpsKPBFqsQ25NvjDWFhCpeqCHKUJ4Be27CDbSl7lAkBuHMPHJs8f8xPgAbHRXZOxVCpayZ2SNDfCwsnGWpWFoMGvdMbygngCn6jA/W1VSFOlRlfLuuGe7QFfDwA0jaLCxuWt/BgZylp7tAzYKR8lnWmtUCPm4+BtjyVDYtDCiGBD9Z4P13RFWvJHw5aapx/5W/CuvVyI7pKwvc2IT+KPxCUhH1XI8ca5RN3C9NoPJJf6qpg4g0rJH3aaWkoMRrYvQ+5PXXYUzjtRHImghRGd/ydERYoAZXuGSbPkm9Y/p2X8unLcW+F0xpJD98+ZI+tzSsI99Zs5wijSUGYr9/j18KHFTMQ8n+1jauc5bCCegN27dPeKXNSZ5riXFL2XX6BkY68y58UaNzmeGMiUL9BOV1iV+PMb7B7PYs7oFLjAhh0EdyvfHkrh/ZV9BEhtFa7yXp8XR0J6vz1YV9R6DYJmLjOEbhU8N0gc3tZm4Qz39lIIG6w3FDAgMBAAGjggFUMIIBUDAdBgNVHQ4EFgQUrsRtyWJftjpdRM0+925Y6Cl08SUwggEfBgNVHSMEggEWMIIBEoAUrsRtyWJftjpdRM0+925Y6Cl08SWhge6kgeswgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tggkAnS7684Nkme0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOCAgEAJsfhsPk3r8kLXLxY+v+vHzbr4ufNtqnL9/1Uuf8NrsCtpXAoyZ0YqfbkWx3NHTZ7OE9ZRhdMP/RqHQE1p4N4Sa1nZKhTKasV6KhHDqSCt/dvEm89xWm2MVA7nyzQxVlHa9AkcBaemcXEiyT19XdpiXOP4Vhs+J1R5m8zQOxZlV1GtF9vsXmJqWZpOVPmZ8f35BCsYPvv4yMewnrtAC8PFEK/bOPeYcKN50bol22QYaZuLfpkHfNiFTnfMh8sl/ablPyNY7DUNiP5DRcMdIwmfGQxR5WEQoHL3yPJ42LkB5zs6jIm26DGNXfwura/mi105+ENH1CaROtRYwkiHb08U6qLXXJz80mWJkT90nr8Asj35xN2cUppg74nG3YVav/38P48T56hG1NHbYF5uOCske19F6wi9maUoto/3vEr0rnXJUp2KODmKdvBI7co245lHBABWikk8VfejQSlCtDBXn644ZMtAdoxKNfR2WTFVEwJiyd1Fzx0yujuiXDROLhISLQDRjVVAvawrAtLZWYK31bY7KlezPlQnl/D9Asxe85l8jO5+0LdJ6VyOs/Hd4w52alDW/MFySDZSfQHMTIc30hLBJ8OnCEIvluVQQ2UQvoW+no177N9L2Y+M9TcTA62ZyMXShHQGeh20rb4kK8f+iFX8NxtdHVSkxMEFSfDDyQ="
) )
func PIAGeoChoices() (regions []string) { func PIAGeoChoices() (regions []string) {
for region := range PIAGeoToSubdomainMapping() { for region := range PIAGeoToSubdomainMapping() {
regions = append(regions, string(region)) regions = append(regions, string(region))
} }
return regions return regions
} }
func PIAGeoToSubdomainMapping() map[models.PIARegion]string { func PIAGeoToSubdomainMapping() map[models.PIARegion]string {
return map[models.PIARegion]string{ return map[models.PIARegion]string{
models.PIARegion("AU Melbourne"): "au-melbourne", models.PIARegion("AU Melbourne"): "au-melbourne",
models.PIARegion("AU Perth"): "au-perth", models.PIARegion("AU Perth"): "au-perth",
models.PIARegion("AU Sydney"): "au-sydney", models.PIARegion("AU Sydney"): "au-sydney",
models.PIARegion("Austria"): "austria", models.PIARegion("Austria"): "austria",
models.PIARegion("Belgium"): "belgium", models.PIARegion("Belgium"): "belgium",
models.PIARegion("CA Montreal"): "ca-montreal", models.PIARegion("CA Montreal"): "ca-montreal",
models.PIARegion("CA Toronto"): "ca-toronto", models.PIARegion("CA Toronto"): "ca-toronto",
models.PIARegion("CA Vancouver"): "ca-vancouver", models.PIARegion("CA Vancouver"): "ca-vancouver",
models.PIARegion("Czech Republic"): "czech", models.PIARegion("Czech Republic"): "czech",
models.PIARegion("DE Berlin"): "de-berlin", models.PIARegion("DE Berlin"): "de-berlin",
models.PIARegion("DE Frankfurt"): "de-frankfurt", models.PIARegion("DE Frankfurt"): "de-frankfurt",
models.PIARegion("Denmark"): "denmark", models.PIARegion("Denmark"): "denmark",
models.PIARegion("Finland"): "fi", models.PIARegion("Finland"): "fi",
models.PIARegion("France"): "france", models.PIARegion("France"): "france",
models.PIARegion("Hong Kong"): "hk", models.PIARegion("Hong Kong"): "hk",
models.PIARegion("Hungary"): "hungary", models.PIARegion("Hungary"): "hungary",
models.PIARegion("India"): "in", models.PIARegion("India"): "in",
models.PIARegion("Ireland"): "ireland", models.PIARegion("Ireland"): "ireland",
models.PIARegion("Israel"): "israel", models.PIARegion("Israel"): "israel",
models.PIARegion("Italy"): "italy", models.PIARegion("Italy"): "italy",
models.PIARegion("Japan"): "japan", models.PIARegion("Japan"): "japan",
models.PIARegion("Luxembourg"): "lu", models.PIARegion("Luxembourg"): "lu",
models.PIARegion("Mexico"): "mexico", models.PIARegion("Mexico"): "mexico",
models.PIARegion("Netherlands"): "nl", models.PIARegion("Netherlands"): "nl",
models.PIARegion("New Zealand"): "nz", models.PIARegion("New Zealand"): "nz",
models.PIARegion("Norway"): "no", models.PIARegion("Norway"): "no",
models.PIARegion("Poland"): "poland", models.PIARegion("Poland"): "poland",
models.PIARegion("Romania"): "ro", models.PIARegion("Romania"): "ro",
models.PIARegion("Singapore"): "sg", models.PIARegion("Singapore"): "sg",
models.PIARegion("Spain"): "spain", models.PIARegion("Spain"): "spain",
models.PIARegion("Sweden"): "sweden", models.PIARegion("Sweden"): "sweden",
models.PIARegion("Switzerland"): "swiss", models.PIARegion("Switzerland"): "swiss",
models.PIARegion("UAE"): "ae", models.PIARegion("UAE"): "ae",
models.PIARegion("UK London"): "uk-london", models.PIARegion("UK London"): "uk-london",
models.PIARegion("UK Manchester"): "uk-manchester", models.PIARegion("UK Manchester"): "uk-manchester",
models.PIARegion("UK Southampton"): "uk-southampton", models.PIARegion("UK Southampton"): "uk-southampton",
models.PIARegion("US Atlanta"): "us-atlanta", models.PIARegion("US Atlanta"): "us-atlanta",
models.PIARegion("US California"): "us-california", models.PIARegion("US California"): "us-california",
models.PIARegion("US Chicago"): "us-chicago", models.PIARegion("US Chicago"): "us-chicago",
models.PIARegion("US Denver"): "us-denver", models.PIARegion("US Denver"): "us-denver",
models.PIARegion("US East"): "us-east", models.PIARegion("US East"): "us-east",
models.PIARegion("US Florida"): "us-florida", models.PIARegion("US Florida"): "us-florida",
models.PIARegion("US Houston"): "us-houston", models.PIARegion("US Houston"): "us-houston",
models.PIARegion("US Las Vegas"): "us-lasvegas", models.PIARegion("US Las Vegas"): "us-lasvegas",
models.PIARegion("US New York City"): "us-newyorkcity", models.PIARegion("US New York City"): "us-newyorkcity",
models.PIARegion("US Seattle"): "us-seattle", models.PIARegion("US Seattle"): "us-seattle",
models.PIARegion("US Silicon Valley"): "us-siliconvalley", models.PIARegion("US Silicon Valley"): "us-siliconvalley",
models.PIARegion("US Texas"): "us-texas", models.PIARegion("US Texas"): "us-texas",
models.PIARegion("US Washington DC"): "us-washingtondc", models.PIARegion("US Washington DC"): "us-washingtondc",
models.PIARegion("US West"): "us-west", models.PIARegion("US West"): "us-west",
} }
} }
const ( const (
PIAPortForwardURL models.URL = "http://209.222.18.222:2000" PIAPortForwardURL models.URL = "http://209.222.18.222:2000"
) )
+289 -287
View File
@@ -1,287 +1,289 @@
package dns package dns
import ( import (
"fmt" "fmt"
"sort" "net/http"
"strings" "sort"
"strings"
"github.com/qdm12/golibs/files"
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/files"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/logging"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/golibs/network"
"github.com/qdm12/private-internet-access-docker/internal/settings" "github.com/qdm12/private-internet-access-docker/internal/constants"
) "github.com/qdm12/private-internet-access-docker/internal/settings"
)
func (c *configurator) MakeUnboundConf(settings settings.DNS, uid, gid int) (err error) {
c.logger.Info("generating Unbound configuration") func (c *configurator) MakeUnboundConf(settings settings.DNS, uid, gid int) (err error) {
lines, warnings, err := generateUnboundConf(settings, c.client, c.logger) c.logger.Info("generating Unbound configuration")
for _, warning := range warnings { lines, warnings := generateUnboundConf(settings, c.client, c.logger)
c.logger.Warn(warning) for _, warning := range warnings {
} c.logger.Warn(warning)
if err != nil { }
return err return c.fileManager.WriteLinesToFile(
} string(constants.UnboundConf),
return c.fileManager.WriteLinesToFile( lines,
string(constants.UnboundConf), files.Ownership(uid, gid),
lines, files.Permissions(0400))
files.Ownership(uid, gid), }
files.Permissions(0400))
} // MakeUnboundConf generates an Unbound configuration from the user provided settings
func generateUnboundConf(settings settings.DNS, client network.Client, logger logging.Logger) (lines []string, warnings []error) {
// MakeUnboundConf generates an Unbound configuration from the user provided settings doIPv6 := "no"
func generateUnboundConf(settings settings.DNS, client network.Client, logger logging.Logger) (lines []string, warnings []error, err error) { if settings.IPv6 {
doIPv6 := "no" doIPv6 = "yes"
if settings.IPv6 { }
doIPv6 = "yes" serverSection := map[string]string{
} // Logging
serverSection := map[string]string{ "verbosity": fmt.Sprintf("%d", settings.VerbosityLevel),
// Logging "val-log-level": fmt.Sprintf("%d", settings.ValidationLogLevel),
"verbosity": fmt.Sprintf("%d", settings.VerbosityLevel), "use-syslog": "no",
"val-log-level": fmt.Sprintf("%d", settings.ValidationLogLevel), // Performance
"use-syslog": "no", "num-threads": "1",
// Performance "prefetch": "yes",
"num-threads": "1", "prefetch-key": "yes",
"prefetch": "yes", "key-cache-size": "16m",
"prefetch-key": "yes", "key-cache-slabs": "4",
"key-cache-size": "16m", "msg-cache-size": "4m",
"key-cache-slabs": "4", "msg-cache-slabs": "4",
"msg-cache-size": "4m", "rrset-cache-size": "4m",
"msg-cache-slabs": "4", "rrset-cache-slabs": "4",
"rrset-cache-size": "4m", "cache-min-ttl": "3600",
"rrset-cache-slabs": "4", "cache-max-ttl": "9000",
"cache-min-ttl": "3600", // Privacy
"cache-max-ttl": "9000", "rrset-roundrobin": "yes",
// Privacy "hide-identity": "yes",
"rrset-roundrobin": "yes", "hide-version": "yes",
"hide-identity": "yes", // Security
"hide-version": "yes", "tls-cert-bundle": fmt.Sprintf("%q", constants.CACertificates),
// Security "root-hints": fmt.Sprintf("%q", constants.RootHints),
"tls-cert-bundle": fmt.Sprintf("%q", constants.CACertificates), "trust-anchor-file": fmt.Sprintf("%q", constants.RootKey),
"root-hints": fmt.Sprintf("%q", constants.RootHints), "harden-below-nxdomain": "yes",
"trust-anchor-file": fmt.Sprintf("%q", constants.RootKey), "harden-referral-path": "yes",
"harden-below-nxdomain": "yes", "harden-algo-downgrade": "yes",
"harden-referral-path": "yes", // Network
"harden-algo-downgrade": "yes", "do-ip4": "yes",
// Network "do-ip6": doIPv6,
"do-ip4": "yes", "interface": "127.0.0.1",
"do-ip6": doIPv6, "port": "53",
"interface": "127.0.0.1", // Other
"port": "53", "username": "\"nonrootuser\"",
// Other }
"username": "\"nonrootuser\"",
} // Block lists
hostnamesLines, ipsLines, warnings := buildBlocked(client,
// Block lists settings.BlockMalicious, settings.BlockAds, settings.BlockSurveillance,
hostnamesLines, ipsLines, warnings := buildBlocked(client, settings.AllowedHostnames, settings.PrivateAddresses,
settings.BlockMalicious, settings.BlockAds, settings.BlockSurveillance, )
settings.AllowedHostnames, settings.PrivateAddresses, logger.Info("%d hostnames blocked overall", len(hostnamesLines))
) logger.Info("%d IP addresses blocked overall", len(ipsLines))
logger.Info("%d hostnames blocked overall", len(hostnamesLines)) sort.Slice(hostnamesLines, func(i, j int) bool { // for unit tests really
logger.Info("%d IP addresses blocked overall", len(ipsLines)) return hostnamesLines[i] < hostnamesLines[j]
sort.Slice(hostnamesLines, func(i, j int) bool { // for unit tests really })
return hostnamesLines[i] < hostnamesLines[j] sort.Slice(ipsLines, func(i, j int) bool { // for unit tests really
}) return ipsLines[i] < ipsLines[j]
sort.Slice(ipsLines, func(i, j int) bool { // for unit tests really })
return ipsLines[i] < ipsLines[j]
}) // Server
lines = append(lines, "server:")
// Server serverLines := make([]string, len(serverSection))
lines = append(lines, "server:") i := 0
var serverLines []string for k, v := range serverSection {
for k, v := range serverSection { serverLines[i] = " " + k + ": " + v
serverLines = append(serverLines, " "+k+": "+v) i++
} }
sort.Slice(serverLines, func(i, j int) bool { sort.Slice(serverLines, func(i, j int) bool {
return serverLines[i] < serverLines[j] return serverLines[i] < serverLines[j]
}) })
lines = append(lines, serverLines...) lines = append(lines, serverLines...)
lines = append(lines, hostnamesLines...) lines = append(lines, hostnamesLines...)
lines = append(lines, ipsLines...) lines = append(lines, ipsLines...)
// Forward zone // Forward zone
lines = append(lines, "forward-zone:") lines = append(lines, "forward-zone:")
forwardZoneSection := map[string]string{ forwardZoneSection := map[string]string{
"name": "\".\"", "name": "\".\"",
"forward-tls-upstream": "yes", "forward-tls-upstream": "yes",
} }
if settings.Caching { if settings.Caching {
forwardZoneSection["forward-no-cache"] = "no" forwardZoneSection["forward-no-cache"] = "no"
} else { } else {
forwardZoneSection["forward-no-cache"] = "yes" forwardZoneSection["forward-no-cache"] = "yes"
} }
var forwardZoneLines []string forwardZoneLines := make([]string, len(forwardZoneSection))
for k, v := range forwardZoneSection { i = 0
forwardZoneLines = append(forwardZoneLines, " "+k+": "+v) for k, v := range forwardZoneSection {
} forwardZoneLines[i] = " " + k + ": " + v
sort.Slice(forwardZoneLines, func(i, j int) bool { i++
return forwardZoneLines[i] < forwardZoneLines[j] }
}) sort.Slice(forwardZoneLines, func(i, j int) bool {
for _, provider := range settings.Providers { return forwardZoneLines[i] < forwardZoneLines[j]
providerData := constants.DNSProviderMapping()[provider] })
for _, IP := range providerData.IPs { for _, provider := range settings.Providers {
forwardZoneLines = append(forwardZoneLines, providerData := constants.DNSProviderMapping()[provider]
fmt.Sprintf(" forward-addr: %s@853#%s", IP.String(), providerData.Host)) for _, IP := range providerData.IPs {
} forwardZoneLines = append(forwardZoneLines,
} fmt.Sprintf(" forward-addr: %s@853#%s", IP.String(), providerData.Host))
lines = append(lines, forwardZoneLines...) }
return lines, warnings, nil }
} lines = append(lines, forwardZoneLines...)
return lines, warnings
func buildBlocked(client network.Client, blockMalicious, blockAds, blockSurveillance bool, }
allowedHostnames, privateAddresses []string) (hostnamesLines, ipsLines []string, errs []error) {
chHostnames := make(chan []string) func buildBlocked(client network.Client, blockMalicious, blockAds, blockSurveillance bool,
chIPs := make(chan []string) allowedHostnames, privateAddresses []string) (hostnamesLines, ipsLines []string, errs []error) {
chErrors := make(chan []error) chHostnames := make(chan []string)
go func() { chIPs := make(chan []string)
lines, errs := buildBlockedHostnames(client, blockMalicious, blockAds, blockSurveillance, allowedHostnames) chErrors := make(chan []error)
chHostnames <- lines go func() {
chErrors <- errs lines, errs := buildBlockedHostnames(client, blockMalicious, blockAds, blockSurveillance, allowedHostnames)
}() chHostnames <- lines
go func() { chErrors <- errs
lines, errs := buildBlockedIPs(client, blockMalicious, blockAds, blockSurveillance, privateAddresses) }()
chIPs <- lines go func() {
chErrors <- errs lines, errs := buildBlockedIPs(client, blockMalicious, blockAds, blockSurveillance, privateAddresses)
}() chIPs <- lines
n := 2 chErrors <- errs
for n > 0 { }()
select { n := 2
case lines := <-chHostnames: for n > 0 {
hostnamesLines = append(hostnamesLines, lines...) select {
case lines := <-chIPs: case lines := <-chHostnames:
ipsLines = append(ipsLines, lines...) hostnamesLines = append(hostnamesLines, lines...)
case routineErrs := <-chErrors: case lines := <-chIPs:
errs = append(errs, routineErrs...) ipsLines = append(ipsLines, lines...)
n-- case routineErrs := <-chErrors:
} errs = append(errs, routineErrs...)
} n--
return hostnamesLines, ipsLines, errs }
} }
return hostnamesLines, ipsLines, errs
func getList(client network.Client, URL string) (results []string, err error) { }
content, status, err := client.GetContent(URL)
if err != nil { func getList(client network.Client, url string) (results []string, err error) {
return nil, err content, status, err := client.GetContent(url)
} else if status != 200 { if err != nil {
return nil, fmt.Errorf("HTTP status code is %d and not 200", status) return nil, err
} } else if status != http.StatusOK {
results = strings.Split(string(content), "\n") return nil, fmt.Errorf("HTTP status code is %d and not 200", status)
}
// remove empty lines results = strings.Split(string(content), "\n")
last := len(results) - 1
for i := range results { // remove empty lines
if len(results[i]) == 0 { last := len(results) - 1
results[i] = results[last] for i := range results {
last-- if len(results[i]) == 0 {
} results[i] = results[last]
} last--
results = results[:last+1] }
}
if len(results) == 0 { results = results[:last+1]
return nil, nil
} if len(results) == 0 {
return results, nil return nil, nil
} }
return results, nil
func buildBlockedHostnames(client network.Client, blockMalicious, blockAds, blockSurveillance bool, }
allowedHostnames []string) (lines []string, errs []error) {
chResults := make(chan []string) func buildBlockedHostnames(client network.Client, blockMalicious, blockAds, blockSurveillance bool,
chError := make(chan error) allowedHostnames []string) (lines []string, errs []error) {
listsLeftToFetch := 0 chResults := make(chan []string)
if blockMalicious { chError := make(chan error)
listsLeftToFetch++ listsLeftToFetch := 0
go func() { if blockMalicious {
results, err := getList(client, string(constants.MaliciousBlockListHostnamesURL)) listsLeftToFetch++
chResults <- results go func() {
chError <- err results, err := getList(client, string(constants.MaliciousBlockListHostnamesURL))
}() chResults <- results
} chError <- err
if blockAds { }()
listsLeftToFetch++ }
go func() { if blockAds {
results, err := getList(client, string(constants.AdsBlockListHostnamesURL)) listsLeftToFetch++
chResults <- results go func() {
chError <- err results, err := getList(client, string(constants.AdsBlockListHostnamesURL))
}() chResults <- results
} chError <- err
if blockSurveillance { }()
listsLeftToFetch++ }
go func() { if blockSurveillance {
results, err := getList(client, string(constants.SurveillanceBlockListHostnamesURL)) listsLeftToFetch++
chResults <- results go func() {
chError <- err results, err := getList(client, string(constants.SurveillanceBlockListHostnamesURL))
}() chResults <- results
} chError <- err
uniqueResults := make(map[string]struct{}) }()
for listsLeftToFetch > 0 { }
select { uniqueResults := make(map[string]struct{})
case results := <-chResults: for listsLeftToFetch > 0 {
for _, result := range results { select {
uniqueResults[result] = struct{}{} case results := <-chResults:
} for _, result := range results {
case err := <-chError: uniqueResults[result] = struct{}{}
listsLeftToFetch-- }
if err != nil { case err := <-chError:
errs = append(errs, err) listsLeftToFetch--
} if err != nil {
} errs = append(errs, err)
} }
for _, allowedHostname := range allowedHostnames { }
delete(uniqueResults, allowedHostname) }
} for _, allowedHostname := range allowedHostnames {
for result := range uniqueResults { delete(uniqueResults, allowedHostname)
lines = append(lines, " local-zone: \""+result+"\" static") }
} for result := range uniqueResults {
return lines, errs lines = append(lines, " local-zone: \""+result+"\" static")
} }
return lines, errs
func buildBlockedIPs(client network.Client, blockMalicious, blockAds, blockSurveillance bool, }
privateAddresses []string) (lines []string, errs []error) {
chResults := make(chan []string) func buildBlockedIPs(client network.Client, blockMalicious, blockAds, blockSurveillance bool,
chError := make(chan error) privateAddresses []string) (lines []string, errs []error) {
listsLeftToFetch := 0 chResults := make(chan []string)
if blockMalicious { chError := make(chan error)
listsLeftToFetch++ listsLeftToFetch := 0
go func() { if blockMalicious {
results, err := getList(client, string(constants.MaliciousBlockListIPsURL)) listsLeftToFetch++
chResults <- results go func() {
chError <- err results, err := getList(client, string(constants.MaliciousBlockListIPsURL))
}() chResults <- results
} chError <- err
if blockAds { }()
listsLeftToFetch++ }
go func() { if blockAds {
results, err := getList(client, string(constants.AdsBlockListIPsURL)) listsLeftToFetch++
chResults <- results go func() {
chError <- err results, err := getList(client, string(constants.AdsBlockListIPsURL))
}() chResults <- results
} chError <- err
if blockSurveillance { }()
listsLeftToFetch++ }
go func() { if blockSurveillance {
results, err := getList(client, string(constants.SurveillanceBlockListIPsURL)) listsLeftToFetch++
chResults <- results go func() {
chError <- err results, err := getList(client, string(constants.SurveillanceBlockListIPsURL))
}() chResults <- results
} chError <- err
uniqueResults := make(map[string]struct{}) }()
for listsLeftToFetch > 0 { }
select { uniqueResults := make(map[string]struct{})
case results := <-chResults: for listsLeftToFetch > 0 {
for _, result := range results { select {
uniqueResults[result] = struct{}{} case results := <-chResults:
} for _, result := range results {
case err := <-chError: uniqueResults[result] = struct{}{}
listsLeftToFetch-- }
if err != nil { case err := <-chError:
errs = append(errs, err) listsLeftToFetch--
} if err != nil {
} errs = append(errs, err)
} }
for _, privateAddress := range privateAddresses { }
uniqueResults[privateAddress] = struct{}{} }
} for _, privateAddress := range privateAddresses {
for result := range uniqueResults { uniqueResults[privateAddress] = struct{}{}
lines = append(lines, " private-address: "+result) }
} for result := range uniqueResults {
return lines, errs lines = append(lines, " private-address: "+result)
} }
return lines, errs
}
+530 -531
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -9,20 +9,20 @@ import (
) )
// UseDNSInternally is to change the Go program DNS only // UseDNSInternally is to change the Go program DNS only
func (c *configurator) UseDNSInternally(IP net.IP) { func (c *configurator) UseDNSInternally(ip net.IP) {
c.logger.Info("using DNS address %s internally", IP.String()) c.logger.Info("using DNS address %s internally", ip.String())
net.DefaultResolver = &net.Resolver{ net.DefaultResolver = &net.Resolver{
PreferGo: true, PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) { Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{} d := net.Dialer{}
return d.DialContext(ctx, "udp", net.JoinHostPort(IP.String(), "53")) return d.DialContext(ctx, "udp", net.JoinHostPort(ip.String(), "53"))
}, },
} }
} }
// UseDNSSystemWide changes the nameserver to use for DNS system wide // UseDNSSystemWide changes the nameserver to use for DNS system wide
func (c *configurator) UseDNSSystemWide(IP net.IP) error { func (c *configurator) UseDNSSystemWide(ip net.IP) error {
c.logger.Info("using DNS address %s system wide", IP.String()) c.logger.Info("using DNS address %s system wide", ip.String())
data, err := c.fileManager.ReadFile(string(constants.ResolvConf)) data, err := c.fileManager.ReadFile(string(constants.ResolvConf))
if err != nil { if err != nil {
return err return err
@@ -35,12 +35,12 @@ func (c *configurator) UseDNSSystemWide(IP net.IP) error {
found := false found := false
for i := range lines { for i := range lines {
if strings.HasPrefix(lines[i], "nameserver ") { if strings.HasPrefix(lines[i], "nameserver ") {
lines[i] = "nameserver " + IP.String() lines[i] = "nameserver " + ip.String()
found = true found = true
} }
} }
if !found { if !found {
lines = append(lines, "nameserver "+IP.String()) lines = append(lines, "nameserver "+ip.String())
} }
data = []byte(strings.Join(lines, "\n")) data = []byte(strings.Join(lines, "\n"))
return c.fileManager.WriteToFile(string(constants.ResolvConf), data) return c.fileManager.WriteToFile(string(constants.ResolvConf), data)
+3 -2
View File
@@ -2,6 +2,7 @@ package dns
import ( import (
"fmt" "fmt"
"net/http"
"github.com/qdm12/golibs/files" "github.com/qdm12/golibs/files"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
@@ -12,7 +13,7 @@ func (c *configurator) DownloadRootHints(uid, gid int) error {
content, status, err := c.client.GetContent(string(constants.NamedRootURL)) content, status, err := c.client.GetContent(string(constants.NamedRootURL))
if err != nil { if err != nil {
return err return err
} else if status != 200 { } else if status != http.StatusOK {
return fmt.Errorf("HTTP status code is %d for %s", status, constants.NamedRootURL) return fmt.Errorf("HTTP status code is %d for %s", status, constants.NamedRootURL)
} }
return c.fileManager.WriteToFile( return c.fileManager.WriteToFile(
@@ -27,7 +28,7 @@ func (c *configurator) DownloadRootKey(uid, gid int) error {
content, status, err := c.client.GetContent(string(constants.RootKeyURL)) content, status, err := c.client.GetContent(string(constants.RootKeyURL))
if err != nil { if err != nil {
return err return err
} else if status != 200 { } else if status != http.StatusOK {
return fmt.Errorf("HTTP status code is %d for %s", status, constants.RootKeyURL) return fmt.Errorf("HTTP status code is %d for %s", status, constants.RootKeyURL)
} }
return c.fileManager.WriteToFile( return c.fileManager.WriteToFile(
+2 -2
View File
@@ -16,7 +16,7 @@ import (
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
) )
func Test_DownloadRootHints(t *testing.T) { func Test_DownloadRootHints(t *testing.T) { //nolint:dupl
t.Parallel() t.Parallel()
tests := map[string]struct { tests := map[string]struct {
content []byte content []byte
@@ -78,7 +78,7 @@ func Test_DownloadRootHints(t *testing.T) {
} }
} }
func Test_DownloadRootKey(t *testing.T) { func Test_DownloadRootKey(t *testing.T) { //nolint:dupl
t.Parallel() t.Parallel()
tests := map[string]struct { tests := map[string]struct {
content []byte content []byte
+1 -1
View File
@@ -14,7 +14,7 @@ func (c *configurator) WaitForUnbound() (err error) {
return nil return nil
} }
c.logger.Warn("could not resolve %s (try %d of %d): %s", hostToResolve, try, maxTries, err) c.logger.Warn("could not resolve %s (try %d of %d): %s", hostToResolve, try, maxTries, err)
time.Sleep(time.Duration(maxTries * 50 * time.Millisecond)) time.Sleep(maxTries * 50 * time.Millisecond)
} }
return fmt.Errorf("Unbound does not seem to be working after %d tries", maxTries) return fmt.Errorf("Unbound does not seem to be working after %d tries", maxTries)
} }
-1
View File
@@ -68,7 +68,6 @@ func Test_PrintVersion(t *testing.T) {
logger.EXPECT().Error(tc.commandErr).Do(func(err error) { logger.EXPECT().Error(tc.commandErr).Do(func(err error) {
logged = err.Error() logged = err.Error()
}).Times(1) }).Times(1)
} else { } else {
logger.EXPECT().Info("%s version: %s", tc.program, tc.commandVersion). logger.EXPECT().Info("%s version: %s", tc.program, tc.commandVersion).
Do(func(format, program, version string) { Do(func(format, program, version string) {
+2 -2
View File
@@ -10,8 +10,8 @@ import (
func HealthCheck() error { func HealthCheck() error {
// DNS, HTTP and HTTPs check on github.com // DNS, HTTP and HTTPs check on github.com
connectivty := connectivity.NewConnectivity(3 * time.Second) connectivity := connectivity.NewConnectivity(3 * time.Second)
errs := connectivty.Checks("github.com") errs := connectivity.Checks("github.com")
if len(errs) > 0 { if len(errs) > 0 {
var errsStr []string var errsStr []string
for _, err := range errs { for _, err := range errs {
+1 -1
View File
@@ -3,10 +3,10 @@ package models
import "net" import "net"
type MullvadServer struct { type MullvadServer struct {
IPs []net.IP
Country MullvadCountry Country MullvadCountry
City MullvadCity City MullvadCity
Provider MullvadProvider Provider MullvadProvider
Owned bool Owned bool
IPs []net.IP
DefaultPort uint16 DefaultPort uint16
} }
+1 -1
View File
@@ -30,7 +30,7 @@ func (c *configurator) CreateTUN() error {
if err := c.mkNod(string(constants.TunnelDevice), unix.S_IFCHR, int(dev)); err != nil { if err := c.mkNod(string(constants.TunnelDevice), unix.S_IFCHR, int(dev)); err != nil {
return err return err
} }
if err := c.fileManager.SetUserPermissions(string(constants.TunnelDevice), 666); err != nil { if err := c.fileManager.SetUserPermissions(string(constants.TunnelDevice), 0666); err != nil {
return err return err
} }
return nil return nil
+122 -124
View File
@@ -1,124 +1,122 @@
package params package params
import ( import (
"fmt" "fmt"
"strings" "strings"
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
// GetDNSOverTLS obtains if the DNS over TLS should be enabled // GetDNSOverTLS obtains if the DNS over TLS should be enabled
// from the environment variable DOT // from the environment variable DOT
func (p *paramsReader) GetDNSOverTLS() (DNSOverTLS bool, err error) { func (p *reader) GetDNSOverTLS() (DNSOverTLS bool, err error) { //nolint:gocritic
return p.envParams.GetOnOff("DOT", libparams.Default("on")) return p.envParams.GetOnOff("DOT", libparams.Default("on"))
} }
// GetDNSOverTLSProviders obtains the DNS over TLS providers to use // GetDNSOverTLSProviders obtains the DNS over TLS providers to use
// from the environment variable DOT_PROVIDERS // from the environment variable DOT_PROVIDERS
func (p *paramsReader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err error) { func (p *reader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err error) {
s, err := p.envParams.GetEnv("DOT_PROVIDERS", libparams.Default("cloudflare")) s, err := p.envParams.GetEnv("DOT_PROVIDERS", libparams.Default("cloudflare"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, word := range strings.Split(s, ",") { for _, word := range strings.Split(s, ",") {
provider := models.DNSProvider(word) provider := models.DNSProvider(word)
switch provider { switch provider {
case constants.Cloudflare, constants.Google, constants.Quad9, constants.Quadrant, constants.CleanBrowsing, constants.SecureDNS, constants.LibreDNS: case constants.Cloudflare, constants.Google, constants.Quad9, constants.Quadrant, constants.CleanBrowsing, constants.SecureDNS, constants.LibreDNS:
providers = append(providers, provider) providers = append(providers, provider)
default: default:
return nil, fmt.Errorf("DNS over TLS provider %q is not valid", provider) return nil, fmt.Errorf("DNS over TLS provider %q is not valid", provider)
} }
} }
return providers, nil return providers, nil
} }
// GetDNSOverTLSVerbosity obtains the verbosity level to use for Unbound // GetDNSOverTLSVerbosity obtains the verbosity level to use for Unbound
// from the environment variable DOT_VERBOSITY // from the environment variable DOT_VERBOSITY
func (p *paramsReader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) { func (p *reader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) {
n, err := p.envParams.GetEnvIntRange("DOT_VERBOSITY", 0, 5, libparams.Default("1")) n, err := p.envParams.GetEnvIntRange("DOT_VERBOSITY", 0, 5, libparams.Default("1"))
return uint8(n), err return uint8(n), err
} }
// GetDNSOverTLSVerbosityDetails obtains the log level to use for Unbound // GetDNSOverTLSVerbosityDetails obtains the log level to use for Unbound
// from the environment variable DOT_VERBOSITY_DETAILS // from the environment variable DOT_VERBOSITY_DETAILS
func (p *paramsReader) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) { func (p *reader) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) {
n, err := p.envParams.GetEnvIntRange("DOT_VERBOSITY_DETAILS", 0, 4, libparams.Default("0")) n, err := p.envParams.GetEnvIntRange("DOT_VERBOSITY_DETAILS", 0, 4, libparams.Default("0"))
return uint8(n), err return uint8(n), err
} }
// GetDNSOverTLSValidationLogLevel obtains the log level to use for Unbound DOT validation // GetDNSOverTLSValidationLogLevel obtains the log level to use for Unbound DOT validation
// from the environment variable DOT_VALIDATION_LOGLEVEL // from the environment variable DOT_VALIDATION_LOGLEVEL
func (p *paramsReader) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) { func (p *reader) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) {
n, err := p.envParams.GetEnvIntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, libparams.Default("0")) n, err := p.envParams.GetEnvIntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, libparams.Default("0"))
return uint8(n), err return uint8(n), err
} }
// GetDNSMaliciousBlocking obtains if malicious hostnames/IPs should be blocked // GetDNSMaliciousBlocking obtains if malicious hostnames/IPs should be blocked
// from being resolved by Unbound, using the environment variable BLOCK_MALICIOUS // from being resolved by Unbound, using the environment variable BLOCK_MALICIOUS
func (p *paramsReader) GetDNSMaliciousBlocking() (blocking bool, err error) { func (p *reader) GetDNSMaliciousBlocking() (blocking bool, err error) {
return p.envParams.GetOnOff("BLOCK_MALICIOUS", libparams.Default("on")) return p.envParams.GetOnOff("BLOCK_MALICIOUS", libparams.Default("on"))
} }
// GetDNSSurveillanceBlocking obtains if surveillance hostnames/IPs should be blocked // GetDNSSurveillanceBlocking obtains if surveillance hostnames/IPs should be blocked
// from being resolved by Unbound, using the environment variable BLOCK_SURVEILLANCE // from being resolved by Unbound, using the environment variable BLOCK_SURVEILLANCE
// and BLOCK_NSA for retrocompatibility // and BLOCK_NSA for retrocompatibility
func (p *paramsReader) GetDNSSurveillanceBlocking() (blocking bool, err error) { func (p *reader) GetDNSSurveillanceBlocking() (blocking bool, err error) {
// Retro-compatibility // Retro-compatibility
s, err := p.envParams.GetEnv("BLOCK_NSA") s, err := p.envParams.GetEnv("BLOCK_NSA")
if err != nil { if err != nil {
return false, err return false, err
} else if len(s) != 0 { } else if len(s) != 0 {
p.logger.Warn("You are using the old environment variable BLOCK_NSA, please consider changing it to BLOCK_SURVEILLANCE") p.logger.Warn("You are using the old environment variable BLOCK_NSA, please consider changing it to BLOCK_SURVEILLANCE")
return p.envParams.GetOnOff("BLOCK_NSA", libparams.Compulsory()) return p.envParams.GetOnOff("BLOCK_NSA", libparams.Compulsory())
} }
return p.envParams.GetOnOff("BLOCK_SURVEILLANCE", libparams.Default("off")) return p.envParams.GetOnOff("BLOCK_SURVEILLANCE", libparams.Default("off"))
} }
// GetDNSAdsBlocking obtains if ads hostnames/IPs should be blocked // GetDNSAdsBlocking obtains if ads hostnames/IPs should be blocked
// from being resolved by Unbound, using the environment variable BLOCK_ADS // from being resolved by Unbound, using the environment variable BLOCK_ADS
func (p *paramsReader) GetDNSAdsBlocking() (blocking bool, err error) { func (p *reader) GetDNSAdsBlocking() (blocking bool, err error) {
return p.envParams.GetOnOff("BLOCK_ADS", libparams.Default("off")) return p.envParams.GetOnOff("BLOCK_ADS", libparams.Default("off"))
} }
// GetDNSUnblockedHostnames obtains a list of hostnames to unblock from block lists // GetDNSUnblockedHostnames obtains a list of hostnames to unblock from block lists
// from the comma separated list for the environment variable UNBLOCK // from the comma separated list for the environment variable UNBLOCK
func (p *paramsReader) GetDNSUnblockedHostnames() (hostnames []string, err error) { func (p *reader) GetDNSUnblockedHostnames() (hostnames []string, err error) {
s, err := p.envParams.GetEnv("UNBLOCK") s, err := p.envParams.GetEnv("UNBLOCK")
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(s) == 0 { if len(s) == 0 {
return nil, nil return nil, nil
} }
hostnames = strings.Split(s, ",") hostnames = strings.Split(s, ",")
for _, hostname := range hostnames { for _, hostname := range hostnames {
if !p.verifier.MatchHostname(hostname) { if !p.verifier.MatchHostname(hostname) {
return nil, fmt.Errorf("hostname %q does not seem valid", hostname) return nil, fmt.Errorf("hostname %q does not seem valid", hostname)
} }
} }
return hostnames, nil return hostnames, nil
} }
// GetDNSOverTLSCaching obtains if Unbound caching should be enable or not // GetDNSOverTLSCaching obtains if Unbound caching should be enable or not
// from the environment variable DOT_CACHING // from the environment variable DOT_CACHING
func (p *paramsReader) GetDNSOverTLSCaching() (caching bool, err error) { func (p *reader) GetDNSOverTLSCaching() (caching bool, err error) {
return p.envParams.GetOnOff("DOT_CACHING") return p.envParams.GetOnOff("DOT_CACHING")
} }
// GetDNSOverTLSPrivateAddresses obtains if Unbound caching should be enable or not // GetDNSOverTLSPrivateAddresses obtains if Unbound caching should be enable or not
// from the environment variable DOT_PRIVATE_ADDRESS // from the environment variable DOT_PRIVATE_ADDRESS
func (p *paramsReader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string) { func (p *reader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string) {
s, _ := p.envParams.GetEnv("DOT_PRIVATE_ADDRESS") s, _ := p.envParams.GetEnv("DOT_PRIVATE_ADDRESS")
for _, s := range strings.Split(s, ",") { privateAddresses = append(privateAddresses, strings.Split(s, ",")...)
privateAddresses = append(privateAddresses, s) return privateAddresses
} }
return privateAddresses
} // GetDNSOverTLSIPv6 obtains if Unbound should resolve ipv6 addresses using ipv6 DNS over TLS
// servers from the environment variable DOT_IPV6
// GetDNSOverTLSIPv6 obtains if Unbound should resolve ipv6 addresses using ipv6 DNS over TLS func (p *reader) GetDNSOverTLSIPv6() (ipv6 bool, err error) {
// servers from the environment variable DOT_IPV6 return p.envParams.GetOnOff("DOT_IPV6")
func (p *paramsReader) GetDNSOverTLSIPv6() (ipv6 bool, err error) { }
return p.envParams.GetOnOff("DOT_IPV6")
}
+29 -29
View File
@@ -1,29 +1,29 @@
package params package params
import ( import (
"fmt" "fmt"
"net" "net"
"strings" "strings"
) )
// GetExtraSubnets obtains the CIDR subnets from the comma separated list of the // GetExtraSubnets obtains the CIDR subnets from the comma separated list of the
// environment variable EXTRA_SUBNETS // environment variable EXTRA_SUBNETS
func (p *paramsReader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) { func (p *reader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
s, err := p.envParams.GetEnv("EXTRA_SUBNETS") s, err := p.envParams.GetEnv("EXTRA_SUBNETS")
if err != nil { if err != nil {
return nil, err return nil, err
} else if s == "" { } else if s == "" {
return nil, nil return nil, nil
} }
subnets := strings.Split(s, ",") subnets := strings.Split(s, ",")
for _, subnet := range subnets { for _, subnet := range subnets {
_, cidr, err := net.ParseCIDR(subnet) _, cidr, err := net.ParseCIDR(subnet)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not parse subnet %q from environment variable with key EXTRA_SUBNETS: %w", subnet, err) return nil, fmt.Errorf("could not parse subnet %q from environment variable with key EXTRA_SUBNETS: %w", subnet, err)
} else if cidr == nil { } else if cidr == nil {
return nil, fmt.Errorf("parsing subnet %q resulted in a nil CIDR", subnet) return nil, fmt.Errorf("parsing subnet %q resulted in a nil CIDR", subnet)
} }
extraSubnets = append(extraSubnets, *cidr) extraSubnets = append(extraSubnets, *cidr)
} }
return extraSubnets, nil return extraSubnets, nil
} }
+4 -4
View File
@@ -10,7 +10,7 @@ import (
// GetMullvadCountry obtains the country for the Mullvad server from the // GetMullvadCountry obtains the country for the Mullvad server from the
// environment variable COUNTRY // environment variable COUNTRY
func (p *paramsReader) GetMullvadCountry() (country models.MullvadCountry, err error) { func (p *reader) GetMullvadCountry() (country models.MullvadCountry, err error) {
choices := append(constants.MullvadCountryChoices(), "") choices := append(constants.MullvadCountryChoices(), "")
s, err := p.envParams.GetValueIfInside("COUNTRY", choices) s, err := p.envParams.GetValueIfInside("COUNTRY", choices)
return models.MullvadCountry(strings.ToLower(s)), err return models.MullvadCountry(strings.ToLower(s)), err
@@ -18,7 +18,7 @@ func (p *paramsReader) GetMullvadCountry() (country models.MullvadCountry, err e
// GetMullvadCity obtains the city for the Mullvad server from the // GetMullvadCity obtains the city for the Mullvad server from the
// environment variable CITY // environment variable CITY
func (p *paramsReader) GetMullvadCity() (country models.MullvadCity, err error) { func (p *reader) GetMullvadCity() (country models.MullvadCity, err error) {
choices := append(constants.MullvadCityChoices(), "") choices := append(constants.MullvadCityChoices(), "")
s, err := p.envParams.GetValueIfInside("CITY", choices) s, err := p.envParams.GetValueIfInside("CITY", choices)
return models.MullvadCity(strings.ToLower(s)), err return models.MullvadCity(strings.ToLower(s)), err
@@ -26,7 +26,7 @@ func (p *paramsReader) GetMullvadCity() (country models.MullvadCity, err error)
// GetMullvadISP obtains the ISP for the Mullvad server from the // GetMullvadISP obtains the ISP for the Mullvad server from the
// environment variable ISP // environment variable ISP
func (p *paramsReader) GetMullvadISP() (country models.MullvadProvider, err error) { func (p *reader) GetMullvadISP() (country models.MullvadProvider, err error) {
choices := append(constants.MullvadProviderChoices(), "") choices := append(constants.MullvadProviderChoices(), "")
s, err := p.envParams.GetValueIfInside("ISP", choices) s, err := p.envParams.GetValueIfInside("ISP", choices)
return models.MullvadProvider(strings.ToLower(s)), err return models.MullvadProvider(strings.ToLower(s)), err
@@ -34,7 +34,7 @@ func (p *paramsReader) GetMullvadISP() (country models.MullvadProvider, err erro
// GetMullvadPort obtains the port to reach the Mullvad server on from the // GetMullvadPort obtains the port to reach the Mullvad server on from the
// environment variable PORT // environment variable PORT
func (p *paramsReader) GetMullvadPort() (port uint16, err error) { func (p *reader) GetMullvadPort() (port uint16, err error) {
n, err := p.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0")) n, err := p.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
return uint16(n), err return uint16(n), err
} }
+82 -80
View File
@@ -1,80 +1,82 @@
package params package params
import ( import (
"fmt" "fmt"
"net" "net"
"strings" "strings"
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
// GetUser obtains the user to use to connect to the VPN servers // GetUser obtains the user to use to connect to the VPN servers
func (p *paramsReader) GetUser() (s string, err error) { func (p *reader) GetUser() (s string, err error) {
defer func() { defer func() {
unsetenvErr := p.unsetEnv("USER") unsetenvErr := p.unsetEnv("USER")
if err == nil { if err == nil {
err = unsetenvErr err = unsetenvErr
} }
}() }()
return p.envParams.GetEnv("USER", libparams.CaseSensitiveValue(), libparams.Compulsory()) return p.envParams.GetEnv("USER", libparams.CaseSensitiveValue(), libparams.Compulsory())
} }
// GetPassword obtains the password to use to connect to the VPN servers // GetPassword obtains the password to use to connect to the VPN servers
func (p *paramsReader) GetPassword() (s string, err error) { func (p *reader) GetPassword() (s string, err error) {
defer func() { defer func() {
unsetenvErr := p.unsetEnv("PASSWORD") unsetenvErr := p.unsetEnv("PASSWORD")
if err == nil { if err == nil {
err = unsetenvErr err = unsetenvErr
} }
}() }()
return p.envParams.GetEnv("PASSWORD", libparams.CaseSensitiveValue(), libparams.Compulsory()) return p.envParams.GetEnv("PASSWORD", libparams.CaseSensitiveValue(), libparams.Compulsory())
} }
// GetNetworkProtocol obtains the network protocol to use to connect to the // GetNetworkProtocol obtains the network protocol to use to connect to the
// VPN servers from the environment variable PROTOCOL // VPN servers from the environment variable PROTOCOL
func (p *paramsReader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) { func (p *reader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) {
s, err := p.envParams.GetValueIfInside("PROTOCOL", []string{"tcp", "udp"}, libparams.Default("udp")) s, err := p.envParams.GetValueIfInside("PROTOCOL", []string{"tcp", "udp"}, libparams.Default("udp"))
return models.NetworkProtocol(s), err return models.NetworkProtocol(s), err
} }
// GetOpenVPNVerbosity obtains the verbosity level for verbosity between 0 and 6 // GetOpenVPNVerbosity obtains the verbosity level for verbosity between 0 and 6
// from the environment variable OPENVPN_VERBOSITY // from the environment variable OPENVPN_VERBOSITY
func (p *paramsReader) GetOpenVPNVerbosity() (verbosity int, err error) { func (p *reader) GetOpenVPNVerbosity() (verbosity int, err error) {
return p.envParams.GetEnvIntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1")) return p.envParams.GetEnvIntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1"))
} }
// GetOpenVPNRoot obtains if openvpn should be run as root // GetOpenVPNRoot obtains if openvpn should be run as root
// from the environment variable OPENVPN_ROOT // from the environment variable OPENVPN_ROOT
func (p *paramsReader) GetOpenVPNRoot() (root bool, err error) { func (p *reader) GetOpenVPNRoot() (root bool, err error) {
return p.envParams.GetYesNo("OPENVPN_ROOT", libparams.Default("no")) return p.envParams.GetYesNo("OPENVPN_ROOT", libparams.Default("no"))
} }
// GetTargetIP obtains the IP address to choose from the list of IP addresses // GetTargetIP obtains the IP address to choose from the list of IP addresses
// available for a particular region, from the environment variable // available for a particular region, from the environment variable
// OPENVPN_TARGET_IP // OPENVPN_TARGET_IP
func (p *paramsReader) GetTargetIP() (ip net.IP, err error) { func (p *reader) GetTargetIP() (ip net.IP, err error) {
s, err := p.envParams.GetEnv("OPENVPN_TARGET_IP") s, err := p.envParams.GetEnv("OPENVPN_TARGET_IP")
if len(s) == 0 { if len(s) == 0 {
return nil, nil return nil, nil
} } else if err != nil {
ip = net.ParseIP(s) return nil, err
if ip == nil { }
return nil, fmt.Errorf("target IP address %q is not valid", s) ip = net.ParseIP(s)
} if ip == nil {
return ip, nil return nil, fmt.Errorf("target IP address %q is not valid", s)
} }
return ip, nil
// GetOpenVPNCipher obtains a custom cipher to use with OpenVPN }
// from the environment variable OPENVPN_CIPHER
func (p *paramsReader) GetOpenVPNCipher() (cipher string, err error) { // GetOpenVPNCipher obtains a custom cipher to use with OpenVPN
cipher, err = p.envParams.GetEnv("OPENVPN_CIPHER") // from the environment variable OPENVPN_CIPHER
return strings.ToLower(cipher), err func (p *reader) GetOpenVPNCipher() (cipher string, err error) {
} cipher, err = p.envParams.GetEnv("OPENVPN_CIPHER")
return strings.ToLower(cipher), err
// GetOpenVPNAuth obtains a custom auth algorithm to use with OpenVPN }
// from the environment variable OPENVPN_AUTH
func (p *paramsReader) GetOpenVPNAuth() (auth string, err error) { // GetOpenVPNAuth obtains a custom auth algorithm to use with OpenVPN
auth, err = p.envParams.GetEnv("OPENVPN_AUTH") // from the environment variable OPENVPN_AUTH
return strings.ToLower(auth), err func (p *reader) GetOpenVPNAuth() (auth string, err error) {
} auth, err = p.envParams.GetEnv("OPENVPN_AUTH")
return strings.ToLower(auth), err
}
+111 -108
View File
@@ -1,108 +1,111 @@
package params package params
import ( import (
"net" "net"
"os" "os"
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
"github.com/qdm12/golibs/verification" "github.com/qdm12/golibs/verification"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
// ParamsReader contains methods to obtain parameters // Reader contains methods to obtain parameters
type ParamsReader interface { type Reader interface {
GetVPNSP() (vpnServiceProvider string, err error) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error)
// DNS over TLS getters // DNS over TLS getters
GetDNSOverTLS() (DNSOverTLS bool, err error) GetDNSOverTLS() (DNSOverTLS bool, err error)
GetDNSOverTLSProviders() (providers []models.DNSProvider, err error) GetDNSOverTLSProviders() (providers []models.DNSProvider, err error)
GetDNSOverTLSCaching() (caching bool, err error) GetDNSOverTLSCaching() (caching bool, err error)
GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error)
GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error)
GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error)
GetDNSMaliciousBlocking() (blocking bool, err error) GetDNSMaliciousBlocking() (blocking bool, err error)
GetDNSSurveillanceBlocking() (blocking bool, err error) GetDNSSurveillanceBlocking() (blocking bool, err error)
GetDNSAdsBlocking() (blocking bool, err error) GetDNSAdsBlocking() (blocking bool, err error)
GetDNSUnblockedHostnames() (hostnames []string, err error) GetDNSUnblockedHostnames() (hostnames []string, err error)
GetDNSOverTLSPrivateAddresses() (privateAddresses []string) GetDNSOverTLSPrivateAddresses() (privateAddresses []string)
GetDNSOverTLSIPv6() (ipv6 bool, err error) GetDNSOverTLSIPv6() (ipv6 bool, err error)
// System // System
GetUID() (uid int, err error) GetUID() (uid int, err error)
GetGID() (gid int, err error) GetGID() (gid int, err error)
GetTimezone() (timezone string, err error) GetTimezone() (timezone string, err error)
GetIPStatusFilepath() (filepath models.Filepath, err error) GetIPStatusFilepath() (filepath models.Filepath, err error)
// Firewall getters // Firewall getters
GetExtraSubnets() (extraSubnets []net.IPNet, err error) GetExtraSubnets() (extraSubnets []net.IPNet, err error)
// VPN getters // VPN getters
GetUser() (s string, err error) GetUser() (s string, err error)
GetPassword() (s string, err error) GetPassword() (s string, err error)
GetNetworkProtocol() (protocol models.NetworkProtocol, err error) GetNetworkProtocol() (protocol models.NetworkProtocol, err error)
GetOpenVPNVerbosity() (verbosity int, err error) GetOpenVPNVerbosity() (verbosity int, err error)
GetOpenVPNRoot() (root bool, err error) GetOpenVPNRoot() (root bool, err error)
GetTargetIP() (ip net.IP, err error) GetTargetIP() (ip net.IP, err error)
GetOpenVPNCipher() (cipher string, err error) GetOpenVPNCipher() (cipher string, err error)
GetOpenVPNAuth() (auth string, err error) GetOpenVPNAuth() (auth string, err error)
// PIA getters // PIA getters
GetPortForwarding() (activated bool, err error) GetPortForwarding() (activated bool, err error)
GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error)
GetPIAEncryption() (models.PIAEncryption, error) GetPIAEncryption() (models.PIAEncryption, error)
GetPIARegion() (models.PIARegion, error) GetPIARegion() (models.PIARegion, error)
// Mullvad getters // Mullvad getters
GetMullvadCountry() (country models.MullvadCountry, err error) GetMullvadCountry() (country models.MullvadCountry, err error)
GetMullvadCity() (country models.MullvadCity, err error) GetMullvadCity() (country models.MullvadCity, err error)
GetMullvadISP() (country models.MullvadProvider, err error) GetMullvadISP() (country models.MullvadProvider, err error)
GetMullvadPort() (port uint16, err error) GetMullvadPort() (port uint16, err error)
// Windscribe getters // Windscribe getters
GetWindscribeRegion() (country models.WindscribeRegion, err error) GetWindscribeRegion() (country models.WindscribeRegion, err error)
GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error)
// Shadowsocks getters // Shadowsocks getters
GetShadowSocks() (activated bool, err error) GetShadowSocks() (activated bool, err error)
GetShadowSocksLog() (activated bool, err error) GetShadowSocksLog() (activated bool, err error)
GetShadowSocksPort() (port uint16, err error) GetShadowSocksPort() (port uint16, err error)
GetShadowSocksPassword() (password string, err error) GetShadowSocksPassword() (password string, err error)
GetShadowSocksMethod() (method string, err error) GetShadowSocksMethod() (method string, err error)
// Tinyproxy getters // Tinyproxy getters
GetTinyProxy() (activated bool, err error) GetTinyProxy() (activated bool, err error)
GetTinyProxyLog() (models.TinyProxyLogLevel, error) GetTinyProxyLog() (models.TinyProxyLogLevel, error)
GetTinyProxyPort() (port uint16, err error) GetTinyProxyPort() (port uint16, err error)
GetTinyProxyUser() (user string, err error) GetTinyProxyUser() (user string, err error)
GetTinyProxyPassword() (password string, err error) GetTinyProxyPassword() (password string, err error)
// Version getters // Version getters
GetVersion() string GetVersion() string
GetBuildDate() string GetBuildDate() string
GetVcsRef() string GetVcsRef() string
} }
type paramsReader struct { type reader struct {
envParams libparams.EnvParams envParams libparams.EnvParams
logger logging.Logger logger logging.Logger
verifier verification.Verifier verifier verification.Verifier
unsetEnv func(key string) error unsetEnv func(key string) error
} }
// NewParamsReader returns a paramsReadeer object to read parameters from // Newreader returns a paramsReadeer object to read parameters from
// environment variables // environment variables
func NewParamsReader(logger logging.Logger) ParamsReader { func NewReader(logger logging.Logger) Reader {
return &paramsReader{ return &reader{
envParams: libparams.NewEnvParams(), envParams: libparams.NewEnvParams(),
logger: logger, logger: logger,
verifier: verification.NewVerifier(), verifier: verification.NewVerifier(),
unsetEnv: os.Unsetenv, unsetEnv: os.Unsetenv,
} }
} }
// GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP // GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP
func (p *paramsReader) GetVPNSP() (vpnServiceProvider string, err error) { func (p *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) {
s, err := p.envParams.GetValueIfInside("VPNSP", []string{"pia", "mullvad", "windscribe"}) s, err := p.envParams.GetValueIfInside("VPNSP", []string{"pia", "private internet access", "mullvad", "windscribe"})
return s, err if s == "pia" {
} s = "private internet access"
}
return models.VPNProvider(s), err
}
+60 -60
View File
@@ -1,60 +1,60 @@
package params package params
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
// GetPortForwarding obtains if port forwarding on the VPN provider server // GetPortForwarding obtains if port forwarding on the VPN provider server
// side is enabled or not from the environment variable PORT_FORWARDING // side is enabled or not from the environment variable PORT_FORWARDING
func (p *paramsReader) GetPortForwarding() (activated bool, err error) { func (p *reader) GetPortForwarding() (activated bool, err error) {
s, err := p.envParams.GetEnv("PORT_FORWARDING", libparams.Default("off")) s, err := p.envParams.GetEnv("PORT_FORWARDING", libparams.Default("off"))
if err != nil { if err != nil {
return false, err return false, err
} }
// Custom for retro-compatibility // Custom for retro-compatibility
if s == "false" || s == "off" { if s == "false" || s == "off" {
return false, nil return false, nil
} else if s == "true" || s == "on" { } else if s == "true" || s == "on" {
return true, nil return true, nil
} }
return false, fmt.Errorf("PORT_FORWARDING can only be \"on\" or \"off\"") return false, fmt.Errorf("PORT_FORWARDING can only be \"on\" or \"off\"")
} }
// GetPortForwardingStatusFilepath obtains the port forwarding status file path // GetPortForwardingStatusFilepath obtains the port forwarding status file path
// from the environment variable PORT_FORWARDING_STATUS_FILE // from the environment variable PORT_FORWARDING_STATUS_FILE
func (p *paramsReader) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) { func (p *reader) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) {
filepathStr, err := p.envParams.GetPath("PORT_FORWARDING_STATUS_FILE", libparams.Default("/forwarded_port"), libparams.CaseSensitiveValue()) filepathStr, err := p.envParams.GetPath("PORT_FORWARDING_STATUS_FILE", libparams.Default("/forwarded_port"), libparams.CaseSensitiveValue())
return models.Filepath(filepathStr), err return models.Filepath(filepathStr), err
} }
// GetPIAEncryption obtains the encryption level for the PIA connection // GetPIAEncryption obtains the encryption level for the PIA connection
// from the environment variable PIA_ENCRYPTION, and using ENCRYPTION for // from the environment variable PIA_ENCRYPTION, and using ENCRYPTION for
// retro compatibility // retro compatibility
func (p *paramsReader) GetPIAEncryption() (models.PIAEncryption, error) { func (p *reader) GetPIAEncryption() (models.PIAEncryption, error) {
// Retro-compatibility // Retro-compatibility
s, err := p.envParams.GetValueIfInside("ENCRYPTION", []string{"normal", "strong", ""}) s, err := p.envParams.GetValueIfInside("ENCRYPTION", []string{"normal", "strong", ""})
if err != nil { if err != nil {
return "", err return "", err
} else if len(s) != 0 { } else if len(s) != 0 {
p.logger.Warn("You are using the old environment variable ENCRYPTION, please consider changing it to PIA_ENCRYPTION") p.logger.Warn("You are using the old environment variable ENCRYPTION, please consider changing it to PIA_ENCRYPTION")
return models.PIAEncryption(s), nil return models.PIAEncryption(s), nil
} }
s, err = p.envParams.GetValueIfInside("PIA_ENCRYPTION", []string{"normal", "strong"}, libparams.Default("strong")) s, err = p.envParams.GetValueIfInside("PIA_ENCRYPTION", []string{"normal", "strong"}, libparams.Default("strong"))
return models.PIAEncryption(s), err return models.PIAEncryption(s), err
} }
// GetPIARegion obtains the region for the PIA server from the // GetPIARegion obtains the region for the PIA server from the
// environment variable REGION // environment variable REGION
func (p *paramsReader) GetPIARegion() (region models.PIARegion, err error) { func (p *reader) GetPIARegion() (region models.PIARegion, err error) {
choices := append(constants.PIAGeoChoices(), "") choices := append(constants.PIAGeoChoices(), "")
s, err := p.envParams.GetValueIfInside("REGION", choices) s, err := p.envParams.GetValueIfInside("REGION", choices)
if len(s) == 0 { // Suggestion by @rorph https://github.com/rorph if len(s) == 0 { // Suggestion by @rorph https://github.com/rorph
s = choices[rand.Int()%len(choices)] s = choices[rand.Int()%len(choices)] //nolint:gosec
} }
return models.PIARegion(s), err return models.PIARegion(s), err
} }
+51 -46
View File
@@ -1,46 +1,51 @@
package params package params
import ( import (
"strconv" "strconv"
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
) )
// GetShadowSocks obtains if ShadowSocks is on from the environment variable // GetShadowSocks obtains if ShadowSocks is on from the environment variable
// SHADOWSOCKS // SHADOWSOCKS
func (p *paramsReader) GetShadowSocks() (activated bool, err error) { func (p *reader) GetShadowSocks() (activated bool, err error) {
return p.envParams.GetOnOff("SHADOWSOCKS", libparams.Default("off")) return p.envParams.GetOnOff("SHADOWSOCKS", libparams.Default("off"))
} }
// GetShadowSocksLog obtains the ShadowSocks log level from the environment variable // GetShadowSocksLog obtains the ShadowSocks log level from the environment variable
// SHADOWSOCKS_LOG // SHADOWSOCKS_LOG
func (p *paramsReader) GetShadowSocksLog() (activated bool, err error) { func (p *reader) GetShadowSocksLog() (activated bool, err error) {
return p.envParams.GetOnOff("SHADOWSOCKS_LOG", libparams.Default("off")) return p.envParams.GetOnOff("SHADOWSOCKS_LOG", libparams.Default("off"))
} }
// GetShadowSocksPort obtains the ShadowSocks listening port from the environment variable // GetShadowSocksPort obtains the ShadowSocks listening port from the environment variable
// SHADOWSOCKS_PORT // SHADOWSOCKS_PORT
func (p *paramsReader) GetShadowSocksPort() (port uint16, err error) { func (p *reader) GetShadowSocksPort() (port uint16, err error) {
portStr, err := p.envParams.GetEnv("SHADOWSOCKS_PORT", libparams.Default("8388")) portStr, err := p.envParams.GetEnv("SHADOWSOCKS_PORT", libparams.Default("8388"))
if err != nil { if err != nil {
return 0, err return 0, err
} }
if err := p.verifier.VerifyPort(portStr); err != nil { if err := p.verifier.VerifyPort(portStr); err != nil {
return 0, err return 0, err
} }
portUint64, err := strconv.ParseUint(portStr, 10, 16) portUint64, err := strconv.ParseUint(portStr, 10, 16)
return uint16(portUint64), err return uint16(portUint64), err
} }
// GetShadowSocksPassword obtains the ShadowSocks server password from the environment variable // GetShadowSocksPassword obtains the ShadowSocks server password from the environment variable
// SHADOWSOCKS_PASSWORD // SHADOWSOCKS_PASSWORD
func (p *paramsReader) GetShadowSocksPassword() (password string, err error) { func (p *reader) GetShadowSocksPassword() (password string, err error) {
defer p.unsetEnv("SHADOWSOCKS_PASSWORD") defer func() {
return p.envParams.GetEnv("SHADOWSOCKS_PASSWORD", libparams.CaseSensitiveValue()) unsetErr := p.unsetEnv("SHADOWSOCKS_PASSWORD")
} if err == nil {
err = unsetErr
// GetShadowSocksMethod obtains the ShadowSocks method to use from the environment variable }
// SHADOWSOCKS_METHOD }()
func (p *paramsReader) GetShadowSocksMethod() (method string, err error) { return p.envParams.GetEnv("SHADOWSOCKS_PASSWORD", libparams.CaseSensitiveValue())
return p.envParams.GetEnv("SHADOWSOCKS_METHOD", libparams.Default("chacha20-ietf-poly1305")) }
}
// GetShadowSocksMethod obtains the ShadowSocks method to use from the environment variable
// SHADOWSOCKS_METHOD
func (p *reader) GetShadowSocksMethod() (method string, err error) {
return p.envParams.GetEnv("SHADOWSOCKS_METHOD", libparams.Default("chacha20-ietf-poly1305"))
}
+28 -28
View File
@@ -1,28 +1,28 @@
package params package params
import ( import (
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
// GetUID obtains the user ID to use from the environment variable UID // GetUID obtains the user ID to use from the environment variable UID
func (p *paramsReader) GetUID() (uid int, err error) { func (p *reader) GetUID() (uid int, err error) {
return p.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000")) return p.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000"))
} }
// GetGID obtains the group ID to use from the environment variable GID // GetGID obtains the group ID to use from the environment variable GID
func (p *paramsReader) GetGID() (gid int, err error) { func (p *reader) GetGID() (gid int, err error) {
return p.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000")) return p.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000"))
} }
// GetTZ obtains the timezone from the environment variable TZ // GetTZ obtains the timezone from the environment variable TZ
func (p *paramsReader) GetTimezone() (timezone string, err error) { func (p *reader) GetTimezone() (timezone string, err error) {
return p.envParams.GetEnv("TZ") return p.envParams.GetEnv("TZ")
} }
// GetIPStatusFilepath obtains the IP status file path // GetIPStatusFilepath obtains the IP status file path
// from the environment variable IP_STATUS_FILE // from the environment variable IP_STATUS_FILE
func (p *paramsReader) GetIPStatusFilepath() (filepath models.Filepath, err error) { func (p *reader) GetIPStatusFilepath() (filepath models.Filepath, err error) {
filepathStr, err := p.envParams.GetPath("IP_STATUS_FILE", libparams.Default("/ip"), libparams.CaseSensitiveValue()) filepathStr, err := p.envParams.GetPath("IP_STATUS_FILE", libparams.Default("/ip"), libparams.CaseSensitiveValue())
return models.Filepath(filepathStr), err return models.Filepath(filepathStr), err
} }
+116 -94
View File
@@ -1,94 +1,116 @@
package params package params
import ( import (
"strconv" "strconv"
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
// GetTinyProxy obtains if TinyProxy is on from the environment variable // GetTinyProxy obtains if TinyProxy is on from the environment variable
// TINYPROXY, and using PROXY as a retro-compatibility name // TINYPROXY, and using PROXY as a retro-compatibility name
func (p *paramsReader) GetTinyProxy() (activated bool, err error) { func (p *reader) GetTinyProxy() (activated bool, err error) {
// Retro-compatibility // Retro-compatibility
s, err := p.envParams.GetEnv("PROXY") s, err := p.envParams.GetEnv("PROXY")
if err != nil { if err != nil {
return false, err return false, err
} else if len(s) != 0 { } else if len(s) != 0 {
p.logger.Warn("You are using the old environment variable PROXY, please consider changing it to TINYPROXY") p.logger.Warn("You are using the old environment variable PROXY, please consider changing it to TINYPROXY")
return p.envParams.GetOnOff("PROXY", libparams.Compulsory()) return p.envParams.GetOnOff("PROXY", libparams.Compulsory())
} }
return p.envParams.GetOnOff("TINYPROXY", libparams.Default("off")) return p.envParams.GetOnOff("TINYPROXY", libparams.Default("off"))
} }
// GetTinyProxyLog obtains the TinyProxy log level from the environment variable // GetTinyProxyLog obtains the TinyProxy log level from the environment variable
// TINYPROXY_LOG, and using PROXY_LOG_LEVEL as a retro-compatibility name // TINYPROXY_LOG, and using PROXY_LOG_LEVEL as a retro-compatibility name
func (p *paramsReader) GetTinyProxyLog() (models.TinyProxyLogLevel, error) { func (p *reader) GetTinyProxyLog() (models.TinyProxyLogLevel, error) {
// Retro-compatibility // Retro-compatibility
s, err := p.envParams.GetEnv("PROXY_LOG_LEVEL") s, err := p.envParams.GetEnv("PROXY_LOG_LEVEL")
if err != nil { if err != nil {
return models.TinyProxyLogLevel(s), err return models.TinyProxyLogLevel(s), err
} else if len(s) != 0 { } else if len(s) != 0 {
p.logger.Warn("You are using the old environment variable PROXY_LOG_LEVEL, please consider changing it to TINYPROXY_LOG") p.logger.Warn("You are using the old environment variable PROXY_LOG_LEVEL, please consider changing it to TINYPROXY_LOG")
s, err = p.envParams.GetValueIfInside("PROXY_LOG_LEVEL", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Compulsory()) s, err = p.envParams.GetValueIfInside("PROXY_LOG_LEVEL", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Compulsory())
return models.TinyProxyLogLevel(s), err return models.TinyProxyLogLevel(s), err
} }
s, err = p.envParams.GetValueIfInside("TINYPROXY_LOG", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Default("Connect")) s, err = p.envParams.GetValueIfInside("TINYPROXY_LOG", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Default("Connect"))
return models.TinyProxyLogLevel(s), err return models.TinyProxyLogLevel(s), err
} }
// GetTinyProxyPort obtains the TinyProxy listening port from the environment variable // GetTinyProxyPort obtains the TinyProxy listening port from the environment variable
// TINYPROXY_PORT, and using PROXY_PORT as a retro-compatibility name // TINYPROXY_PORT, and using PROXY_PORT as a retro-compatibility name
func (p *paramsReader) GetTinyProxyPort() (port uint16, err error) { func (p *reader) GetTinyProxyPort() (port uint16, err error) {
// Retro-compatibility // Retro-compatibility
portStr, err := p.envParams.GetEnv("PROXY_PORT") portStr, err := p.envParams.GetEnv("PROXY_PORT")
if err != nil { switch {
return 0, err case err != nil:
} else if len(portStr) != 0 { return 0, err
p.logger.Warn("You are using the old environment variable PROXY_PORT, please consider changing it to TINYPROXY_PORT") case len(portStr) != 0:
} else { p.logger.Warn("You are using the old environment variable PROXY_PORT, please consider changing it to TINYPROXY_PORT")
portStr, err = p.envParams.GetEnv("TINYPROXY_PORT", libparams.Default("8888")) default:
if err != nil { portStr, err = p.envParams.GetEnv("TINYPROXY_PORT", libparams.Default("8888"))
return 0, err if err != nil {
} return 0, err
} }
if err := p.verifier.VerifyPort(portStr); err != nil { }
return 0, err if err := p.verifier.VerifyPort(portStr); err != nil {
} return 0, err
portUint64, err := strconv.ParseUint(portStr, 10, 16) }
return uint16(portUint64), err portUint64, err := strconv.ParseUint(portStr, 10, 16)
} return uint16(portUint64), err
}
// GetTinyProxyUser obtains the TinyProxy server user from the environment variable
// TINYPROXY_USER, and using PROXY_USER as a retro-compatibility name // GetTinyProxyUser obtains the TinyProxy server user from the environment variable
func (p *paramsReader) GetTinyProxyUser() (user string, err error) { // TINYPROXY_USER, and using PROXY_USER as a retro-compatibility name
defer p.unsetEnv("PROXY_USER") func (p *reader) GetTinyProxyUser() (user string, err error) {
defer p.unsetEnv("TINYPROXY_USER") defer func() {
// Retro-compatibility unsetErr := p.unsetEnv("PROXY_USER")
user, err = p.envParams.GetEnv("PROXY_USER", libparams.CaseSensitiveValue()) if err == nil {
if err != nil { err = unsetErr
return user, err }
} }()
if len(user) != 0 { defer func() {
p.logger.Warn("You are using the old environment variable PROXY_USER, please consider changing it to TINYPROXY_USER") unsetErr := p.unsetEnv("TINYPROXY_USER")
return user, nil if err == nil {
} err = unsetErr
return p.envParams.GetEnv("TINYPROXY_USER", libparams.CaseSensitiveValue()) }
} }()
// Retro-compatibility
// GetTinyProxyPassword obtains the TinyProxy server password from the environment variable user, err = p.envParams.GetEnv("PROXY_USER", libparams.CaseSensitiveValue())
// TINYPROXY_PASSWORD, and using PROXY_PASSWORD as a retro-compatibility name if err != nil {
func (p *paramsReader) GetTinyProxyPassword() (password string, err error) { return user, err
defer p.unsetEnv("PROXY_PASSWORD") }
defer p.unsetEnv("TINYPROXY_PASSWORD") if len(user) != 0 {
// Retro-compatibility p.logger.Warn("You are using the old environment variable PROXY_USER, please consider changing it to TINYPROXY_USER")
password, err = p.envParams.GetEnv("PROXY_PASSWORD", libparams.CaseSensitiveValue()) return user, nil
if err != nil { }
return password, err return p.envParams.GetEnv("TINYPROXY_USER", libparams.CaseSensitiveValue())
} }
if len(password) != 0 {
p.logger.Warn("You are using the old environment variable PROXY_PASSWORD, please consider changing it to TINYPROXY_PASSWORD") // GetTinyProxyPassword obtains the TinyProxy server password from the environment variable
return password, nil // TINYPROXY_PASSWORD, and using PROXY_PASSWORD as a retro-compatibility name
} func (p *reader) GetTinyProxyPassword() (password string, err error) {
return p.envParams.GetEnv("TINYPROXY_PASSWORD", libparams.CaseSensitiveValue()) defer func() {
} unsetErr := p.unsetEnv("PROXY_PASSWORD")
if err == nil {
err = unsetErr
}
}()
defer func() {
unsetErr := p.unsetEnv("TINYPROXY_PASSWORD")
if err == nil {
err = unsetErr
}
}()
// Retro-compatibility
password, err = p.envParams.GetEnv("PROXY_PASSWORD", libparams.CaseSensitiveValue())
if err != nil {
return password, err
}
if len(password) != 0 {
p.logger.Warn("You are using the old environment variable PROXY_PASSWORD, please consider changing it to TINYPROXY_PASSWORD")
return password, nil
}
return p.envParams.GetEnv("TINYPROXY_PASSWORD", libparams.CaseSensitiveValue())
}
+3 -3
View File
@@ -4,17 +4,17 @@ import (
libparams "github.com/qdm12/golibs/params" libparams "github.com/qdm12/golibs/params"
) )
func (p *paramsReader) GetVersion() string { func (p *reader) GetVersion() string {
version, _ := p.envParams.GetEnv("VERSION", libparams.Default("?"), libparams.CaseSensitiveValue()) version, _ := p.envParams.GetEnv("VERSION", libparams.Default("?"), libparams.CaseSensitiveValue())
return version return version
} }
func (p *paramsReader) GetBuildDate() string { func (p *reader) GetBuildDate() string {
buildDate, _ := p.envParams.GetEnv("BUILD_DATE", libparams.Default("?"), libparams.CaseSensitiveValue()) buildDate, _ := p.envParams.GetEnv("BUILD_DATE", libparams.Default("?"), libparams.CaseSensitiveValue())
return buildDate return buildDate
} }
func (p *paramsReader) GetVcsRef() string { func (p *reader) GetVcsRef() string {
buildDate, _ := p.envParams.GetEnv("VCS_REF", libparams.Default("?"), libparams.CaseSensitiveValue()) buildDate, _ := p.envParams.GetEnv("VCS_REF", libparams.Default("?"), libparams.CaseSensitiveValue())
return buildDate return buildDate
} }
+3 -4
View File
@@ -11,15 +11,14 @@ import (
// GetWindscribeRegion obtains the region for the Windscribe server from the // GetWindscribeRegion obtains the region for the Windscribe server from the
// environment variable REGION // environment variable REGION
func (p *paramsReader) GetWindscribeRegion() (country models.WindscribeRegion, err error) { func (p *reader) GetWindscribeRegion() (country models.WindscribeRegion, err error) {
choices := append(constants.WindscribeRegionChoices()) s, err := p.envParams.GetValueIfInside("REGION", constants.WindscribeRegionChoices())
s, err := p.envParams.GetValueIfInside("REGION", choices)
return models.WindscribeRegion(strings.ToLower(s)), err return models.WindscribeRegion(strings.ToLower(s)), err
} }
// GetMullvadPort obtains the port to reach the Mullvad server on from the // GetMullvadPort obtains the port to reach the Mullvad server on from the
// environment variable PORT // environment variable PORT
func (p *paramsReader) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) { func (p *reader) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) {
n, err := p.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0")) n, err := p.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
if err != nil { if err != nil {
return 0, err return 0, err
+5 -5
View File
@@ -14,7 +14,7 @@ func (c *configurator) GetOpenVPNConnections(region models.PIARegion, protocol m
geoMapping := constants.PIAGeoToSubdomainMapping() geoMapping := constants.PIAGeoToSubdomainMapping()
var subdomain string var subdomain string
for r, s := range geoMapping { for r, s := range geoMapping {
if strings.ToLower(string(region)) == strings.ToLower(string(r)) { if strings.EqualFold(string(region), string(r)) {
subdomain = s subdomain = s
break break
} }
@@ -75,8 +75,8 @@ func (c *configurator) BuildConf(connections []models.OpenVPNConnection, encrypt
if len(auth) == 0 { if len(auth) == 0 {
auth = "sha1" auth = "sha1"
} }
X509CRL = constants.PIAX509CRL_NORMAL X509CRL = constants.PiaX509CRLNormal
certificate = constants.PIACertificate_NORMAL certificate = constants.PIACertificateNormal
} else { // strong encryption } else { // strong encryption
if len(cipher) == 0 { if len(cipher) == 0 {
cipher = "aes-256-cbc" cipher = "aes-256-cbc"
@@ -84,8 +84,8 @@ func (c *configurator) BuildConf(connections []models.OpenVPNConnection, encrypt
if len(auth) == 0 { if len(auth) == 0 {
auth = "sha256" auth = "sha256"
} }
X509CRL = constants.PIAX509CRL_STRONG X509CRL = constants.PiaX509CRLStrong
certificate = constants.PIACertificate_STRONG certificate = constants.PIACertificateStrong
} }
lines := []string{ lines := []string{
"client", "client",
+7 -5
View File
@@ -4,6 +4,7 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http"
"github.com/qdm12/golibs/files" "github.com/qdm12/golibs/files"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
@@ -19,11 +20,12 @@ func (c *configurator) GetPortForward() (port uint16, err error) {
clientID := hex.EncodeToString(b) clientID := hex.EncodeToString(b)
url := fmt.Sprintf("%s/?client_id=%s", constants.PIAPortForwardURL, clientID) url := fmt.Sprintf("%s/?client_id=%s", constants.PIAPortForwardURL, clientID)
content, status, err := c.client.GetContent(url) content, status, err := c.client.GetContent(url)
if err != nil { switch {
case err != nil:
return 0, err return 0, err
} else if status != 200 { case status != http.StatusOK:
return 0, fmt.Errorf("status is %d for %s; does your PIA server support port forwarding?", status, url) return 0, fmt.Errorf("status is %d for %s; does your PIA server support port forwarding?", status, url)
} else if len(content) == 0 { case len(content) == 0:
return 0, fmt.Errorf("port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding") return 0, fmt.Errorf("port forwarding is already activated on this connection, has expired, or you are not connected to a PIA region that supports port forwarding")
} }
body := struct { body := struct {
@@ -42,7 +44,7 @@ func (c *configurator) WritePortForward(filepath models.Filepath, port uint16, u
string(filepath), string(filepath),
[]string{fmt.Sprintf("%d", port)}, []string{fmt.Sprintf("%d", port)},
files.Ownership(uid, gid), files.Ownership(uid, gid),
files.Permissions(400)) files.Permissions(0400))
} }
func (c *configurator) AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error) { func (c *configurator) AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error) {
@@ -52,5 +54,5 @@ func (c *configurator) AllowPortForwardFirewall(device models.VPNDevice, port ui
func (c *configurator) ClearPortForward(filepath models.Filepath, uid, gid int) (err error) { func (c *configurator) ClearPortForward(filepath models.Filepath, uid, gid int) (err error) {
c.logger.Info("Clearing forwarded port status file %s", filepath) c.logger.Info("Clearing forwarded port status file %s", filepath)
return c.fileManager.WriteToFile(string(filepath), nil, files.Ownership(uid, gid), files.Permissions(400)) return c.fileManager.WriteToFile(string(filepath), nil, files.Ownership(uid, gid), files.Permissions(0400))
} }
+1 -1
View File
@@ -72,7 +72,7 @@ func parseRoutingEntry(s string) (r routingEntry, err error) {
return r, nil return r, nil
} }
func reversedHexToIPv4(reversedHex string) (IP net.IP, err error) { func reversedHexToIPv4(reversedHex string) (ip net.IP, err error) {
bytes, err := hex.DecodeString(reversedHex) bytes, err := hex.DecodeString(reversedHex)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot parse reversed IP hex %q: %s", reversedHex, err) return nil, fmt.Errorf("cannot parse reversed IP hex %q: %s", reversedHex, err)
+138 -133
View File
@@ -1,133 +1,138 @@
package settings package settings
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// DNS contains settings to configure Unbound for DNS over TLS operation // DNS contains settings to configure Unbound for DNS over TLS operation
type DNS struct { type DNS struct {
Enabled bool Enabled bool
Providers []models.DNSProvider Providers []models.DNSProvider
AllowedHostnames []string AllowedHostnames []string
PrivateAddresses []string PrivateAddresses []string
Caching bool Caching bool
BlockMalicious bool BlockMalicious bool
BlockSurveillance bool BlockSurveillance bool
BlockAds bool BlockAds bool
VerbosityLevel uint8 VerbosityLevel uint8
VerbosityDetailsLevel uint8 VerbosityDetailsLevel uint8
ValidationLogLevel uint8 ValidationLogLevel uint8
IPv6 bool IPv6 bool
} }
func (d *DNS) String() string { func (d *DNS) String() string {
if !d.Enabled { if !d.Enabled {
return "DNS over TLS settings: disabled" return "DNS over TLS settings: disabled"
} }
caching, blockMalicious, blockSurveillance, blockAds, ipv6 := "disabled", "disabed", "disabed", "disabed", "disabed" const (
if d.Caching { enabled = "enabled"
caching = "enabled" disabled = "disabled"
} )
if d.BlockMalicious { caching, blockMalicious, blockSurveillance, blockAds, ipv6 := disabled, disabled, disabled, disabled, disabled
blockMalicious = "enabled" if d.Caching {
} caching = enabled
if d.BlockSurveillance { }
blockSurveillance = "enabled" if d.BlockMalicious {
} blockMalicious = enabled
if d.BlockAds { }
blockAds = "enabled" if d.BlockSurveillance {
} blockSurveillance = enabled
if d.IPv6 { }
ipv6 = "enabled" if d.BlockAds {
} blockAds = enabled
var providersStr []string }
for _, provider := range d.Providers { if d.IPv6 {
providersStr = append(providersStr, string(provider)) ipv6 = enabled
} }
settingsList := []string{ providersStr := make([]string, len(d.Providers))
"DNS over TLS settings:", for i := range d.Providers {
"DNS over TLS provider:\n |--" + strings.Join(providersStr, "\n |--"), providersStr[i] = string(d.Providers[i])
"Caching: " + caching, }
"Block malicious: " + blockMalicious, settingsList := []string{
"Block surveillance: " + blockSurveillance, "DNS over TLS settings:",
"Block ads: " + blockAds, "DNS over TLS provider:\n |--" + strings.Join(providersStr, "\n |--"),
"Allowed hostnames:\n |--" + strings.Join(d.AllowedHostnames, "\n |--"), "Caching: " + caching,
"Private addresses:\n |--" + strings.Join(d.PrivateAddresses, "\n |--"), "Block malicious: " + blockMalicious,
"Verbosity level: " + fmt.Sprintf("%d/5", d.VerbosityLevel), "Block surveillance: " + blockSurveillance,
"Verbosity details level: " + fmt.Sprintf("%d/4", d.VerbosityDetailsLevel), "Block ads: " + blockAds,
"Validation log level: " + fmt.Sprintf("%d/2", d.ValidationLogLevel), "Allowed hostnames:\n |--" + strings.Join(d.AllowedHostnames, "\n |--"),
"IPv6 resolution: " + ipv6, "Private addresses:\n |--" + strings.Join(d.PrivateAddresses, "\n |--"),
} "Verbosity level: " + fmt.Sprintf("%d/5", d.VerbosityLevel),
return strings.Join(settingsList, "\n |--") "Verbosity details level: " + fmt.Sprintf("%d/4", d.VerbosityDetailsLevel),
} "Validation log level: " + fmt.Sprintf("%d/2", d.ValidationLogLevel),
"IPv6 resolution: " + ipv6,
// GetDNSSettings obtains DNS over TLS settings from environment variables using the params package. }
func GetDNSSettings(params params.ParamsReader) (settings DNS, err error) { return strings.Join(settingsList, "\n |--")
settings.Enabled, err = params.GetDNSOverTLS() }
if err != nil || !settings.Enabled {
return settings, err // GetDNSSettings obtains DNS over TLS settings from environment variables using the params package.
} func GetDNSSettings(paramsReader params.Reader) (settings DNS, err error) {
settings.Providers, err = params.GetDNSOverTLSProviders() settings.Enabled, err = paramsReader.GetDNSOverTLS()
if err != nil { if err != nil || !settings.Enabled {
return settings, err return settings, err
} }
settings.AllowedHostnames, err = params.GetDNSUnblockedHostnames() settings.Providers, err = paramsReader.GetDNSOverTLSProviders()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Caching, err = params.GetDNSOverTLSCaching() settings.AllowedHostnames, err = paramsReader.GetDNSUnblockedHostnames()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.BlockMalicious, err = params.GetDNSMaliciousBlocking() settings.Caching, err = paramsReader.GetDNSOverTLSCaching()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.BlockSurveillance, err = params.GetDNSSurveillanceBlocking() settings.BlockMalicious, err = paramsReader.GetDNSMaliciousBlocking()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.BlockAds, err = params.GetDNSAdsBlocking() settings.BlockSurveillance, err = paramsReader.GetDNSSurveillanceBlocking()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.VerbosityLevel, err = params.GetDNSOverTLSVerbosity() settings.BlockAds, err = paramsReader.GetDNSAdsBlocking()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.VerbosityDetailsLevel, err = params.GetDNSOverTLSVerbosityDetails() settings.VerbosityLevel, err = paramsReader.GetDNSOverTLSVerbosity()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.ValidationLogLevel, err = params.GetDNSOverTLSValidationLogLevel() settings.VerbosityDetailsLevel, err = paramsReader.GetDNSOverTLSVerbosityDetails()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.PrivateAddresses = params.GetDNSOverTLSPrivateAddresses() settings.ValidationLogLevel, err = paramsReader.GetDNSOverTLSValidationLogLevel()
settings.IPv6, err = params.GetDNSOverTLSIPv6() if err != nil {
if err != nil { return settings, err
return settings, err }
} settings.PrivateAddresses = paramsReader.GetDNSOverTLSPrivateAddresses()
settings.IPv6, err = paramsReader.GetDNSOverTLSIPv6()
// Consistency check if err != nil {
IPv6Support := false return settings, err
for _, provider := range settings.Providers { }
providerData, ok := constants.DNSProviderMapping()[provider]
if !ok { // Consistency check
return settings, fmt.Errorf("DNS provider %q does not have associated data", provider) IPv6Support := false
} else if !providerData.SupportsTLS { for _, provider := range settings.Providers {
return settings, fmt.Errorf("DNS provider %q does not support DNS over TLS", provider) providerData, ok := constants.DNSProviderMapping()[provider]
} else if providerData.SupportsIPv6 { switch {
IPv6Support = true case !ok:
} return settings, fmt.Errorf("DNS provider %q does not have associated data", provider)
} case !providerData.SupportsTLS:
if settings.IPv6 && !IPv6Support { return settings, fmt.Errorf("DNS provider %q does not support DNS over TLS", provider)
return settings, fmt.Errorf("None of the DNS over TLS provider(s) set support IPv6") case providerData.SupportsIPv6:
} IPv6Support = true
return settings, nil }
} }
if settings.IPv6 && !IPv6Support {
return settings, fmt.Errorf("None of the DNS over TLS provider(s) set support IPv6")
}
return settings, nil
}
+34 -34
View File
@@ -1,34 +1,34 @@
package settings package settings
import ( import (
"net" "net"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// Firewall contains settings to customize the firewall operation // Firewall contains settings to customize the firewall operation
type Firewall struct { type Firewall struct {
AllowedSubnets []net.IPNet AllowedSubnets []net.IPNet
} }
func (f *Firewall) String() string { func (f *Firewall) String() string {
var allowedSubnets []string allowedSubnets := make([]string, len(f.AllowedSubnets))
for _, net := range f.AllowedSubnets { for i := range f.AllowedSubnets {
allowedSubnets = append(allowedSubnets, net.String()) allowedSubnets[i] = f.AllowedSubnets[i].String()
} }
settingsList := []string{ settingsList := []string{
"Firewall settings:", "Firewall settings:",
"Allowed subnets: " + strings.Join(allowedSubnets, ", "), "Allowed subnets: " + strings.Join(allowedSubnets, ", "),
} }
return strings.Join(settingsList, "\n |--") return strings.Join(settingsList, "\n |--")
} }
// GetFirewallSettings obtains firewall settings from environment variables using the params package. // GetFirewallSettings obtains firewall settings from environment variables using the params package.
func GetFirewallSettings(params params.ParamsReader) (settings Firewall, err error) { func GetFirewallSettings(paramsReader params.Reader) (settings Firewall, err error) {
settings.AllowedSubnets, err = params.GetExtraSubnets() settings.AllowedSubnets, err = paramsReader.GetExtraSubnets()
if err != nil { if err != nil {
return settings, err return settings, err
} }
return settings, nil return settings, nil
} }
+56 -56
View File
@@ -1,56 +1,56 @@
package settings package settings
import ( import (
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// Mullvad contains the settings to connect to a Mullvad server // Mullvad contains the settings to connect to a Mullvad server
type Mullvad struct { type Mullvad struct {
User string User string
Country models.MullvadCountry Country models.MullvadCountry
City models.MullvadCity City models.MullvadCity
ISP models.MullvadProvider ISP models.MullvadProvider
Port uint16 Port uint16
} }
func (m *Mullvad) String() string { func (m *Mullvad) String() string {
settingsList := []string{ settingsList := []string{
"Mullvad settings:", "Mullvad settings:",
"User: [redacted]", "User: [redacted]",
"Country: " + string(m.Country), "Country: " + string(m.Country),
"City: " + string(m.City), "City: " + string(m.City),
"ISP: " + string(m.ISP), "ISP: " + string(m.ISP),
"Port: " + string(m.Port), "Port: " + string(m.Port),
} }
return strings.Join(settingsList, "\n |--") return strings.Join(settingsList, "\n |--")
} }
// GetMullvadSettings obtains Mullvad settings from environment variables using the params package. // GetMullvadSettings obtains Mullvad settings from environment variables using the params package.
func GetMullvadSettings(params params.ParamsReader) (settings Mullvad, err error) { func GetMullvadSettings(paramsReader params.Reader) (settings Mullvad, err error) {
settings.User, err = params.GetUser() settings.User, err = paramsReader.GetUser()
if err != nil { if err != nil {
return settings, err return settings, err
} }
// Remove spaces in user ID to simplify user's life, thanks @JeordyR // Remove spaces in user ID to simplify user's life, thanks @JeordyR
settings.User = strings.ReplaceAll(settings.User, " ", "") settings.User = strings.ReplaceAll(settings.User, " ", "")
settings.Country, err = params.GetMullvadCountry() settings.Country, err = paramsReader.GetMullvadCountry()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.City, err = params.GetMullvadCity() settings.City, err = paramsReader.GetMullvadCity()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.ISP, err = params.GetMullvadISP() settings.ISP, err = paramsReader.GetMullvadISP()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Port, err = params.GetMullvadPort() settings.Port, err = paramsReader.GetMullvadPort()
if err != nil { if err != nil {
return settings, err return settings, err
} }
return settings, nil return settings, nil
} }
+66 -66
View File
@@ -1,66 +1,66 @@
package settings package settings
import ( import (
"fmt" "fmt"
"net" "net"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// OpenVPN contains settings to configure the OpenVPN client // OpenVPN contains settings to configure the OpenVPN client
type OpenVPN struct { type OpenVPN struct {
NetworkProtocol models.NetworkProtocol NetworkProtocol models.NetworkProtocol
Verbosity int Verbosity int
Root bool Root bool
TargetIP net.IP TargetIP net.IP
Cipher string Cipher string
Auth string Auth string
} }
// GetOpenVPNSettings obtains the OpenVPN settings using the params functions // GetOpenVPNSettings obtains the OpenVPN settings using the params functions
func GetOpenVPNSettings(params params.ParamsReader) (settings OpenVPN, err error) { func GetOpenVPNSettings(paramsReader params.Reader) (settings OpenVPN, err error) {
settings.NetworkProtocol, err = params.GetNetworkProtocol() settings.NetworkProtocol, err = paramsReader.GetNetworkProtocol()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Verbosity, err = params.GetOpenVPNVerbosity() settings.Verbosity, err = paramsReader.GetOpenVPNVerbosity()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Root, err = params.GetOpenVPNRoot() settings.Root, err = paramsReader.GetOpenVPNRoot()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.TargetIP, err = params.GetTargetIP() settings.TargetIP, err = paramsReader.GetTargetIP()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Cipher, err = params.GetOpenVPNCipher() settings.Cipher, err = paramsReader.GetOpenVPNCipher()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Auth, err = params.GetOpenVPNAuth() settings.Auth, err = paramsReader.GetOpenVPNAuth()
if err != nil { if err != nil {
return settings, err return settings, err
} }
return settings, nil return settings, nil
} }
func (o *OpenVPN) String() string { func (o *OpenVPN) String() string {
runAsRoot := "no" runAsRoot := "no"
if o.Root { if o.Root {
runAsRoot = "yes" runAsRoot = "yes"
} }
settingsList := []string{ settingsList := []string{
"OpenVPN settings:", "OpenVPN settings:",
"Network protocol: " + string(o.NetworkProtocol), "Network protocol: " + string(o.NetworkProtocol),
"Verbosity level: " + fmt.Sprintf("%d", o.Verbosity), "Verbosity level: " + fmt.Sprintf("%d", o.Verbosity),
"Run as root: " + runAsRoot, "Run as root: " + runAsRoot,
"Target IP address: " + o.TargetIP.String(), "Target IP address: " + o.TargetIP.String(),
"Custom cipher: " + o.Cipher, "Custom cipher: " + o.Cipher,
"Custom auth algorithm: " + o.Auth, "Custom auth algorithm: " + o.Auth,
} }
return strings.Join(settingsList, "\n|--") return strings.Join(settingsList, "\n|--")
} }
+74 -74
View File
@@ -1,74 +1,74 @@
package settings package settings
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// PIA contains the settings to connect to a PIA server // PIA contains the settings to connect to a PIA server
type PIA struct { type PIA struct {
User string User string
Password string Password string
Encryption models.PIAEncryption Encryption models.PIAEncryption
Region models.PIARegion Region models.PIARegion
PortForwarding PortForwarding PortForwarding PortForwarding
} }
// PortForwarding contains settings for port forwarding // PortForwarding contains settings for port forwarding
type PortForwarding struct { type PortForwarding struct {
Enabled bool Enabled bool
Filepath models.Filepath Filepath models.Filepath
} }
func (p *PortForwarding) String() string { func (p *PortForwarding) String() string {
if p.Enabled { if p.Enabled {
return fmt.Sprintf("on, saved in %s", p.Filepath) return fmt.Sprintf("on, saved in %s", p.Filepath)
} }
return "off" return "off"
} }
func (p *PIA) String() string { func (p *PIA) String() string {
settingsList := []string{ settingsList := []string{
"PIA settings:", "PIA settings:",
"User: [redacted]", "User: [redacted]",
"Password: [redacted]", "Password: [redacted]",
"Region: " + string(p.Region), "Region: " + string(p.Region),
"Encryption: " + string(p.Encryption), "Encryption: " + string(p.Encryption),
"Port forwarding: " + p.PortForwarding.String(), "Port forwarding: " + p.PortForwarding.String(),
} }
return strings.Join(settingsList, "\n |--") return strings.Join(settingsList, "\n |--")
} }
// GetPIASettings obtains PIA settings from environment variables using the params package. // GetPIASettings obtains PIA settings from environment variables using the params package.
func GetPIASettings(params params.ParamsReader) (settings PIA, err error) { func GetPIASettings(paramsReader params.Reader) (settings PIA, err error) {
settings.User, err = params.GetUser() settings.User, err = paramsReader.GetUser()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Password, err = params.GetPassword() settings.Password, err = paramsReader.GetPassword()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Encryption, err = params.GetPIAEncryption() settings.Encryption, err = paramsReader.GetPIAEncryption()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Region, err = params.GetPIARegion() settings.Region, err = paramsReader.GetPIARegion()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.PortForwarding.Enabled, err = params.GetPortForwarding() settings.PortForwarding.Enabled, err = paramsReader.GetPortForwarding()
if err != nil { if err != nil {
return settings, err return settings, err
} }
if settings.PortForwarding.Enabled { if settings.PortForwarding.Enabled {
settings.PortForwarding.Filepath, err = params.GetPortForwardingStatusFilepath() settings.PortForwarding.Filepath, err = paramsReader.GetPortForwardingStatusFilepath()
if err != nil { if err != nil {
return settings, err return settings, err
} }
} }
return settings, nil return settings, nil
} }
+127 -125
View File
@@ -1,125 +1,127 @@
package settings package settings
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/constants"
) "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/params"
// Settings contains all settings for the program to run )
type Settings struct {
VPNSP string // Settings contains all settings for the program to run
OpenVPN OpenVPN type Settings struct {
PIA PIA VPNSP models.VPNProvider
Mullvad Mullvad OpenVPN OpenVPN
Windscribe Windscribe PIA PIA
System System Mullvad Mullvad
DNS DNS Windscribe Windscribe
Firewall Firewall System System
TinyProxy TinyProxy DNS DNS
ShadowSocks ShadowSocks Firewall Firewall
} TinyProxy TinyProxy
ShadowSocks ShadowSocks
func (s *Settings) String() string { }
var vpnServiceProvider string
switch s.VPNSP { func (s *Settings) String() string {
case "pia": var vpnServiceProviderSettings string
vpnServiceProvider = s.PIA.String() switch s.VPNSP {
case "mullvad": case constants.PrivateInternetAccess:
vpnServiceProvider = s.Mullvad.String() vpnServiceProviderSettings = s.PIA.String()
case "windscribe": case constants.Mullvad:
vpnServiceProvider = s.Windscribe.String() vpnServiceProviderSettings = s.Mullvad.String()
} case constants.Windscribe:
return strings.Join([]string{ vpnServiceProviderSettings = s.Windscribe.String()
"Settings summary below:", }
s.OpenVPN.String(), return strings.Join([]string{
vpnServiceProvider, "Settings summary below:",
s.System.String(), s.OpenVPN.String(),
s.DNS.String(), vpnServiceProviderSettings,
s.Firewall.String(), s.System.String(),
s.TinyProxy.String(), s.DNS.String(),
s.ShadowSocks.String(), s.Firewall.String(),
"", // new line at the end s.TinyProxy.String(),
}, "\n") s.ShadowSocks.String(),
} "", // new line at the end
}, "\n")
// GetAllSettings obtains all settings for the program and returns an error as soon }
// as an error is encountered reading them.
func GetAllSettings(params params.ParamsReader) (settings Settings, err error) { // GetAllSettings obtains all settings for the program and returns an error as soon
settings.VPNSP, err = params.GetVPNSP() // as an error is encountered reading them.
if err != nil { func GetAllSettings(paramsReader params.Reader) (settings Settings, err error) {
return settings, err settings.VPNSP, err = paramsReader.GetVPNSP()
} if err != nil {
settings.OpenVPN, err = GetOpenVPNSettings(params) return settings, err
if err != nil { }
return settings, err settings.OpenVPN, err = GetOpenVPNSettings(paramsReader)
} if err != nil {
switch settings.VPNSP { return settings, err
case "pia": }
switch settings.OpenVPN.Cipher { switch settings.VPNSP {
case "", "aes-128-cbc", "aes-256-cbc", "aes-128-gcm", "aes-256-gcm": case constants.PrivateInternetAccess:
default: switch settings.OpenVPN.Cipher {
return settings, fmt.Errorf("cipher %q is not supported by Private Internet Access", settings.OpenVPN.Cipher) case "", "aes-128-cbc", "aes-256-cbc", "aes-128-gcm", "aes-256-gcm":
} default:
switch settings.OpenVPN.Auth { return settings, fmt.Errorf("cipher %q is not supported by Private Internet Access", settings.OpenVPN.Cipher)
case "", "sha1", "sha256": }
default: switch settings.OpenVPN.Auth {
return settings, fmt.Errorf("auth algorithm %q is not supported by Private Internet Access", settings.OpenVPN.Auth) case "", "sha1", "sha256":
} default:
settings.PIA, err = GetPIASettings(params) return settings, fmt.Errorf("auth algorithm %q is not supported by Private Internet Access", settings.OpenVPN.Auth)
case "mullvad": }
switch settings.OpenVPN.Cipher { settings.PIA, err = GetPIASettings(paramsReader)
case "": case constants.Mullvad:
default: switch settings.OpenVPN.Cipher {
return settings, fmt.Errorf("cipher %q is not supported by Mullvad", settings.OpenVPN.Cipher) case "":
} default:
switch settings.OpenVPN.Auth { return settings, fmt.Errorf("cipher %q is not supported by Mullvad", settings.OpenVPN.Cipher)
case "": }
default: switch settings.OpenVPN.Auth {
return settings, fmt.Errorf("auth algorithm %q is not supported by Mullvad (not using auth at all)", settings.OpenVPN.Auth) case "":
} default:
settings.Mullvad, err = GetMullvadSettings(params) return settings, fmt.Errorf("auth algorithm %q is not supported by Mullvad (not using auth at all)", settings.OpenVPN.Auth)
case "windscribe": }
switch settings.OpenVPN.Cipher { settings.Mullvad, err = GetMullvadSettings(paramsReader)
case "", "aes-256-cbc", "aes-256-gcm": // TODO check inside params getters case constants.Windscribe:
default: switch settings.OpenVPN.Cipher {
return settings, fmt.Errorf("cipher %q is not supported by Windscribe", settings.OpenVPN.Cipher) case "", "aes-256-cbc", "aes-256-gcm": // TODO check inside params getters
} default:
switch settings.OpenVPN.Auth { return settings, fmt.Errorf("cipher %q is not supported by Windscribe", settings.OpenVPN.Cipher)
case "", "sha512": }
default: switch settings.OpenVPN.Auth {
return settings, fmt.Errorf("auth algorithm %q is not supported by Windscribe", settings.OpenVPN.Auth) case "", "sha512":
} default:
settings.Windscribe, err = GetWindscribeSettings(params, settings.OpenVPN.NetworkProtocol) return settings, fmt.Errorf("auth algorithm %q is not supported by Windscribe", settings.OpenVPN.Auth)
default: }
err = fmt.Errorf("VPN service provider %q is not valid", settings.VPNSP) settings.Windscribe, err = GetWindscribeSettings(paramsReader, settings.OpenVPN.NetworkProtocol)
} default:
if err != nil { err = fmt.Errorf("VPN service provider %q is not valid", settings.VPNSP)
return settings, err }
} if err != nil {
if err != nil { return settings, err
return settings, err }
} if err != nil {
settings.DNS, err = GetDNSSettings(params) return settings, err
if err != nil { }
return settings, err settings.DNS, err = GetDNSSettings(paramsReader)
} if err != nil {
settings.Firewall, err = GetFirewallSettings(params) return settings, err
if err != nil { }
return settings, err settings.Firewall, err = GetFirewallSettings(paramsReader)
} if err != nil {
settings.TinyProxy, err = GetTinyProxySettings(params) return settings, err
if err != nil { }
return settings, err settings.TinyProxy, err = GetTinyProxySettings(paramsReader)
} if err != nil {
settings.ShadowSocks, err = GetShadowSocksSettings(params) return settings, err
if err != nil { }
return settings, err settings.ShadowSocks, err = GetShadowSocksSettings(paramsReader)
} if err != nil {
settings.System, err = GetSystemSettings(params) return settings, err
if err != nil { }
return settings, err settings.System, err = GetSystemSettings(paramsReader)
} if err != nil {
return settings, nil return settings, err
} }
return settings, nil
}
+60 -60
View File
@@ -1,60 +1,60 @@
package settings package settings
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// ShadowSocks contains settings to configure the Shadowsocks server // ShadowSocks contains settings to configure the Shadowsocks server
type ShadowSocks struct { type ShadowSocks struct {
Enabled bool Method string
Password string Password string
Log bool Port uint16
Port uint16 Enabled bool
Method string Log bool
} }
func (s *ShadowSocks) String() string { func (s *ShadowSocks) String() string {
if !s.Enabled { if !s.Enabled {
return "ShadowSocks settings: disabled" return "ShadowSocks settings: disabled"
} }
log := "disabled" log := "disabled"
if s.Log { if s.Log {
log = "enabled" log = "enabled"
} }
settingsList := []string{ settingsList := []string{
"ShadowSocks settings:", "ShadowSocks settings:",
"Password: [redacted]", "Password: [redacted]",
"Log: " + log, "Log: " + log,
fmt.Sprintf("Port: %d", s.Port), fmt.Sprintf("Port: %d", s.Port),
"Method: " + s.Method, "Method: " + s.Method,
} }
return strings.Join(settingsList, "\n |--") return strings.Join(settingsList, "\n |--")
} }
// GetShadowSocksSettings obtains ShadowSocks settings from environment variables using the params package. // GetShadowSocksSettings obtains ShadowSocks settings from environment variables using the params package.
func GetShadowSocksSettings(params params.ParamsReader) (settings ShadowSocks, err error) { func GetShadowSocksSettings(paramsReader params.Reader) (settings ShadowSocks, err error) {
settings.Enabled, err = params.GetShadowSocks() settings.Enabled, err = paramsReader.GetShadowSocks()
if err != nil || !settings.Enabled { if err != nil || !settings.Enabled {
return settings, err return settings, err
} }
settings.Port, err = params.GetShadowSocksPort() settings.Port, err = paramsReader.GetShadowSocksPort()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Password, err = params.GetShadowSocksPassword() settings.Password, err = paramsReader.GetShadowSocksPassword()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Log, err = params.GetShadowSocksLog() settings.Log, err = paramsReader.GetShadowSocksLog()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Method, err = params.GetShadowSocksMethod() settings.Method, err = paramsReader.GetShadowSocksMethod()
if err != nil { if err != nil {
return settings, err return settings, err
} }
return settings, nil return settings, nil
} }
+5 -5
View File
@@ -17,20 +17,20 @@ type System struct {
} }
// GetSystemSettings obtains the System settings using the params functions // GetSystemSettings obtains the System settings using the params functions
func GetSystemSettings(params params.ParamsReader) (settings System, err error) { func GetSystemSettings(paramsReader params.Reader) (settings System, err error) {
settings.UID, err = params.GetUID() settings.UID, err = paramsReader.GetUID()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.GID, err = params.GetGID() settings.GID, err = paramsReader.GetGID()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Timezone, err = params.GetTimezone() settings.Timezone, err = paramsReader.GetTimezone()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.IPStatusFilepath, err = params.GetIPStatusFilepath() settings.IPStatusFilepath, err = paramsReader.GetIPStatusFilepath()
if err != nil { if err != nil {
return settings, err return settings, err
} }
+59 -59
View File
@@ -1,59 +1,59 @@
package settings package settings
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// TinyProxy contains settings to configure TinyProxy // TinyProxy contains settings to configure TinyProxy
type TinyProxy struct { type TinyProxy struct {
Enabled bool User string
User string Password string
Password string LogLevel models.TinyProxyLogLevel
Port uint16 Port uint16
LogLevel models.TinyProxyLogLevel Enabled bool
} }
func (t *TinyProxy) String() string { func (t *TinyProxy) String() string {
if !t.Enabled { if !t.Enabled {
return "TinyProxy settings: disabled" return "TinyProxy settings: disabled"
} }
auth := "disabled" auth := "disabled"
if t.User != "" { if t.User != "" {
auth = "enabled" auth = "enabled"
} }
settingsList := []string{ settingsList := []string{
fmt.Sprintf("Port: %d", t.Port), fmt.Sprintf("Port: %d", t.Port),
"Authentication: " + auth, "Authentication: " + auth,
"Log level: " + string(t.LogLevel), "Log level: " + string(t.LogLevel),
} }
return "TinyProxy settings:\n" + strings.Join(settingsList, "\n |--") return "TinyProxy settings:\n" + strings.Join(settingsList, "\n |--")
} }
// GetTinyProxySettings obtains TinyProxy settings from environment variables using the params package. // GetTinyProxySettings obtains TinyProxy settings from environment variables using the params package.
func GetTinyProxySettings(params params.ParamsReader) (settings TinyProxy, err error) { func GetTinyProxySettings(paramsReader params.Reader) (settings TinyProxy, err error) {
settings.Enabled, err = params.GetTinyProxy() settings.Enabled, err = paramsReader.GetTinyProxy()
if err != nil || !settings.Enabled { if err != nil || !settings.Enabled {
return settings, err return settings, err
} }
settings.User, err = params.GetTinyProxyUser() settings.User, err = paramsReader.GetTinyProxyUser()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Password, err = params.GetTinyProxyPassword() settings.Password, err = paramsReader.GetTinyProxyPassword()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Port, err = params.GetTinyProxyPort() settings.Port, err = paramsReader.GetTinyProxyPort()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.LogLevel, err = params.GetTinyProxyLog() settings.LogLevel, err = paramsReader.GetTinyProxyLog()
if err != nil { if err != nil {
return settings, err return settings, err
} }
return settings, nil return settings, nil
} }
+49 -49
View File
@@ -1,49 +1,49 @@
package settings package settings
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
"github.com/qdm12/private-internet-access-docker/internal/params" "github.com/qdm12/private-internet-access-docker/internal/params"
) )
// Windscribe contains the settings to connect to a Windscribe server // Windscribe contains the settings to connect to a Windscribe server
type Windscribe struct { type Windscribe struct {
User string User string
Password string Password string
Region models.WindscribeRegion Region models.WindscribeRegion
Port uint16 Port uint16
} }
func (w *Windscribe) String() string { func (w *Windscribe) String() string {
settingsList := []string{ settingsList := []string{
"Windscribe settings:", "Windscribe settings:",
"User: [redacted]", "User: [redacted]",
"Password: [redacted]", "Password: [redacted]",
"Region: " + string(w.Region), "Region: " + string(w.Region),
"Custom port: " + fmt.Sprintf("%d", w.Port), "Custom port: " + fmt.Sprintf("%d", w.Port),
} }
return strings.Join(settingsList, "\n |--") return strings.Join(settingsList, "\n |--")
} }
// GetWindscribeSettings obtains Windscribe settings from environment variables using the params package. // GetWindscribeSettings obtains Windscribe settings from environment variables using the params package.
func GetWindscribeSettings(params params.ParamsReader, protocol models.NetworkProtocol) (settings Windscribe, err error) { func GetWindscribeSettings(paramsReader params.Reader, protocol models.NetworkProtocol) (settings Windscribe, err error) {
settings.User, err = params.GetUser() settings.User, err = paramsReader.GetUser()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Password, err = params.GetPassword() settings.Password, err = paramsReader.GetPassword()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Region, err = params.GetWindscribeRegion() settings.Region, err = paramsReader.GetWindscribeRegion()
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.Port, err = params.GetWindscribePort(protocol) settings.Port, err = paramsReader.GetWindscribePort(protocol)
if err != nil { if err != nil {
return settings, err return settings, err
} }
return settings, nil return settings, nil
} }
+1 -1
View File
@@ -11,7 +11,7 @@ import (
) )
// Splash returns the welcome spash message // Splash returns the welcome spash message
func Splash(paramsReader params.ParamsReader) string { func Splash(paramsReader params.Reader) string {
version := paramsReader.GetVersion() version := paramsReader.GetVersion()
vcsRef := paramsReader.GetVcsRef() vcsRef := paramsReader.GetVcsRef()
buildDate := paramsReader.GetBuildDate() buildDate := paramsReader.GetBuildDate()