summaryrefslogtreecommitdiff
path: root/internal/wireguard/wireguard.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/wireguard/wireguard.go')
-rw-r--r--internal/wireguard/wireguard.go118
1 files changed, 97 insertions, 21 deletions
diff --git a/internal/wireguard/wireguard.go b/internal/wireguard/wireguard.go
index cc6c577..af290ea 100644
--- a/internal/wireguard/wireguard.go
+++ b/internal/wireguard/wireguard.go
@@ -2,34 +2,110 @@
package wireguard
import (
+ "errors"
"fmt"
- "regexp"
+ "net"
- "github.com/go-errors/errors"
+ "github.com/eduvpn/eduvpn-common/internal/wireguard/ini"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
-// GenerateKey generates a WireGuard private key using wgctrl
-// It returns an error if key generation failed.
-func GenerateKey() (wgtypes.Key, error) {
- key, err := wgtypes.GeneratePrivateKey()
+func availableTCPPort() (int, error) {
+ tcpaddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
if err != nil {
- return key, errors.WrapPrefix(err, "failed generating WireGuard key", 0)
+ return -1, err
}
- return key, nil
+ ltcp, err := net.ListenTCP("tcp", tcpaddr)
+ if err != nil {
+ return -1, err
+ }
+ defer ltcp.Close()
+ return ltcp.Addr().(*net.TCPAddr).Port, nil
+}
+
+func availableUDPPort() (int, error) {
+ udpaddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
+ if err != nil {
+ return -1, err
+ }
+ ludp, err := net.ListenUDP("udp", udpaddr)
+ if err != nil {
+ return -1, err
+ }
+ defer ludp.Close()
+ return ludp.LocalAddr().(*net.UDPAddr).Port, nil
+}
+
+type Proxy struct {
+ SourcePort int
+ Listen string
+ Peer string
+}
+
+func Config(cfg string, key *wgtypes.Key, tcp bool) (string, *Proxy, error) {
+ // the key is nil if the client does not accept WireGuard
+ if key == nil {
+ return "", nil, errors.New("the server sent us a WireGuard profile but the client does not accept WireGuard")
+ }
+
+ var tcpp int
+ var proxy string
+ var err error
+
+ if tcp {
+ tcpp, err = availableTCPPort()
+ if err != nil {
+ return "", nil, err
+ }
+ udpp, err := availableUDPPort()
+ if err != nil {
+ return "", nil, err
+ }
+ proxy = fmt.Sprintf("127.0.0.1:%d", udpp)
+ }
+
+ rcfg, peer, err := configReplace(cfg, *key, proxy)
+ if err != nil {
+ return "", nil, err
+ }
+ var retP *Proxy
+ if tcp {
+ retP = &Proxy{
+ SourcePort: tcpp,
+ Listen: proxy,
+ Peer: peer,
+ }
+ }
+ return rcfg, retP, nil
}
-// ConfigAddKey takes the WireGuard configuration and adds the PrivateKey to the right section
-// FIXME: Instead of doing a regex replace, decide if we should use a parser.
-func ConfigAddKey(config string, key wgtypes.Key) string {
- interfaceSection := "[Interface]"
- InterfaceSectionEscaped := regexp.QuoteMeta(interfaceSection)
-
- // (?m) enables multi line mode
- // ^ match from beginning of line
- // $ match till end of line
- // So it matches [Interface] section exactly
- InterfaceRe := regexp.MustCompile(fmt.Sprintf("(?m)^%s$", InterfaceSectionEscaped))
- toReplace := fmt.Sprintf("%s\nPrivateKey = %s", interfaceSection, key.String())
- return InterfaceRe.ReplaceAllString(config, toReplace)
+// ConfigReplace replaces the wireguard config with our private key and proxy in case of TCP
+func configReplace(cfg string, key wgtypes.Key, proxy string) (string, string, error) {
+ // first parse the config
+ secs := ini.Parse(cfg)
+ if secs.Empty() {
+ return "", "", errors.New("parsed ini is empty")
+ }
+
+ // find the interface section
+ // and set the private key
+ is, err := secs.Section("Interface")
+ if err != nil {
+ return "", "", err
+ }
+ is.AddOrReplaceKeyValue("PrivateKey", key.String())
+ peer := ""
+ if proxy != "" {
+ ps, err := secs.Section("Peer")
+ if err != nil {
+ return "", "", err
+ }
+ peer, err = ps.RemoveKey("TCPEndpoint")
+ if err != nil {
+ return "", "", err
+ }
+ ps.AddOrReplaceKeyValue("Endpoint", proxy)
+ }
+
+ return secs.String(), peer, nil
}