diff options
| author | David Anderson <danderson@tailscale.com> | 2021-08-30 14:30:06 -0700 |
|---|---|---|
| committer | David Anderson <danderson@tailscale.com> | 2021-08-30 14:30:06 -0700 |
| commit | 9c0a1375eb59721a7c9f46c5560531d8da45b750 (patch) | |
| tree | d23efab8641eebffd77c2187680b926dd624320a /wgengine/kproxy/proxy.go | |
| parent | a35c3ba2214bac4c05bac4c60d5e067607fdab11 (diff) | |
| download | tailscale-danderson/kernel-tailscale.tar.xz tailscale-danderson/kernel-tailscale.zip | |
WIP: kernel accelerated tailscaleddanderson/kernel-tailscale
Diffstat (limited to 'wgengine/kproxy/proxy.go')
| -rw-r--r-- | wgengine/kproxy/proxy.go | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/wgengine/kproxy/proxy.go b/wgengine/kproxy/proxy.go new file mode 100644 index 000000000..0174b2bd3 --- /dev/null +++ b/wgengine/kproxy/proxy.go @@ -0,0 +1,136 @@ +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package kproxy + +import ( + "encoding/json" + "net" + "sync" + + "golang.zx2c4.com/wireguard/conn" + "inet.af/netaddr" + "tailscale.com/tailcfg" + "tailscale.com/types/netmap" + "tailscale.com/types/wgkey" + "tailscale.com/wgengine/magicsock" + "tailscale.com/wgengine/wgcfg" +) + +type Proxy struct { + mu sync.RWMutex + conn *magicsock.Conn + byKey map[tailcfg.NodeKey]*pipe + byEndpoint map[conn.Endpoint]*pipe +} + +func New(c *magicsock.Conn) (*Proxy, error) { + ret := &Proxy{ + conn: c, + byEndpoint: map[conn.Endpoint]*pipe{}, + byKey: map[tailcfg.NodeKey]*pipe{}, + } + fns, _, err := c.Bind().Open(0) + if err != nil { + return nil, err + } + for _, fn := range fns { + go func(fn conn.ReceiveFunc) { + for { + var bs [1500]byte + n, ep, err := fn(bs[:]) + if err != nil { + // Sadness. + continue + } + ret.mu.RLock() + pip, ok := ret.byEndpoint[ep] + ret.mu.RUnlock() + if ok { + if _, err := pip.proxy.Write(bs[:n]); err != nil { + _ = err // TODO + } + } + } + }(fn) + } + + return ret, nil +} + +var proxyListenIP = netaddr.MustParseIPPort("127.0.0.1:0") +var wgIP = netaddr.MustParseIPPort("127.0.0.1:4242") + +func (p *Proxy) SetNetworkMap(nm *netmap.NetworkMap) (map[tailcfg.NodeKey]netaddr.IPPort, error) { + p.mu.Lock() + defer p.mu.Unlock() + ret := make(map[tailcfg.NodeKey]netaddr.IPPort, len(nm.Peers)) + for _, peer := range nm.Peers { + if pip, ok := p.byKey[peer.Key]; ok { + ret[peer.Key] = pip.proxyAddr + } else { + wgEp := wgcfg.Endpoints{ + PublicKey: wgkey.Key(peer.Key), + DiscoKey: peer.DiscoKey, + } + bs, err := json.Marshal(wgEp) + if err != nil { + return nil, err + } + ep, err := p.conn.ParseEndpoint(string(bs)) + if err != nil { + return nil, err + } + conn, err := net.DialUDP("udp4", proxyListenIP.UDPAddr(), wgIP.UDPAddr()) + if err != nil { + return nil, err + } + connAddr := netaddr.MustParseIPPort(conn.LocalAddr().String()) + pip = &pipe{ + ep: ep, + proxy: conn, + proxyAddr: connAddr, + } + go func() { + for { + var bs [1500]byte + n, ua, err := conn.ReadFromUDP(bs[:]) + if err != nil { + return // TODO: more noise + } + ip, ok := netaddr.FromStdIP(ua.IP) + if !ok { + // ??? + continue + } + if netaddr.IPPortFrom(ip, uint16(ua.Port)) != wgIP { + // Random noise that isn't kernel wg + continue + } + if err := p.conn.Send(bs[:n], ep); err != nil { + // Probably complain a bit + continue + } + } + }() + p.byKey[peer.Key] = pip + p.byEndpoint[ep] = pip + ret[peer.Key] = pip.proxyAddr + } + } + for key, pip := range p.byKey { + if _, ok := ret[key]; !ok { + pip.proxy.Close() + delete(p.byKey, key) + delete(p.byEndpoint, pip.ep) + } + } + return ret, nil +} + +type pipe struct { + ep conn.Endpoint + proxy net.Conn + proxyAddr netaddr.IPPort +} |
