Skip to content
This repository has been archived by the owner on Jul 5, 2021. It is now read-only.

Commit

Permalink
Initial Commit for wgconf
Browse files Browse the repository at this point in the history
wgconf could be used to configure wireguard-go from config file.
  • Loading branch information
QuantumGhost committed Nov 3, 2019
1 parent 23406de commit 2dcbbc4
Show file tree
Hide file tree
Showing 6 changed files with 484 additions and 0 deletions.
8 changes: 8 additions & 0 deletions go.mod
Expand Up @@ -3,12 +3,20 @@ module golang.zx2c4.com/wireguard/wgctrl
go 1.13

require (
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/google/go-cmp v0.3.1
github.com/gookit/ini/v2 v2.0.4
github.com/kr/pretty v0.1.0 // indirect
github.com/mdlayher/genetlink v0.0.0-20191008151445-a2cadeac9a63
github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721
github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect
golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934
golang.zx2c4.com/wireguard v0.0.20191012
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.2.4 // indirect
)
40 changes: 40 additions & 0 deletions go.sum
@@ -1,8 +1,30 @@
github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gookit/goutil v0.1.7 h1:lEdJiRB21RTnkL6XwV10rZo4/rLp2bTLqDh3qic6RkE=
github.com/gookit/goutil v0.1.7/go.mod h1:LRPzhcWV540XDMnW+7oXy5VRW+lyQ7dWi7blm187ILo=
github.com/gookit/ini/v2 v2.0.4 h1:AKlDWaiXNYH4/uV4r/L1zIUpH7YihXWm4d/fGMMN9KU=
github.com/gookit/ini/v2 v2.0.4/go.mod h1:e535tteuSqCKXVGkFYvt551Ead+MLynzQtOe9YwuaYk=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a h1:84IpUNXj4mCR9CuCEvSiCArMbzr/TMbuPIadKDwypkI=
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mdlayher/genetlink v0.0.0-20191008151445-a2cadeac9a63 h1:ActsKJ9UiaN48gqvN22JVaR54tjcs6FhGWoeAWD8yhM=
github.com/mdlayher/genetlink v0.0.0-20191008151445-a2cadeac9a63/go.mod h1:XVJN/Mv38rd1AEMAjHTddGScIY0D53G8aBDo4CxEw6w=
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
Expand All @@ -12,6 +34,16 @@ github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b h1:W3er9pI7mt2gOq
github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand All @@ -31,6 +63,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c h1:6Zx7DRlKXf79yfxuQ/7GqV3w2y7aDsk6bGg0MzF5RVU=
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -43,3 +76,10 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.20191012 h1:sdX+y3hrHkW8KJkjY7ZgzpT5Tqo8XnBkH55U1klphko=
golang.zx2c4.com/wireguard v0.0.20191012/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
145 changes: 145 additions & 0 deletions wgconf/cmd/wgconf/main.go
@@ -0,0 +1,145 @@
package wgconf

import (
"fmt"
"log"
"os"
"strings"
"text/template"
"time"

"github.com/alecthomas/kingpin"

"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgconf/config"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)

func main() {
rootCmd := newCommandLine()
getCmd, getOpt := newGetCommand(rootCmd)
setCmd, setOpt := newSetCommand(rootCmd)
switch kingpin.MustParse(rootCmd.Parse(os.Args[1:])) {
case getCmd.FullCommand():
getConfig(*getOpt)
case setCmd.FullCommand():
setConfig(*setOpt)
}
}

func newCommandLine() *kingpin.Application {
return kingpin.New("wgconf", "wireguard configuring tool")
}

type getOption struct {
Interface string
ShowCredential bool
}

type setOption struct {
Interface string
Config string
}

func newGetCommand(root *kingpin.Application) (*kingpin.CmdClause, *getOption) {
opt := getOption{}
cmd := root.Command("get", "get wireguard configuration")
cmd.Flag("interface", "interface to show").StringVar(&opt.Interface)
cmd.Flag("show-credential", "show credentials for interface").BoolVar(&opt.ShowCredential)
return cmd, &opt
}

func newSetCommand(root *kingpin.Application) (*kingpin.CmdClause, *setOption) {
opt := setOption{}
cmd := root.Command("set", "set wireguard configuration")
cmd.Flag("interface", "interface to set").StringVar(&opt.Interface)
cmd.Flag("config", "configuration file").StringVar(&opt.Config)
return cmd, &opt
}

func checkError(err error) {
if err != nil {
log.Fatalln(err)
}
}

func getConfig(opt getOption) {

client, err := wgctrl.New()
checkError(err)
dev, err := client.Device(opt.Interface)
checkError(err)
fmt.Printf("Interface: %s (%s)\n", opt.Interface, dev.Type.String())
fmt.Printf(" public key: %s\n", dev.PublicKey.String())
privkeyStr := "(hidden)"
if opt.ShowCredential {
privkeyStr = dev.PrivateKey.String()
}
fmt.Printf(" private key: %s\n", privkeyStr)
fmt.Printf(" listening port: %d\n", dev.ListenPort)
for _, peer := range dev.Peers {
printPeers(peer, opt.ShowCredential)
}
}

