This repository has been archived by the owner on Jul 5, 2021. It is now read-only.
forked from WireGuard/wgctrl-go
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wgconf could be used to configure wireguard-go from config file.
- Loading branch information
1 parent
23406de
commit 2dcbbc4
Showing
6 changed files
with
484 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
Oops, something went wrong.