2425a06cd8
This commit adds support for defining arbitrary peers that should have access to the VPN. In k8s, this is accomplished using the new Peer CRD.
131 lines
3.5 KiB
Go
131 lines
3.5 KiB
Go
// Copyright 2019 the Kilo authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package wireguard
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os/exec"
|
|
"regexp"
|
|
"strconv"
|
|
|
|
"github.com/vishvananda/netlink"
|
|
)
|
|
|
|
type wgLink struct {
|
|
a netlink.LinkAttrs
|
|
t string
|
|
}
|
|
|
|
func (w wgLink) Attrs() *netlink.LinkAttrs {
|
|
return &w.a
|
|
}
|
|
|
|
func (w wgLink) Type() string {
|
|
return w.t
|
|
}
|
|
|
|
// New creates a new WireGuard interface.
|
|
func New(prefix string) (int, error) {
|
|
links, err := netlink.LinkList()
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to list links: %v", err)
|
|
}
|
|
max := 0
|
|
re := regexp.MustCompile(fmt.Sprintf("^%s([0-9]+)$", prefix))
|
|
for _, link := range links {
|
|
if matches := re.FindStringSubmatch(link.Attrs().Name); len(matches) == 2 {
|
|
i, err := strconv.Atoi(matches[1])
|
|
if err != nil {
|
|
// This should never happen.
|
|
return 0, fmt.Errorf("failed to parse digits as an integer: %v", err)
|
|
}
|
|
if i >= max {
|
|
max = i + 1
|
|
}
|
|
}
|
|
}
|
|
name := fmt.Sprintf("%s%d", prefix, max)
|
|
wl := wgLink{a: netlink.NewLinkAttrs(), t: "wireguard"}
|
|
wl.a.Name = name
|
|
if err := netlink.LinkAdd(wl); err != nil {
|
|
return 0, fmt.Errorf("failed to create interface %s: %v", name, err)
|
|
}
|
|
link, err := netlink.LinkByName(name)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("failed to get interface index: %v", err)
|
|
}
|
|
return link.Attrs().Index, nil
|
|
}
|
|
|
|
// Keys generates a WireGuard private and public key-pair.
|
|
func Keys() ([]byte, []byte, error) {
|
|
private, err := GenKey()
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to generate private key: %v", err)
|
|
}
|
|
public, err := PubKey(private)
|
|
return private, public, err
|
|
}
|
|
|
|
// GenKey generates a WireGuard private key.
|
|
func GenKey() ([]byte, error) {
|
|
key, err := exec.Command("wg", "genkey").Output()
|
|
return bytes.Trim(key, "\n"), err
|
|
}
|
|
|
|
// PubKey generates a WireGuard public key for a given private key.
|
|
func PubKey(key []byte) ([]byte, error) {
|
|
cmd := exec.Command("wg", "pubkey")
|
|
stdin, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open pipe to stdin: %v", err)
|
|
}
|
|
|
|
go func() {
|
|
defer stdin.Close()
|
|
stdin.Write(key)
|
|
}()
|
|
|
|
public, err := cmd.Output()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate public key: %v", err)
|
|
}
|
|
return bytes.Trim(public, "\n"), nil
|
|
}
|
|
|
|
// SetConf applies a WireGuard configuration file to the given interface.
|
|
func SetConf(iface string, path string) error {
|
|
cmd := exec.Command("wg", "setconf", iface, path)
|
|
var stderr bytes.Buffer
|
|
cmd.Stderr = &stderr
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("failed to apply the WireGuard configuration: %s", stderr.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ShowConf gets the WireGuard configuration for the given interface.
|
|
func ShowConf(iface string) ([]byte, error) {
|
|
cmd := exec.Command("wg", "showconf", iface)
|
|
var stderr, stdout bytes.Buffer
|
|
cmd.Stderr = &stderr
|
|
cmd.Stdout = &stdout
|
|
if err := cmd.Run(); err != nil {
|
|
return nil, fmt.Errorf("failed to read the WireGuard configuration: %s", stderr.String())
|
|
}
|
|
return stdout.Bytes(), nil
|
|
}
|