Initial prototype server
parent
5801fb1087
commit
42eb0ea8ef
43
README.md
43
README.md
|
@ -11,7 +11,7 @@ In summary:
|
||||||
|
|
||||||
* Manage "client" keys
|
* Manage "client" keys
|
||||||
* Exchange keys over HTTP(S)
|
* Exchange keys over HTTP(S)
|
||||||
* Exchange IP addressing (DHCP-like)
|
* Exchange IP addressing
|
||||||
* Manually gate new peers
|
* Manually gate new peers
|
||||||
* Sets up network interface on the "client"
|
* Sets up network interface on the "client"
|
||||||
* Generate Ansible INI inventory
|
* Generate Ansible INI inventory
|
||||||
|
@ -27,3 +27,44 @@ The primary scenario this tool is going to be used for is to manage machines usi
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
> TODO
|
> TODO
|
||||||
|
|
||||||
|
# Operation
|
||||||
|
|
||||||
|
## Server
|
||||||
|
|
||||||
|
The "server" manages a WireGuard interface, treating a WireGuard configuration file as a database. It assumes this interface and configuration exists. It only adds new peers to the configuration file and interface, and does not delete existing configuration.
|
||||||
|
|
||||||
|
The "server" also exposes the HTTP server with the following endpoints:
|
||||||
|
|
||||||
|
### `POST /request`
|
||||||
|
|
||||||
|
Request for the assignment of an IP address and accepted as a peer. This blocks until the server has finished configuring the peer, therefore the client SHOULD NOT timeout.
|
||||||
|
|
||||||
|
#### Request Body
|
||||||
|
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
| Name | Description | Required |
|
||||||
|
|------|-------------|----------|
|
||||||
|
| PublicKey | The public key of the "client" peer | X |
|
||||||
|
|
||||||
|
#### Response Body
|
||||||
|
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|------|------|-------------|
|
||||||
|
| PublicKey | String | Base64 encoded public key of the "server" peer |
|
||||||
|
| Endpoint | String | The endpoint of the "server" peer |
|
||||||
|
| PersistentKeepaliveInterval | Number | Suggests a PersistentKeepaliveInterval |
|
||||||
|
| AllowedIPs | []String | List of allowed IP addresses in CIDR notation |
|
||||||
|
| InterfaceIPs | []String | List of IP addresses assigned to the "client" interface |
|
||||||
|
|
||||||
|
## Client
|
||||||
|
|
||||||
|
The "client" sets up a WireGuard interface, and relies on network backends to do so. *It should not be run more than once*. The following network backends are supported:
|
||||||
|
|
||||||
|
- (Not implemented) `none`: Creates an interface and WireGuard configuration file
|
||||||
|
- `networkd`: Creates a `systemd.netdev` file in `/etc/systemd/network`
|
||||||
|
|
||||||
|
It does so by performing `POST /request` to the "server".
|
||||||
|
|
|
@ -19,33 +19,58 @@ var CmdRequest = &cli.Command{
|
||||||
Usage: "Name for new WireGuard interface",
|
Usage: "Name for new WireGuard interface",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "config",
|
Name: "none",
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
Value: "",
|
Value: "",
|
||||||
DefaultText: "/etc/wireguard/<interface>.conf",
|
DefaultText: "/etc/wireguard/<interface>.conf",
|
||||||
Usage: "Path to the WireGuard configuration file",
|
Usage: "Path to save a WireGuard configuration file",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "type",
|
Name: "networkd",
|
||||||
Value: "none",
|
Aliases: []string{"n"},
|
||||||
Usage: "Select network interface backend. Currently only none and networkd are implemented",
|
Value: "",
|
||||||
|
DefaultText: "/etc/systemd/network/<interface>.netdev",
|
||||||
|
Usage: "Path to save a networkd configuration file",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "type",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Value: "networkd",
|
||||||
|
Usage: "Select network interface backend. Currently only networkd is implemented",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "server",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Usage: "wireguard-negotiator server URL",
|
||||||
|
Required: true,
|
||||||
|
EnvVars: []string{"WGN_SERVER_URL"},
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "insecure",
|
||||||
|
Usage: "Disable TLS verification",
|
||||||
|
EnvVars: []string{"WGN_SERVER_INSECURE"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRequest(ctx *cli.Context) error {
|
func runRequest(ctx *cli.Context) error {
|
||||||
inter := ctx.String("interface")
|
inter := ctx.String("interface")
|
||||||
config := ctx.String("config")
|
|
||||||
if !ctx.IsSet("config") {
|
|
||||||
config = "/etc/wireguard/" + inter + ".conf"
|
|
||||||
}
|
|
||||||
netBackend := ctx.String("type")
|
netBackend := ctx.String("type")
|
||||||
|
noneConfig := ctx.String("none")
|
||||||
|
if !ctx.IsSet("none") {
|
||||||
|
noneConfig = "/etc/wireguard/" + inter + ".conf"
|
||||||
|
}
|
||||||
|
networkdConfig := ctx.String("networkd")
|
||||||
|
if !ctx.IsSet("networkd") {
|
||||||
|
networkdConfig = "/etc/systemd/network/" + inter + ".netdev"
|
||||||
|
}
|
||||||
|
|
||||||
client := lib.NewClient(ctx.String("server"), ctx.Bool("insecure"))
|
client := lib.NewClient(ctx.String("server"), ctx.Bool("insecure"))
|
||||||
|
|
||||||
log.Println(inter)
|
log.Println(inter)
|
||||||
log.Println(config)
|
|
||||||
log.Println(netBackend)
|
log.Println(netBackend)
|
||||||
|
log.Println(noneConfig)
|
||||||
|
log.Println(networkdConfig)
|
||||||
log.Println(client)
|
log.Println(client)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
218
cmd/server.go
218
cmd/server.go
|
@ -1,16 +1,23 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrNoAddressesFound = fmt.Errorf("No address found on the interface")
|
||||||
|
|
||||||
var CmdServer = &cli.Command{
|
var CmdServer = &cli.Command{
|
||||||
Name: "server",
|
Name: "server",
|
||||||
Usage: "Start the wireguard-negotiator server",
|
Usage: "Start the wireguard-negotiator server",
|
||||||
|
@ -26,13 +33,14 @@ var CmdServer = &cli.Command{
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
Value: "",
|
Value: "",
|
||||||
DefaultText: "/etc/wireguard/<interface>.conf",
|
DefaultText: "/etc/wireguard/<interface>.conf",
|
||||||
Usage: "Path to the WireGuard configuration file",
|
Usage: "Path to the existing WireGuard configuration file",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "endpoint",
|
Name: "endpoint",
|
||||||
Aliases: []string{"e"},
|
Aliases: []string{"e"},
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Set the endpoint address",
|
Required: true,
|
||||||
|
Usage: "Set the endpoint address",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "listen",
|
Name: "listen",
|
||||||
|
@ -51,33 +59,37 @@ type request struct {
|
||||||
|
|
||||||
func runServer(ctx *cli.Context) error {
|
func runServer(ctx *cli.Context) error {
|
||||||
inter := ctx.String("interface")
|
inter := ctx.String("interface")
|
||||||
interf, err := net.InterfaceByName(inter)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
config := ctx.String("config")
|
config := ctx.String("config")
|
||||||
if !ctx.IsSet("config") {
|
if !ctx.IsSet("config") {
|
||||||
config = "/etc/wireguard/" + inter + ".conf"
|
config = "/etc/wireguard/" + inter + ".conf"
|
||||||
}
|
}
|
||||||
endpoint := ctx.String("endpoint")
|
endpoint := ctx.String("endpoint")
|
||||||
if !ctx.IsSet("endpoint") {
|
|
||||||
log.Fatal("Please specify endpoint with -endpoint")
|
|
||||||
}
|
|
||||||
listen := ctx.String("listen")
|
listen := ctx.String("listen")
|
||||||
|
|
||||||
// Obtain the server's public key
|
// Obtain the network interface
|
||||||
serverPublicKey := configReadInterfacePublicKey(config)
|
interf, err := net.InterfaceByName(inter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain the server's public key
|
||||||
|
serverPublicKey, err := configReadInterfacePublicKey(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Define this allocation method
|
||||||
|
// TODO: Include allocation behaviour in README
|
||||||
terribleCounterThatShouldNotExist := 1
|
terribleCounterThatShouldNotExist := 1
|
||||||
interfAddrs, err := interf.Addrs()
|
interfAddrs, err := interf.Addrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
// TODO: Define this allocation method
|
|
||||||
// TODO: Include allocation behaviour in README
|
// Obtain interface address for use in allocation
|
||||||
var interfIPNet *net.IPNet
|
var interfIPNet *net.IPNet
|
||||||
if len(interfAddrs) < 1 {
|
if len(interfAddrs) < 1 {
|
||||||
log.Fatal("No address found on the interface")
|
return ErrNoAddressesFound
|
||||||
}
|
}
|
||||||
_, interfIPNet, err = net.ParseCIDR(interfAddrs[0].String())
|
_, interfIPNet, err = net.ParseCIDR(interfAddrs[0].String())
|
||||||
|
|
||||||
|
@ -90,62 +102,112 @@ func runServer(ctx *cli.Context) error {
|
||||||
// TODO: Rate limiting
|
// TODO: Rate limiting
|
||||||
|
|
||||||
http.HandleFunc("/request", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/request", func(w http.ResponseWriter, r *http.Request) {
|
||||||
publicKey := r.PostFormValue("public_key")
|
switch r.Method {
|
||||||
// TODO: Ensure public key is new
|
case "POST":
|
||||||
// Assign an IP address
|
publicKey := r.PostFormValue("PublicKey")
|
||||||
terribleCounterThatShouldNotExist += 1
|
// TODO: Ensure public key is new
|
||||||
ip := incrementIP(interfIPNet.IP, terribleCounterThatShouldNotExist)
|
if len(publicKey) == 0 {
|
||||||
if !interfIPNet.Contains(ip) {
|
w.WriteHeader(400)
|
||||||
log.Fatal("Ran out of IP addresses to allocate")
|
return
|
||||||
}
|
}
|
||||||
// Enqueue request into the gate
|
|
||||||
req := request{
|
// Assign an IP address
|
||||||
ip: ip,
|
terribleCounterThatShouldNotExist += 1
|
||||||
publicKey: publicKey,
|
ip := incrementIP(interfIPNet.IP, terribleCounterThatShouldNotExist)
|
||||||
}
|
if !interfIPNet.Contains(ip) {
|
||||||
// Wait for flush of configuration
|
log.Println("WARNING: Ran out of addresses to allocate")
|
||||||
gateQueue <- req
|
w.WriteHeader(500)
|
||||||
// Produce configuration to client
|
return
|
||||||
ipNet := &net.IPNet{
|
}
|
||||||
IP: ip,
|
|
||||||
Mask: interfIPNet.Mask,
|
// Enqueue request into the gate
|
||||||
}
|
req := request{
|
||||||
resp := struct {
|
ip: ip,
|
||||||
interfaceIP string `json:"interface_ip"`
|
publicKey: publicKey,
|
||||||
peerAllowedIPs string `json:"peer_allowed_ips"`
|
}
|
||||||
peerPublicKey string `json:"peer_public_key"`
|
|
||||||
peerEndpoint string `json:"peer_endpoint"`
|
// Wait for flush of configuration
|
||||||
}{
|
gateQueue <- req
|
||||||
ipNet.String(),
|
|
||||||
interfIPNet.IP.Mask(interfIPNet.Mask),
|
// Produce configuration to client
|
||||||
"",
|
ipNet := &net.IPNet{
|
||||||
"",
|
IP: ip,
|
||||||
|
Mask: interfIPNet.Mask,
|
||||||
|
}
|
||||||
|
resp := struct {
|
||||||
|
InterfaceIPs string
|
||||||
|
AllowedIPs string
|
||||||
|
PublicKey string
|
||||||
|
Endpoint string
|
||||||
|
PersistentKeepaliveInterval int
|
||||||
|
}{
|
||||||
|
ipNet.String(),
|
||||||
|
interfIPNet.IP.Mask(interfIPNet.Mask).String(),
|
||||||
|
serverPublicKey,
|
||||||
|
endpoint,
|
||||||
|
25,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(resp)
|
||||||
|
default:
|
||||||
|
w.WriteHeader(405)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
http.ListenAndServe(listen, nil)
|
// Shutdown notifier
|
||||||
|
go func() {
|
||||||
|
sigint := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigint, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-sigint
|
||||||
|
close(gateQueue)
|
||||||
|
close(addQueue)
|
||||||
|
/*
|
||||||
|
if err := http.Shutdown(context.Background()); err != nil {
|
||||||
|
log.Printf("Server shutdown error: %v\n", err)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}()
|
||||||
|
|
||||||
return nil
|
return http.ListenAndServe(listen, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func adder(queue chan request, inter string, config string) {
|
func adder(queue chan request, inter string, config string) {
|
||||||
// Write requests to config and add peer
|
// Write requests to config and add peer
|
||||||
for req := range queue {
|
for {
|
||||||
configAddPeer(config, req)
|
select {
|
||||||
interAddPeer(inter, req, config)
|
case req, ok := <-queue:
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := configAddPeer(config, req)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
err = interAddPeer(inter, req, config)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gater(queue chan request, result chan request) {
|
func gater(queue chan request, result chan request) {
|
||||||
// Receive requests and prompt the admin
|
// Receive requests and prompt the admin
|
||||||
for req := range queue {
|
for {
|
||||||
// For now, accept all
|
select {
|
||||||
log.Println(req)
|
case req, ok := <-queue:
|
||||||
result <- req
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// For now, accept all
|
||||||
|
log.Println(req.ip.String(), req.publicKey)
|
||||||
|
result <- req
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func configAddPeer(config string, req request) {
|
func configAddPeer(config string, req request) error {
|
||||||
// For every request, we'll just open the config file again and rewrite it
|
// For every request, we'll just open the config file again and rewrite it
|
||||||
// We don't need to optimise this because it happens infrequently
|
// We don't need to optimise this because it happens infrequently
|
||||||
|
|
||||||
|
@ -159,36 +221,44 @@ func configAddPeer(config string, req request) {
|
||||||
publicKey.SetValue(req.publicKey)
|
publicKey.SetValue(req.publicKey)
|
||||||
allowedIPs := sec.Key("AllowedIPs")
|
allowedIPs := sec.Key("AllowedIPs")
|
||||||
allowedHost := ipToIPNetWithHostMask(req.ip)
|
allowedHost := ipToIPNetWithHostMask(req.ip)
|
||||||
allowedIPs.AddShadow((&allowedHost).String())
|
allowedIPs.SetValue((&allowedHost).String())
|
||||||
|
|
||||||
f, err := os.OpenFile(config, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
f, err := os.OpenFile(config, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return fmt.Errorf("opening %s failed: %w", config, err)
|
||||||
}
|
}
|
||||||
_, err = cfg.WriteTo(f)
|
_, err = cfg.WriteTo(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return fmt.Errorf("writing to %s failed: %w", config, err)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configReadInterfacePublicKey(config string) string {
|
func configReadInterfacePublicKey(config string) (string, error) {
|
||||||
cfg, err := ini.Load(config)
|
cfg, err := ini.Load(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to read interface public key")
|
return "", fmt.Errorf("read interface public key failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg.Section("Interface").Key("PrivateKey")
|
b64PrivateKey := cfg.Section("Interface").Key("PrivateKey").String()
|
||||||
|
wgPrivateKey, err := wgtypes.ParseKey(b64PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("read interface public key failed: %w", err)
|
||||||
|
}
|
||||||
|
wgPublicKey := wgPrivateKey.PublicKey()
|
||||||
|
return wgPublicKey.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func interAddPeer(inter string, req request, config string) {
|
func interAddPeer(inter string, req request, config string) error {
|
||||||
// For every request, we also need to dynamically add the peer to the interface
|
// For every request, we also need to dynamically add the peer to the interface
|
||||||
|
|
||||||
// For now, we simply run one fixed command to reread from the config file
|
// For now, we simply run one fixed command to reread from the config file
|
||||||
cmd := exec.Command("wg", "setconf", inter, config)
|
cmd := exec.Command("wg", "setconf", inter, config)
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
return fmt.Errorf("wq setconf failed: %w", err)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -206,11 +276,19 @@ func ipToIPNetWithHostMask(ip net.IP) net.IPNet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func incrementIP(ip net.IP) net.IP {
|
func incrementIP(ip net.IP, inc int) net.IP {
|
||||||
|
result := make(net.IP, len(ip))
|
||||||
|
copy(result, ip)
|
||||||
|
|
||||||
for i := len(ip) - 1; i >= 0; i-- {
|
for i := len(ip) - 1; i >= 0; i-- {
|
||||||
ip[i]++
|
remainder := inc % 256
|
||||||
if ip[i] != 0 {
|
overflow := int(result[i])+remainder > 255
|
||||||
break
|
|
||||||
|
result[i] += byte(remainder)
|
||||||
|
if overflow {
|
||||||
|
inc += 256
|
||||||
}
|
}
|
||||||
|
inc /= 256
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -4,5 +4,6 @@ go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/urfave/cli/v2 v2.0.0
|
github.com/urfave/cli/v2 v2.0.0
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191219145116-fa6499c8e75f
|
||||||
gopkg.in/ini.v1 v1.51.0
|
gopkg.in/ini.v1 v1.51.0
|
||||||
)
|
)
|
||||||
|
|
32
go.sum
32
go.sum
|
@ -1,6 +1,13 @@
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||||
|
github.com/mdlayher/genetlink v0.0.0-20191205172946-651acf4b47ef/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
|
||||||
|
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||||
|
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||||
|
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
@ -9,6 +16,31 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||||
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
||||||
github.com/urfave/cli/v2 v2.0.0 h1:+HU9SCbu8GnEUFtIBfuUNXN39ofWViIEJIp6SURMpCg=
|
github.com/urfave/cli/v2 v2.0.0 h1:+HU9SCbu8GnEUFtIBfuUNXN39ofWViIEJIp6SURMpCg=
|
||||||
github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
|
||||||
|
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
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-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191218084908-4a24b4065292/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
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=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191219145116-fa6499c8e75f h1:xc7xbwx/flY4HCaTpfgGqvsEMELJ5EBF82MP2lvfdbo=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191219145116-fa6499c8e75f/go.mod h1:QKgTDEXdhtb9dg1EdxK63hefKjD1e+bSXUbRmZBfCSw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
//"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReadConfig is yet another INI-like configuration file parser, but for WireGuard
|
|
@ -0,0 +1,23 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var testGoodConfiguration1 = `
|
||||||
|
# Test = Example comment
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
# Test comment 2
|
||||||
|
ListenPort = 3333
|
||||||
|
PrivateKey = MITUgapB4QfRFF54ITXL3TaiYiSsVYkchqfjAXjxM10=
|
||||||
|
[Peer]
|
||||||
|
PublicKey = pjFx72IjbMh84SH1nq8Qfbl7HD5mSScHXCV1eISR7lk=
|
||||||
|
AllowedIPs = 192.168.10.2/32, 2001:470:ed5d:a::2/128
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
AllowedIPs = 192.168.10.40/32, 2001:470:ed5d:a::28/128
|
||||||
|
PublicKey = wXU+vSTdEoIwSi+Tmv35SCOFg17wCAwnmYxeQPpbzDg=
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestReadConfig(t *testing.T) {
|
||||||
|
|
||||||
|
}
|
14
main.go
14
main.go
|
@ -13,19 +13,7 @@ func main() {
|
||||||
app := &cli.App{
|
app := &cli.App{
|
||||||
Name: "wireguard-negotiator",
|
Name: "wireguard-negotiator",
|
||||||
Usage: "Exchange WireGuard keys over HTTP(S)",
|
Usage: "Exchange WireGuard keys over HTTP(S)",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{},
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "server",
|
|
||||||
Aliases: []string{"s"},
|
|
||||||
Usage: "wireguard-negotiator server URL",
|
|
||||||
EnvVars: []string{"WGN_SERVER_URL"},
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "insecure",
|
|
||||||
Usage: "Disable TLS verification",
|
|
||||||
EnvVars: []string{"WGN_SERVER_INSECURE"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
cmd.CmdServer,
|
cmd.CmdServer,
|
||||||
cmd.CmdList,
|
cmd.CmdList,
|
||||||
|
|
Loading…
Reference in New Issue