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

Commit

Permalink
Replace original wgctrl
Browse files Browse the repository at this point in the history
  • Loading branch information
QuantumGhost committed Nov 5, 2019
1 parent 2dcbbc4 commit d379964
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 215 deletions.
181 changes: 116 additions & 65 deletions cmd/wgctrl/main.go
@@ -1,93 +1,144 @@
// Command wgctrl is a testing utility for interacting with WireGuard via package
// wgctrl.
package main

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

"github.com/alecthomas/kingpin"

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

func main() {
flag.Parse()

c, err := wgctrl.New()
if err != nil {
log.Fatalf("failed to open wgctrl: %v", err)
}
defer c.Close()

var devices []*wgtypes.Device
if device := flag.Arg(0); device != "" {
d, err := c.Device(device)
if err != nil {
log.Fatalf("failed to get device %q: %v", device, err)
}

devices = append(devices, d)
} else {
devices, err = c.Devices()
if err != nil {
log.Fatalf("failed to get devices: %v", err)
}
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)
}
}

for _, d := range devices {
printDevice(d)
func newCommandLine() *kingpin.Application {
return kingpin.New("wgconf", "wireguard configuring tool")
}

for _, p := range d.Peers {
printPeer(p)
}
}
type getOption struct {
Interface string
ShowCredential bool
}

func printDevice(d *wgtypes.Device) {
const f = `interface: %s (%s)
public key: %s
private key: (hidden)
listening port: %d
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
}

fmt.Printf(
f,
d.Name,
d.Type.String(),
d.PublicKey.String(),
d.ListenPort)
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 printPeer(p wgtypes.Peer) {
const f = `peer: %s
endpoint: %s
allowed ips: %s
latest handshake: %s
transfer: %d B received, %d B sent
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 {
printPeer(peer, opt.ShowCredential)
}
}

fmt.Printf(
f,
p.PublicKey.String(),
// TODO(mdlayher): get right endpoint with getnameinfo.
p.Endpoint.String(),
ipsString(p.AllowedIPs),
p.LastHandshakeTime.String(),
p.ReceiveBytes,
p.TransmitBytes,
)
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 ipsString(ipns []net.IPNet) string {
ss := make([]string, 0, len(ipns))
for _, ipn := range ipns {
ss = append(ss, ipn.String())
func printPeer(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,
}

return strings.Join(ss, ", ")
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)
}
15 changes: 14 additions & 1 deletion wgconf/config/parser.go → config/parser.go
Expand Up @@ -132,7 +132,20 @@ func parseInterfaceField(cfg *wgtypes.Config, p pair) *parseError {
}
cfg.ListenPort = &port
case "FwMark":
return &parseError{message: "FwMark is not supported"}
value := strings.ToLower(p.value)
base := 10
if strings.HasPrefix(value, "0x") {
value = value[2:]
base = 16
}
fwmark, err := strconv.ParseInt(value, base, 32)
if err != nil {
return &parseError{message: err.Error()}
}
if fwmark != 0 {
fwmarkInt := int(fwmark)
cfg.FirewallMark = &fwmarkInt
}
default:
return &parseError{message: fmt.Sprintf("invalid key %s for Interface section", p.key)}
}
Expand Down
6 changes: 5 additions & 1 deletion wgconf/config/config_test.go → config/parser_test.go
Expand Up @@ -2,10 +2,11 @@ package config

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

"github.com/stretchr/testify/assert"

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

Expand All @@ -14,6 +15,7 @@ func newSource() *bytes.Buffer {
[Interface]
ListenPort = 51820
PrivateKey = XbHLxgz75/yVgxeQoTegSTQlrpWObIcnqlAWzawY3SI=
FwMark = 10
[Peer]
# foo
Expand All @@ -36,7 +38,9 @@ func TestLoadConfig(t *testing.T) {
key, err := wgtypes.ParseKey("XbHLxgz75/yVgxeQoTegSTQlrpWObIcnqlAWzawY3SI=")
assert.NoError(t, err)
assert.Equal(t, key, *cfg.PrivateKey)
assert.Equal(t, 10, *cfg.FirewallMark)
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)
Expand Down
4 changes: 1 addition & 3 deletions wgconf/examples/full.conf → examples/full.conf
Expand Up @@ -3,8 +3,7 @@
[Interface]
ListenPort = 51820
PrivateKey = LEvpMepC4lqD7CJghor8f1cwA4E5r6AXrVRkXQQav6s=
# FwMark is not supported
# FwMark = 0
FwMark = 10 # or FwMark = 0x11
# PostUp and PostDown hooks are not supported.

[Peer]
Expand All @@ -14,7 +13,6 @@ AllowedIPs = 10.200.200.2/32
Endpoint = www.example.com:880
PersistentKeepalive = 30 # in seconds


# Another peer
# [Peer]
# PublicKey = [BAR'S PUBLIC KEY]
Expand Down

0 comments on commit d379964

Please sign in to comment.