From c42d13f14f10d5b2085ade4b1ae49d7f256eff30 Mon Sep 17 00:00:00 2001 From: "Quentin McGaw (desktop)" Date: Sun, 16 Feb 2020 19:51:08 +0000 Subject: [PATCH] Added Mullvad configuration builder --- internal/mullvad/conf.go | 71 +++++++++++++++++++++++++++++++++++++ internal/mullvad/mullvad.go | 27 ++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 internal/mullvad/conf.go create mode 100644 internal/mullvad/mullvad.go diff --git a/internal/mullvad/conf.go b/internal/mullvad/conf.go new file mode 100644 index 00000000..a119f754 --- /dev/null +++ b/internal/mullvad/conf.go @@ -0,0 +1,71 @@ +package mullvad + +import ( + "fmt" + + "github.com/qdm12/golibs/files" + "github.com/qdm12/private-internet-access-docker/internal/constants" + "github.com/qdm12/private-internet-access-docker/internal/models" +) + +func (c *configurator) GetOpenVPNConnections(country models.MullvadCountry, city models.MullvadCity, provider models.MullvadProvider, protocol models.NetworkProtocol, customPort uint16) (connections []models.OpenVPNConnection, err error) { + servers := constants.MullvadServerFilter(country, city, provider) + if len(servers) == 0 { + return nil, fmt.Errorf("no server found for country %q, city %q and ISP %q", country, city, provider) + } + for _, server := range servers { + port := server.DefaultPort + if customPort > 0 { + port = customPort + } + for _, IP := range server.IPs { + connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: protocol}) + } + } + return connections, nil +} + +func (c *configurator) BuildConf(connections []models.OpenVPNConnection, uid, gid int) (err error) { + if len(connections) == 0 { + return fmt.Errorf("at least one connection string is expected") + } + lines := []string{ + "client", + "dev tun", + "nobind", + "persist-key", + "persist-tun", + "remote-cert-tls server", + "ping 300", + "verb 1", // TODO env variable + + // Mullvad specific + // "sndbuf 524288" + // "rcvbuf 524288" + "cipher AES-256-CBC", + "tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + + // Added constant values + "mute-replay-warnings", + "user nonrootuser", + "pull-filter ignore \"auth-token\"", // prevent auth failed loops + "auth-retry nointeract", + "remote-random", + + // Modified variables + fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf), + fmt.Sprintf("proto %s", string(connections[0].Protocol)), + } + for _, connection := range connections { + lines = append(lines, fmt.Sprintf("remote %s %d", connection.IP.String(), connection.Port)) + } + lines = append(lines, []string{ + "", + "-----BEGIN CERTIFICATE-----", + constants.MullvadCertificate, + "-----END CERTIFICATE-----", + "", + "", + }...) + return c.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(uid, gid), files.Permissions(0400)) +} diff --git a/internal/mullvad/mullvad.go b/internal/mullvad/mullvad.go new file mode 100644 index 00000000..2406e9a9 --- /dev/null +++ b/internal/mullvad/mullvad.go @@ -0,0 +1,27 @@ +package mullvad + +import ( + "github.com/qdm12/golibs/files" + "github.com/qdm12/golibs/logging" + "github.com/qdm12/golibs/network" + "github.com/qdm12/private-internet-access-docker/internal/models" +) + +const logPrefix = "Mullvad configurator" + +// Configurator contains methods to download, read and modify the openvpn configuration to connect as a client +type Configurator interface { + GetOpenVPNConnections(country models.MullvadCountry, city models.MullvadCity, provider models.MullvadProvider, protocol models.NetworkProtocol, customPort uint16) (connections []models.OpenVPNConnection, err error) + BuildConf(connections []models.OpenVPNConnection, uid, gid int) (err error) +} + +type configurator struct { + client network.Client + fileManager files.FileManager + logger logging.Logger +} + +// NewConfigurator returns a new Configurator object +func NewConfigurator(client network.Client, fileManager files.FileManager, logger logging.Logger) Configurator { + return &configurator{client, fileManager, logger} +}