func setConfig(opt setOption) {
fin, err := os.Open(opt.Config)
checkError(err)
cfg, err := config.LoadConfig(fin)
checkError(err)
client, err := wgctrl.New()
checkError(err)
err = client.ConfigureDevice(opt.Interface, *cfg)
checkError(err)
log.Printf("interface %s configured.\n", opt.Interface)
}

func printPeers(peer wgtypes.Peer, showCredential bool) {
const tmpl = `
peer: {{ .PublicKey }}
preshared key = {{ .PresharedKey }}
endpoint = {{ .Endpoint }}
keep alive interval = {{ .KeepAliveInterval }}s
last handshake time = {{ .LastHandshakeTime }}
receive bytes = {{ .ReceiveBytes }}
transmit bytes = {{ .TransmitBytes }}
allowed ips = {{ .AllowedIPs }}
protocol version = {{ .ProtocolVersion }}
`

type tmplContent struct {
PublicKey string
PresharedKey string
Endpoint string
KeepAliveInterval float64
LastHandshakeTime string
ReceiveBytes int64
TransmitBytes int64
AllowedIPs string
ProtocolVersion int
}

t := template.Must(template.New("peer_tmpl").Parse(tmpl))
c := tmplContent{
PublicKey: peer.PublicKey.String(),
PresharedKey: "(hidden)",
Endpoint: peer.Endpoint.String(),
KeepAliveInterval: peer.PersistentKeepaliveInterval.Seconds(),
LastHandshakeTime: peer.LastHandshakeTime.Format(time.RFC3339),
ReceiveBytes: peer.ReceiveBytes,
TransmitBytes: peer.TransmitBytes,
AllowedIPs: "",
ProtocolVersion: peer.ProtocolVersion,
}

if showCredential {
c.PresharedKey = peer.PresharedKey.String()
}
allowdIpStrings := make([]string, 0, len(peer.AllowedIPs))
for _, v := range peer.AllowedIPs {
allowdIpStrings = append(allowdIpStrings, v.String())
}
c.AllowedIPs = strings.Join(allowdIpStrings, ", ")
t.Execute(os.Stdout, c)

}
62 changes: 62 additions & 0 deletions wgconf/config/config_test.go
@@ -0,0 +1,62 @@
package config

import (
"bytes"
"github.com/stretchr/testify/assert"
"net"
"testing"

"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)

func newSource() *bytes.Buffer {
const s = `
[Interface]
ListenPort = 51820
PrivateKey = XbHLxgz75/yVgxeQoTegSTQlrpWObIcnqlAWzawY3SI=
[Peer]
# foo
PublicKey = wALKCWOGCXMNISqMgJNa6DwNxe62fzKYRgtuIM1NGVc=
PresharedKey = W9tyo4+5i39K58Tm3TyJ9M7R9o2IU8RMttloSRzTjZI=
AllowedIPs = 10.200.200.2/32, 10.200.200.3/24
Endpoint = 192.168.0.100:7777
[Peer]
# bar
PublicKey = z+H+iGabx7HcDfL+vh6DD/ARlY0CgFe7rC+lu/9fC9w=
`
return bytes.NewBufferString(s)
}

func TestLoadConfig(t *testing.T) {
cfg, err := LoadConfig(newSource())
assert.NoError(t, err)
assert.Equal(t, 51820, *cfg.ListenPort)
key, err := wgtypes.ParseKey("XbHLxgz75/yVgxeQoTegSTQlrpWObIcnqlAWzawY3SI=")
assert.NoError(t, err)
assert.Equal(t, key, *cfg.PrivateKey)
assert.Equal(t, 2, len(cfg.Peers))
peer0 := cfg.Peers[0]
assert.Equal(t, net.ParseIP("192.168.0.100"), peer0.Endpoint.IP)
assert.Equal(t, 7777, peer0.Endpoint.Port)
assert.Equal(t, 2, len(peer0.AllowedIPs))
allowedIPs := peer0.AllowedIPs
assert.True(t, net.IPv4(10, 200, 200, 2).Equal(allowedIPs[0].IP))
assert.Equal(t, net.IPv4Mask(255, 255, 255, 255), allowedIPs[0].Mask)
assert.True(t, net.IPv4(10, 200, 200, 0).Equal(allowedIPs[1].IP))
assert.Equal(t, net.IPv4Mask(255, 255, 255, 0), allowedIPs[1].Mask)
assert.Equal(t, mustDecodeKey("wALKCWOGCXMNISqMgJNa6DwNxe62fzKYRgtuIM1NGVc="), peer0.PublicKey)
assert.Equal(t, mustDecodeKey("W9tyo4+5i39K58Tm3TyJ9M7R9o2IU8RMttloSRzTjZI="), *peer0.PresharedKey)

peer1 := cfg.Peers[1]
assert.Equal(t, mustDecodeKey("z+H+iGabx7HcDfL+vh6DD/ARlY0CgFe7rC+lu/9fC9w="), peer1.PublicKey)
}

func mustDecodeKey(s string) wgtypes.Key {
key, err := wgtypes.ParseKey(s)
if err != nil {
panic(err)
}
return key
}

0 comments on commit 2dcbbc4

Please sign in to comment.