blob: cbe5ab9f78a06acae7ce390d14b322d2f1ebbcf3 [file] [log] [blame]
giolekva3c0e1822021-03-15 00:08:44 +04001package engine
2
3import (
giolekva3c0e1822021-03-15 00:08:44 +04004 "fmt"
5 "log"
6
7 "github.com/giolekva/pcloud/core/vpn/types"
giolekva2a088e22021-08-01 14:20:25 +04008 "golang.zx2c4.com/wireguard/tun"
giolekva3c0e1822021-03-15 00:08:44 +04009
giolekva3c0e1822021-03-15 00:08:44 +040010 "inet.af/netaddr"
giolekva3c0e1822021-03-15 00:08:44 +040011 "tailscale.com/ipn/ipnstate"
giolekva2a088e22021-08-01 14:20:25 +040012 "tailscale.com/net/dns"
giolekva3c0e1822021-03-15 00:08:44 +040013 "tailscale.com/tailcfg"
giolekva2a088e22021-08-01 14:20:25 +040014 "tailscale.com/types/netmap"
giolekva3c0e1822021-03-15 00:08:44 +040015 "tailscale.com/types/wgkey"
16 "tailscale.com/wgengine"
17 "tailscale.com/wgengine/router"
giolekva2a088e22021-08-01 14:20:25 +040018 "tailscale.com/wgengine/wgcfg"
giolekva3c0e1822021-03-15 00:08:44 +040019)
20
21// Wireguard specific implementation of the Engine interface.
22type WireguardEngine struct {
23 wg wgengine.Engine
24 port uint16
25 privKey types.PrivateKey
26}
27
28// Creates Wireguard engine.
29func NewWireguardEngine(tunName string, port uint16, privKey types.PrivateKey) (Engine, error) {
giolekva2a088e22021-08-01 14:20:25 +040030 tun, err := tun.CreateTUN(tunName, 1500)
31 if err != nil {
32 return nil, err
33 }
34 e, err := wgengine.NewUserspaceEngine(log.Printf, wgengine.Config{
35 Tun: tun,
36 ListenPort: port,
37 })
giolekva3c0e1822021-03-15 00:08:44 +040038 if err != nil {
39 return nil, err
40 }
41 return &WireguardEngine{
42 wg: e,
43 port: port,
44 privKey: privKey,
45 }, nil
46}
47
48// Used for unit testing.
49func NewFakeWireguardEngine(port uint16, privKey types.PrivateKey) (Engine, error) {
giolekva2a088e22021-08-01 14:20:25 +040050 e, err := wgengine.NewFakeUserspaceEngine(log.Printf, port)
giolekva3c0e1822021-03-15 00:08:44 +040051 if err != nil {
52 return nil, err
53 }
54 return &WireguardEngine{
55 wg: e,
56 port: port,
57 privKey: privKey,
58 }, nil
59}
60
giolekva98a695d2021-03-15 12:43:20 +040061func genWireguardConf(privKey types.PrivateKey, port uint16,
62 netMap *types.NetworkMap) *wgcfg.Config {
giolekva3c0e1822021-03-15 00:08:44 +040063 c := &wgcfg.Config{
giolekva98a695d2021-03-15 12:43:20 +040064 // TODO(giolekva): we shoudld probably use hostname and share
65 // it with the controller
66 Name: "local-node",
giolekva2a088e22021-08-01 14:20:25 +040067 PrivateKey: wgkey.Private(privKey),
68 Addresses: []netaddr.IPPrefix{netaddr.IPPrefixFrom(
69 netMap.Self.VPNIP,
70 32, // TODO(giolekva): adapt for IPv6
71 )},
72 // ListenPort: port,
73 Peers: make([]wgcfg.Peer, 0, len(netMap.Peers)),
giolekva3c0e1822021-03-15 00:08:44 +040074 }
75 for _, peer := range netMap.Peers {
76 c.Peers = append(c.Peers, wgcfg.Peer{
giolekva2a088e22021-08-01 14:20:25 +040077 PublicKey: wgkey.Key(peer.PublicKey),
78 AllowedIPs: []netaddr.IPPrefix{netaddr.IPPrefixFrom(
79 peer.VPNIP,
80 32,
81 )},
82 Endpoints: wgcfg.Endpoints{
83 DiscoKey: tailcfg.DiscoKey(peer.DiscoKey),
84 },
giolekva3c0e1822021-03-15 00:08:44 +040085 PersistentKeepalive: 15, // TODO(giolekva): make it configurable
86 })
87 }
88 return c
89}
90
91func genRouterConf(netMap *types.NetworkMap) *router.Config {
92 c := &router.Config{
giolekva2a088e22021-08-01 14:20:25 +040093 LocalAddrs: []netaddr.IPPrefix{netaddr.IPPrefixFrom(
94 netMap.Self.VPNIP,
95 32,
96 )},
giolekva3c0e1822021-03-15 00:08:44 +040097 Routes: make([]netaddr.IPPrefix, 0, len(netMap.Peers)),
98 }
99 for _, peer := range netMap.Peers {
giolekva2a088e22021-08-01 14:20:25 +0400100 c.Routes = append(c.Routes, netaddr.IPPrefixFrom(
101 peer.VPNIP,
102 32,
103 ))
giolekva3c0e1822021-03-15 00:08:44 +0400104 }
105 return c
106}
107
giolekva2a088e22021-08-01 14:20:25 +0400108func genTailNetMap(privKey types.PrivateKey, port uint16, netMap *types.NetworkMap) *netmap.NetworkMap {
109 c := &netmap.NetworkMap{
giolekva3c0e1822021-03-15 00:08:44 +0400110 SelfNode: &tailcfg.Node{
111 ID: 0, // TODO(giolekva): maybe IDs should be stored server side.
112 StableID: "0",
113 Name: "0",
114 Key: tailcfg.NodeKey(netMap.Self.PublicKey),
115 DiscoKey: tailcfg.DiscoKey(netMap.Self.DiscoKey),
giolekva2a088e22021-08-01 14:20:25 +0400116 Addresses: []netaddr.IPPrefix{netaddr.IPPrefixFrom(
117 netMap.Self.VPNIP,
118 32,
119 )},
giolekva3c0e1822021-03-15 00:08:44 +0400120 AllowedIPs: make([]netaddr.IPPrefix, 0, len(netMap.Peers)),
121 Endpoints: []string{netMap.Self.IPPort.String()},
122 KeepAlive: true, // TODO(giolekva): make it configurable
123 },
124 NodeKey: tailcfg.NodeKey(netMap.Self.PublicKey),
125 PrivateKey: wgkey.Private(privKey),
126 Name: "0",
giolekva2a088e22021-08-01 14:20:25 +0400127 Addresses: []netaddr.IPPrefix{netaddr.IPPrefixFrom(
128 netMap.Self.VPNIP,
129 32,
130 )},
giolekva3c0e1822021-03-15 00:08:44 +0400131 LocalPort: port,
132 Peers: make([]*tailcfg.Node, 0, len(netMap.Peers)),
133 }
134 for i, peer := range netMap.Peers {
135 c.Peers = append(c.Peers, &tailcfg.Node{
136 ID: tailcfg.NodeID(i + 1),
137 StableID: tailcfg.StableNodeID(fmt.Sprintf("%d", i+1)),
138 Name: fmt.Sprintf("%d", i+1),
139 Key: tailcfg.NodeKey(peer.PublicKey),
140 DiscoKey: tailcfg.DiscoKey(peer.DiscoKey),
giolekva2a088e22021-08-01 14:20:25 +0400141 Addresses: []netaddr.IPPrefix{netaddr.IPPrefixFrom(
142 peer.VPNIP,
143 32,
144 )},
145 AllowedIPs: []netaddr.IPPrefix{netaddr.IPPrefixFrom(
146 netMap.Self.VPNIP,
147 32,
148 )},
giolekva3c0e1822021-03-15 00:08:44 +0400149 Endpoints: []string{peer.IPPort.String()},
150 KeepAlive: true,
151 })
152 }
153 return c
154}
155
156func (e *WireguardEngine) Configure(netMap *types.NetworkMap) error {
157 err := e.wg.Reconfig(
158 genWireguardConf(e.privKey, e.port, netMap),
giolekva2a088e22021-08-01 14:20:25 +0400159 genRouterConf(netMap),
160 &dns.Config{},
161 nil)
giolekva3c0e1822021-03-15 00:08:44 +0400162 if err != nil {
163 return err
164 }
165 e.wg.SetNetworkMap(genTailNetMap(e.privKey, e.port, netMap))
166 e.wg.RequestStatus()
167 return err
168}
169
170func (e *WireguardEngine) DiscoKey() types.DiscoKey {
171 return types.DiscoKey(e.wg.DiscoPublicKey())
172}
173
giolekva3c0e1822021-03-15 00:08:44 +0400174func (e *WireguardEngine) Ping(ip netaddr.IP, cb func(*ipnstate.PingResult)) {
giolekva2a088e22021-08-01 14:20:25 +0400175 e.wg.Ping(ip, false, cb)
giolekva3c0e1822021-03-15 00:08:44 +0400176}