From eb5c6c401517bed87eecd859ef05e1d2661150c5 Mon Sep 17 00:00:00 2001 From: Neven Miculinic Date: Wed, 27 Mar 2019 17:26:09 +0100 Subject: [PATCH] update --- .gitlab-ci.yml | 12 +++ config.go | 265 +++++++++++++++++++++++++++++++++++++++++++++++++ config_test.go | 65 ++++++++++++ go.mod | 18 ---- go.sum | 72 +------------- wg.go | 100 +------------------ 6 files changed, 346 insertions(+), 186 deletions(-) create mode 100644 .gitlab-ci.yml create mode 100644 config.go create mode 100644 config_test.go diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..76aba28 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,12 @@ +stages: + - build +go_build: + stage: build + image: golang:1.12 + script: + - go mod vendor + - go test ./... + cache: + key: ${CI_COMMIT_REF_SLUG} + paths: + - vendor/ diff --git a/config.go b/config.go new file mode 100644 index 0000000..0591f12 --- /dev/null +++ b/config.go @@ -0,0 +1,265 @@ +package wgquick + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "github.com/mdlayher/wireguardctrl/wgtypes" + "net" + "strconv" + "strings" + "text/template" + "time" +) + +type Config struct { + wgtypes.Config + + // Address list of IP (v4 or v6) addresses (optionally with CIDR masks) to be assigned to the interface. May be specified multiple times. + Address []*net.IPNet + + // list of IP (v4 or v6) addresses to be set as the interface’s DNS servers. May be specified multiple times. Upon bringing the interface up, this runs ‘resolvconf -a tun.INTERFACE -m 0 -x‘ and upon bringing it down, this runs ‘resolvconf -d tun.INTERFACE‘. If these particular invocations of resolvconf(8) are undesirable, the PostUp and PostDown keys below may be used instead. + // Currently unsupported + DNS []net.IP + // —if not specified, the MTU is automatically determined from the endpoint addresses or the system default route, which is usually a sane choice. However, to manually specify an MTU to override this automatic discovery, this value may be specified explicitly. + MTU int + + // Table — Controls the routing table to which routes are added. + Table int + + // PreUp, PostUp, PreDown, PostDown — script snippets which will be executed by bash(1) before/after setting up/tearing down the interface, most commonly used to configure custom DNS options or firewall rules. The special string ‘%i’ is expanded to INTERFACE. Each one may be specified multiple times, in which case the commands are executed in order. + + // Currently unsupported + PreUp string + PostUp string + PreDown string + PostDown string + + // SaveConfig — if set to ‘true’, the configuration is saved from the current state of the interface upon shutdown. + // Currently unsupported + SaveConfig bool +} + + +var _ encoding.TextMarshaler = (*Config)(nil) +var _ encoding.TextUnmarshaler = (*Config)(nil) + +func (cfg *Config) String() string { + b, err := cfg.MarshalText() + if err != nil { + panic(err) + } + return string(b) +} + +func serializeKey(key *wgtypes.Key) string { + return base64.StdEncoding.EncodeToString(key[:]) +} + +func toSeconds(duration time.Duration) int { + return int(duration / time.Second) +} + +var funcMap = template.FuncMap(map[string]interface{}{ + "wgKey": serializeKey, + "toSeconds": toSeconds, +}) + +var cfgTemplate = template.Must( + template. + New("wg-cfg"). + Funcs(funcMap). + Parse(wgtypeTemplateSpec)) + +func (cfg *Config) MarshalText() (text []byte, err error) { + buff := &bytes.Buffer{} + if err := cfgTemplate.Execute(buff, cfg); err != nil { + return nil, err + } + return buff.Bytes(), nil +} + +const wgtypeTemplateSpec = `[Interface] +{{- range .Address }} +Address = {{ . }} +{{- end }} +{{- range .DNS }} +DNS = {{ . }} +{{- end }} +PrivateKey = {{ .PrivateKey | wgKey }} +{{- if .ListenPort }}{{ "\n" }}ListenPort = {{ .ListenPort }}{{ end }} +{{- if .MTU }}{{ "\n" }}MTU = {{ .MTU }}{{ end }} +{{- if .Table }}{{ "\n" }}Table = {{ .Table }}{{ end }} +{{- if .PreUp }}{{ "\n" }}PreUp = {{ .PreUp }}{{ end }} +{{- if .PostUp }}{{ "\n" }}PostUp = {{ .PostUp }}{{ end }} +{{- if .PreDown }}{{ "\n" }}PreDown = {{ .PreDown }}{{ end }} +{{- if .PostDown }}{{ "\n" }}PostDown = {{ .PostDown }}{{ end }} +{{- if .SaveConfig }}{{ "\n" }}SaveConfig = {{ .SaveConfig }}{{ end }} +{{- range .Peers }} +{{- "\n" }} +[Peer] +PublicKey = {{ .PublicKey | wgKey }} +AllowedIPs = {{ range $i, $el := .AllowedIPs }}{{if $i}}, {{ end }}{{ $el }}{{ end }} +{{- if .PresharedKey }}{{ "\n" }}PresharedKey = {{ .PresharedKey }}{{ end }} +{{- if .PersistentKeepaliveInterval }}{{ "\n" }}PersistentKeepaliveInterval = {{ .PersistentKeepaliveInterval | toSeconds }}{{ end }} +{{- if .Endpoint }}{{ "\n" }}Endpoint = {{ .Endpoint }}{{ end }} +{{- end }} +` + +// Parses base64 encoded wireguard private key +func ParseKey(key string) (wgtypes.Key, error) { + var pkey wgtypes.Key + pkeySlice, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return pkey, err + } + copy(pkey[:], pkeySlice[:]) + return pkey, nil +} + +type parseState int +const ( + unknown parseState = iota + inter = iota + peer = iota +) +func (cfg *Config) UnmarshalText(text []byte) error { + *cfg = Config{} // Zero out the config + state := unknown + var peerCfg *wgtypes.PeerConfig + for no, line := range strings.Split(string(text), "\n") { + ln := strings.TrimSpace(line) + if len(ln) == 0 || ln[0] == '#' { + continue + } + switch ln { + case "[Interface]": + state = inter + case "[Peer]": + state = peer + cfg.Peers = append(cfg.Peers, wgtypes.PeerConfig{}) + peerCfg = &cfg.Peers[len(cfg.Peers) - 1] + default: + parts := strings.Split(ln, "=") + if len(parts) < 2 { + return fmt.Errorf("cannot parse line %d, missing =", no) + } + lhs := strings.TrimSpace(parts[0]) + rhs := strings.TrimSpace(strings.Join(parts[1:], "=")) + + switch state { + case inter: + if err := parseInterfaceLine(cfg, lhs, rhs); err != nil { + return fmt.Errorf("[line %d]: %v", no, err) + } + case peer: + if err := parsePeerLine(peerCfg, lhs, rhs); err != nil { + return fmt.Errorf("[line %d]: %v", no, err) + } + default: + return fmt.Errorf("cannot parse line %d, unknown state", no) + } + } + } + return nil +} +func parseInterfaceLine(cfg *Config, lhs string, rhs string) error { + switch lhs { + case "Address": + for _, addr := range strings.Split(rhs, ",") { + ip, cidr, err := net.ParseCIDR(strings.TrimSpace(addr)) + if err != nil { + return fmt.Errorf("%v", err) + } + cfg.Address = append(cfg.Address, &net.IPNet{IP:ip, Mask:cidr.Mask}) + } + case "DNS": + for _, addr := range strings.Split(rhs, ",") { + ip:= net.ParseIP(strings.TrimSpace(addr)) + if ip == nil { + return fmt.Errorf("cannot parse IP") + } + cfg.DNS = append(cfg.DNS, ip) + } + case "MTU": + mtu, err := strconv.ParseInt(rhs, 10, 64) + if err != nil { + return err + } + cfg.MTU = int(mtu) + case "Table": + tbl, err := strconv.ParseInt(rhs, 10, 64) + if err != nil { + return err + } + cfg.Table = int(tbl) + case "ListenPort": + portI64, err := strconv.ParseInt(rhs, 10, 64) + if err != nil { + return err + } + port := int(portI64) + cfg.ListenPort = &port + case "PreUp": + cfg.PreUp = rhs + case "PostUp": + cfg.PostUp = rhs + case "PreDown": + cfg.PreDown = rhs + case "PostDown": + cfg.PostDown = rhs + case "SaveConfig": + save, err := strconv.ParseBool(rhs) + if err != nil { + return err + } + cfg.SaveConfig = save + case "PrivateKey": + key, err := ParseKey(rhs) + if err != nil { + return fmt.Errorf("cannot decode key %v", err) + } + cfg.PrivateKey = &key + default: + return fmt.Errorf("unknown directive %s", lhs) + } + return nil +} + +func parsePeerLine(peerCfg *wgtypes.PeerConfig, lhs string, rhs string) error { + switch lhs { + case "PublicKey": + key, err := ParseKey(rhs) + if err != nil { + return fmt.Errorf("cannot decode key %v", err) + } + peerCfg.PublicKey = key + case "PresharedKey": + key, err := ParseKey(rhs) + if err != nil { + return fmt.Errorf("cannot decode key %v", err) + } + if peerCfg.PresharedKey != nil { + return fmt.Errorf("preshared key already defined %v", err) + } + peerCfg.PresharedKey = &key + case "AllowedIPs": + for _, addr := range strings.Split(rhs, ",") { + ip, cidr, err := net.ParseCIDR(strings.TrimSpace(addr)) + if err != nil { + return fmt.Errorf("%v", err) + } + peerCfg.AllowedIPs = append(peerCfg.AllowedIPs, net.IPNet{IP:ip, Mask:cidr.Mask}) + } + case "Endpoint": + addr, err := net.ResolveUDPAddr("", rhs) + if err != nil { + return err + } + peerCfg.Endpoint = addr + default: + return fmt.Errorf("unknown directive %s", lhs) + } + return nil +} \ No newline at end of file diff --git a/config_test.go b/config_test.go new file mode 100644 index 0000000..566c069 --- /dev/null +++ b/config_test.go @@ -0,0 +1,65 @@ +package wgquick + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +var testConfigs = map[string]string{ +"simple": `[Interface] +Address = 10.200.100.8/24 +DNS = 10.200.100.1 +PrivateKey = oK56DE9Ue9zK76rAc8pBl6opph+1v36lm7cXXsQKrQM= + +[Peer] +PublicKey = GtL7fZc/bLnqZldpVofMCD6hDjrK28SsdLxevJ+qtKU= +AllowedIPs = 0.0.0.0/0 +PresharedKey = /UwcSPg38hW/D9Y3tcS1FOV0K1wuURMbS0sesJEP5ak= +Endpoint = 123.12.12.1:51820 +`, +"sample-2": `[Interface] +Address = 10.192.122.1/24 +Address = 10.10.0.1/16 +PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk= +ListenPort = 51820 +SaveConfig = true + +[Peer] +PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg= +AllowedIPs = 10.192.122.3/32, 10.192.124.1/24 + +[Peer] +PublicKey = TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0= +AllowedIPs = 10.192.122.4/32, 192.168.0.0/16 + +[Peer] +PublicKey = gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA= +AllowedIPs = 10.10.10.230/32 +`, +"sample-3":`[Interface] +Address = 10.192.122.1/24 +PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk= +ListenPort = 51820 +Table = 1234 +PostUp = ip rule add ipproto tcp dport 22 table 1234 +PreDown = ip rule delete ipproto tcp dport 22 table 1234 + +[Peer] +PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg= +AllowedIPs = 0.0.0.0/0 +`, +} + +func TestExampleConfig(t *testing.T) { + c := &Config{} + for name, cfg := range testConfigs { + t.Run(name, func(t *testing.T) { + err := c.UnmarshalText([]byte(cfg)) + assert.NoError(t, err) + tt, err := c.MarshalText() + assert.NoError(t, err) + t.Logf("Got after remarshaling:\n%s", tt) + assert.Equal(t, cfg, string(tt)) + }) + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index 88056c5..6b7fb2f 100644 --- a/go.mod +++ b/go.mod @@ -3,27 +3,9 @@ module github.com/nmiculinic/wg-quick-go go 1.12 require ( - github.com/KrakenSystems/wg-operator v0.0.0-20190326122344-c32b2bf8f73a - github.com/emicklei/go-restful v2.9.1+incompatible // indirect - github.com/go-openapi/spec v0.19.0 // indirect - github.com/gogo/protobuf v1.2.1 // indirect - github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect - github.com/json-iterator/go v1.1.6 // indirect github.com/mdlayher/wireguardctrl v0.0.0-20190325182839-fcf15c501b90 - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/onsi/ginkgo v1.8.0 // indirect - github.com/onsi/gomega v1.5.0 // indirect github.com/sirupsen/logrus v1.4.0 - github.com/spf13/pflag v1.0.3 // indirect github.com/stretchr/testify v1.3.0 github.com/vishvananda/netlink v1.0.0 github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/api v0.0.0-20190313115550-3c12c96769cc // indirect - k8s.io/apimachinery v0.0.0-20190323104403-03ac7a9ade42 - k8s.io/klog v0.2.0 // indirect - k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580 // indirect - sigs.k8s.io/controller-runtime v0.1.10 // indirect - sigs.k8s.io/yaml v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index 877d367..179d6a0 100644 --- a/go.sum +++ b/go.sum @@ -1,42 +1,11 @@ -github.com/KrakenSystems/wg-operator v0.0.0-20190326122344-c32b2bf8f73a h1:FUwaIyTLYJ2rJbH7/VrcDT673oW495PQ/5yhcnOY0Hs= -github.com/KrakenSystems/wg-operator v0.0.0-20190326122344-c32b2bf8f73a/go.mod h1:KbgWSIZ/HfS5PPTlVYMtcfPDaf6psweYj50kjvyRPiw= -github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful v2.9.1+incompatible h1:TOKUBeOLGz/xFJ6a9bO8++X6xPN9HZR3LGv2RqnE6xM= -github.com/emicklei/go-restful v2.9.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonreference v0.17.0 h1:yJW3HCkTHg7NOA+gZ83IPHzUSnUzGXhGmsdiCcMexbA= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4= -github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851 h1:QYJTEbSDJvDBQenHYMxoiBQPgZ4QUcm75vACe3dkW7o= github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851/go.mod h1:EsbsAEUEs15qC1cosAwxgCWV0Qhd8TmkxnA9Kw1Vhl4= github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c h1:qYXI+3AN4zBWsTF5drEu1akWPu2juaXPs58tZ4/GaCg= @@ -45,21 +14,10 @@ github.com/mdlayher/wireguardctrl v0.0.0-20190325182839-fcf15c501b90 h1:OgbuxwTP github.com/mdlayher/wireguardctrl v0.0.0-20190325182839-fcf15c501b90/go.mod h1:BdyuvE2RP0RjONNIBHLdaVM7iarlHbioRUbsVXeOAJM= github.com/mikioh/ipaddr v0.0.0-20190227002745-725a6cbe920e h1:Pa/tBadWnc5p6P32+GcWt20TvPB9dqlDbBn81oWptqE= github.com/mikioh/ipaddr v0.0.0-20190227002745-725a6cbe920e/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.4.0 h1:yKenngtzGh+cUSSh6GWbxW2abRqhYUSR/t/6+2QqNvE= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -73,40 +31,12 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977 h1:actzWV6iWn3GLqN8dZjzsB+CLt+gaV2+wsxroxiQI8I= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -k8s.io/api v0.0.0-20190313115550-3c12c96769cc h1:m/JS6kQd00rICnXLWlnJzMFQB4AplcURUopS8dKiWmI= -k8s.io/api v0.0.0-20190313115550-3c12c96769cc/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/apimachinery v0.0.0-20190323104403-03ac7a9ade42 h1:g8bMHs6e/f1W6z/yNaUsOCvFCaaDLNlEbtVcnIIrkhA= -k8s.io/apimachinery v0.0.0-20190323104403-03ac7a9ade42/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c= -k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580 h1:fq0ZXW/BAIFZH+dazlups6JTVdwzRo5d9riFA103yuQ= -k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -sigs.k8s.io/controller-runtime v0.1.10 h1:amLOmcekVdnsD1uIpmgRqfTbQWJ2qxvQkcdeFhcotn4= -sigs.k8s.io/controller-runtime v0.1.10/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/wg.go b/wg.go index 40d71e5..6300968 100644 --- a/wg.go +++ b/wg.go @@ -1,107 +1,13 @@ -package wgctl +package wgquick import ( - "bytes" - "encoding/base64" - "net" - "syscall" - "text/template" - "github.com/mdlayher/wireguardctrl" - "github.com/mdlayher/wireguardctrl/wgtypes" "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + "net" + "syscall" ) -type Config struct { - wgtypes.Config - - // Address list of IP (v4 or v6) addresses (optionally with CIDR masks) to be assigned to the interface. May be specified multiple times. - Address []*net.IPNet - - // list of IP (v4 or v6) addresses to be set as the interface’s DNS servers. May be specified multiple times. Upon bringing the interface up, this runs ‘resolvconf -a tun.INTERFACE -m 0 -x‘ and upon bringing it down, this runs ‘resolvconf -d tun.INTERFACE‘. If these particular invocations of resolvconf(8) are undesirable, the PostUp and PostDown keys below may be used instead. - // Currently unsupported - DNS []net.IP - // —if not specified, the MTU is automatically determined from the endpoint addresses or the system default route, which is usually a sane choice. However, to manually specify an MTU to override this automatic discovery, this value may be specified explicitly. - MTU int - - // Table — Controls the routing table to which routes are added. - Table int - - // PreUp, PostUp, PreDown, PostDown — script snippets which will be executed by bash(1) before/after setting up/tearing down the interface, most commonly used to configure custom DNS options or firewall rules. The special string ‘%i’ is expanded to INTERFACE. Each one may be specified multiple times, in which case the commands are executed in order. - - // Currently unsupported - PreUp string - PostUp string - PreDown string - PostDown string - - // SaveConfig — if set to ‘true’, the configuration is saved from the current state of the interface upon shutdown. - // Currently unsupported - SaveConfig bool -} - -func (cfg *Config) String() string { - b, err := cfg.MarshalText() - if err != nil { - panic(err) - } - return string(b) -} - -var cfgTemplate = template.Must( - template. - New("wg-cfg"). - Funcs(template.FuncMap(map[string]interface{}{"wgKey": serializeKey})). - Parse(wgtypeTemplateSpec)) - -func (cfg *Config) MarshalText() (text []byte, err error) { - buff := &bytes.Buffer{} - if err := cfgTemplate.Execute(buff, cfg); err != nil { - return nil, err - } - return buff.Bytes(), nil -} - -const wgtypeTemplateSpec = `[Interface] -{{- range .Address }} -Address = {{ . }} -{{- end }} -{{- range .DNS }} -DNS = {{ . }} -{{- end }} -PrivateKey = {{ .PrivateKey | wgKey }} -{{- if .ListenPort }}{{ "\n" }}ListenPort = {{ .ListenPort }}{{ end }} -{{- if .MTU }}{{ "\n" }}MTU = {{ .MTU }}{{ end }} -{{- if .Table }}{{ "\n" }}Table = {{ .Table }}{{ end }} -{{- if .PreUp }}{{ "\n" }}PreUp = {{ .PreUp }}{{ end }} -{{- if .PostUp }}{{ "\n" }}Table = {{ .Table }}{{ end }} -{{- if .PreDown }}{{ "\n" }}PreDown = {{ .PreDown }}{{ end }} -{{- if .PostDown }}{{ "\n" }}PostDown = {{ .PostDown }}{{ end }} -{{- if .SaveConfig }}{{ "\n" }}SaveConfig = {{ .SaveConfig }}{{ end }} -{{- range .Peers }} -{{- "\n" }} -[Peer] -PublicKey = {{ .PublicKey | wgKey }} -AllowedIps = {{ range $i, $el := .AllowedIPs }}{{if $i}}, {{ end }}{{ $el }}{{ end }} -{{- if .Endpoint }}{{ "\n" }}Endpoint = {{ .Endpoint }}{{ end }} -{{- end }} -` - -func serializeKey(key *wgtypes.Key) string { - return base64.StdEncoding.EncodeToString(key[:]) -} - -// Parses base64 encoded key -func ParseKey(key string) (wgtypes.Key, error) { - var pkey wgtypes.Key - pkeySlice, err := base64.StdEncoding.DecodeString(key) - if err != nil { - return pkey, err - } - copy(pkey[:], pkeySlice[:]) - return pkey, nil -} // Sync the config to the current setup for given interface func (cfg *Config) Sync(iface string, logger logrus.FieldLogger) error {