Skip to content

Commit

Permalink
Merge pull request Place1#10 from Place1/embedded-dns
Browse files Browse the repository at this point in the history
Embedded dns
  • Loading branch information
Place1 authored Jan 27, 2020
2 parents ac50144 + 3e1ccf8 commit 090ace7
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 87 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,6 @@ wireguard:
externalAddress: ""
// The WireGuard ListenPort
port: 51820
// The DNS servers that VPN clients will be directed to use
dns:
- "1.1.1.1"
- "8.8.8.8"
} `yaml:"wireguard"`
vpn:
// CIDR configures a network address space
Expand All @@ -135,6 +131,13 @@ vpn:
// If not configured then the server will select the default
// network interface e.g. eth0
gatewayInterface: ""
dns:
// The upstream DNS servers that VPN clients will use
// VPN Clients will connect to a DNS proxy running on the
// wireguard server, which will send DNS requests to this
// upstream server.
upstream:
- "1.1.1.1"
auth:
// The below are all optional.
// Different authentication backends can be configured.
Expand Down
3 changes: 3 additions & 0 deletions demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ docker run \
--cap-add NET_ADMIN \
--device /dev/net/tun:/dev/net/tun \
-v "$CONFIG_FILE:/config.yaml" \
-v demo-data:/data \
-e "LOG_LEVEL=Debug" \
-p 8000:8000/tcp \
-p 51820:51820/udp \
-p 53:53/udp \
place1/wireguard-access-server /server --config /config.yaml
15 changes: 12 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,30 @@ require (
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/gorilla/handlers v1.4.2 // indirect
github.com/gorilla/mux v1.7.3
github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/miekg/dns v1.1.27
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.8.1
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_golang v1.2.1
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7 // indirect
github.com/sirupsen/logrus v1.4.2
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.4.0 // indirect
github.com/vishvananda/netlink v1.0.0
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f // indirect
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 // indirect
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191008142428-8d021180e987
google.golang.org/grpc v1.24.0 // indirect
google.golang.org/appengine v1.6.1 // indirect
google.golang.org/grpc v1.25.1 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/ldap.v2 v2.5.1 // indirect
gopkg.in/square/go-jose.v2 v2.4.0 // indirect
gopkg.in/yaml.v2 v2.2.2
Expand Down
109 changes: 41 additions & 68 deletions go.sum

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ type AppConfig struct {
ExternalAddress string `yaml:"externalAddress`
// The WireGuard ListenPort
Port int `yaml:"port"`
// The DNS servers that VPN clients will be directed to use
DNS []string `yaml:"dns"`
} `yaml:"wireguard"`
VPN struct {
// CIDR configures a network address space
Expand All @@ -77,6 +75,10 @@ type AppConfig struct {
// to the outside internet
GatewayInterface string `yaml:"gatewayInterface`
}
DNS struct {
// TODO: docs
Upstream []string `yaml:"upstream"`
} `yaml:"dns"`
Auth struct {
OIDC *auth.OIDCConfig `yaml:"oidc"`
Gitlab *auth.GitlabConfig `yaml:"gitlab"`
Expand Down Expand Up @@ -175,10 +177,6 @@ func Read() *AppConfig {
logrus.Warn("storage directory not configured - using in-memory storage backend! wireguard devices will be lost when the process exits!")
}

if len(config.WireGuard.DNS) == 0 {
config.WireGuard.DNS = []string{"1.1.1.1", "8.8.8.8"}
}

return &config
}

Expand Down
117 changes: 117 additions & 0 deletions internal/services/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package services

import (
"fmt"
"net"
"runtime/debug"
"time"

"github.com/miekg/dns"
"github.com/patrickmn/go-cache"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)

type DNSServer struct {
server *dns.Server
client *dns.Client
cache *cache.Cache
upstream []string
}

func NewDNSServer(upstream []string) (*DNSServer, error) {
logrus.Infof("starting dns server")

if len(upstream) == 0 {
upstream = []string{"1.1.1.1"}
}

dnsServer := &DNSServer{
server: &dns.Server{
Addr: "0.0.0.0:53",
Net: "udp",
},
client: &dns.Client{
SingleInflight: true,
},
cache: cache.New(10*time.Minute, 10*time.Minute),
upstream: upstream,
}
dnsServer.server.Handler = dnsServer

go func() {
if err := dnsServer.server.ListenAndServe(); err != nil {
logrus.Error(errors.Wrap(err, "failed to start dns server"))
}
}()

return dnsServer, nil
}

func (d *DNSServer) Close() error {
return d.server.Shutdown()
}

func (d *DNSServer) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
defer func() {
if err := recover(); err != nil {
logrus.Errorf("dns server panic handled: %v\n%s", err, string(debug.Stack()))
dns.HandleFailed(w, r)
}
}()
switch r.Opcode {
case dns.OpcodeQuery:
if logrus.GetLevel() == logrus.DebugLevel {
// log behind a condition to ensure we don't call prettyPrintMsg
// when the log level would filter out the message anyway
logrus.Debugf("dns query: %s", prettyPrintMsg(r))
}
m, err := d.Lookup(r)
if err != nil {
logrus.Errorf("failed lookup record with error: %s\n%s", err.Error(), r)
dns.HandleFailed(w, r)
return
}
m.SetReply(r)
w.WriteMsg(m)
return
}
}

func (d *DNSServer) Lookup(m *dns.Msg) (*dns.Msg, error) {
key := makekey(m)

// check the cache first
if item, found := d.cache.Get(key); found {
if logrus.GetLevel() == logrus.DebugLevel {
logrus.Debugf("dns cache hit %s", prettyPrintMsg(m))
}
return item.(*dns.Msg), nil
}

// fallback to upstream exchange
response, _, err := d.client.Exchange(m, net.JoinHostPort(d.upstream[0], "53"))
if err != nil {
return nil, err
}

if len(response.Answer) > 0 {
ttl := time.Duration(response.Answer[0].Header().Ttl) * time.Second
logrus.Debugf("caching dns response for %v seconds", ttl)
d.cache.Set(key, response, ttl)
}

return response, nil
}

func makekey(m *dns.Msg) string {
q := m.Question[0]
return fmt.Sprintf("%s:%d:%d", q.Name, q.Qtype, q.Qclass)
}

func prettyPrintMsg(m *dns.Msg) string {
if len(m.Question) > 0 {
return fmt.Sprintf("dns query for: %s", makekey(m))
}
return m.String()
}
16 changes: 11 additions & 5 deletions internal/services/network.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package services

import (
"net"

"github.com/coreos/go-iptables/iptables"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
)

func ServerVPNIP(cidr string) *net.IPNet {
vpnip, vpnsubnet := MustParseCIDR(cidr)
vpnsubnet.IP = nextIP(vpnip.Mask(vpnsubnet.Mask))
return vpnsubnet
}

func ConfigureRouting(wgIface string, cidr string) error {
// Networking configuration (ip links and route tables)
// to ensure that network traffic in the VPN subnet
Expand All @@ -15,11 +23,9 @@ func ConfigureRouting(wgIface string, cidr string) error {
if err != nil {
return errors.Wrap(err, "failed to find wireguard interface")
}
vpnip, vpnsubnet := MustParseCIDR(cidr)
vpnsubnet.IP = nextIP(vpnip.Mask(vpnsubnet.Mask))
serverIP := vpnsubnet.String()
logrus.Infof("server VPN subnet IP is %s", serverIP)
addr, err := netlink.ParseAddr(serverIP)
vpnip := ServerVPNIP(cidr)
logrus.Infof("server VPN subnet IP is %s", vpnip.String())
addr, err := netlink.ParseAddr(vpnip.String())
if err != nil {
return errors.Wrap(err, "failed to parse subnet address")
}
Expand Down
12 changes: 11 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ func main() {
time.Sleep(1 * time.Second)
}

// The server's IP within the VPN virtual network
vpnip := services.ServerVPNIP(conf.VPN.CIDR)

// WireGuard
wgserver, err := services.NewWireGuard(
conf.WireGuard.InterfaceName,
conf.WireGuard.PrivateKey,
conf.WireGuard.Port,
conf.WireGuard.ExternalAddress,
conf.WireGuard.DNS,
[]string{vpnip.IP.String()},
)
if err != nil {
logrus.Fatal(errors.Wrap(err, "failed to create wgserver"))
Expand All @@ -65,6 +68,13 @@ func main() {
logrus.Warn("VPN.GatewayInterface is not configured - vpn clients will not have access to the internet")
}

// DNS Server
dns, err := services.NewDNSServer(conf.DNS.Upstream)
if err != nil {
logrus.Fatal(errors.Wrap(err, "failed to start dns server"))
}
defer dns.Close()

// Storage
var storageDriver storage.Storage
if conf.Storage.Directory != "" {
Expand Down

0 comments on commit 090ace7

Please sign in to comment.