1
0
mirror of https://github.com/matrix-org/pinecone.git synced 2026-10-24 11:59:18 +03:00

Add pineconeip for meshnet-lab testing

Squashed commit of the following:

commit 8fa2d4dbe76ffe20c49c5319b290c0a6543da6ae
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Thu May 13 14:47:37 2021 +0100

    Clear stale routing entries from previous ascending/descending nodes

commit b6394239e3
Merge: e41358c fce69f7
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Thu May 13 14:08:12 2021 +0100

    Merge branch 'main' into neilalexander/pineconeip

commit e41358c16a
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Wed May 12 17:24:19 2021 +0100

    Tweaks to TCP timeouts in pineconeip

commit 1870724388
Merge: 5b4be7a 103f27c
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Wed May 12 16:07:55 2021 +0100

    Merge branch 'main' into neilalexander/pineconeip

commit 5b4be7a27a
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Wed May 12 14:57:44 2021 +0100

    Fix pineconeip

commit 8fe3e14cdd
Merge: b6ba203 6c05ae4
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Wed May 12 14:14:15 2021 +0100

    Merge branch 'neilalexander/bootstrap' into neilalexander/pineconeip

commit b6ba2038e2
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Tue May 11 16:03:33 2021 +0100

    Reinstate mutex

commit a04f3f8a96
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Tue May 11 15:43:17 2021 +0100

    Ordering/dupe fixes, other tweaks

commit 932953dc4a
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date:   Tue May 11 13:43:14 2021 +0100

    Add pineconeip
This commit is contained in:
Neil Alexander
2021-05-14 12:02:53 +01:00
parent e4c793a3e3
commit fb4948bc62
11 changed files with 423 additions and 23 deletions

110
cmd/pineconeip/main.go Normal file
View File

@@ -0,0 +1,110 @@
// Copyright 2021 The Matrix.org Foundation C.I.C.
//
// 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 main
import (
"context"
"crypto/ed25519"
"flag"
"fmt"
"log"
"net"
"os"
"time"
"net/http"
_ "net/http/pprof"
"github.com/matrix-org/pinecone/cmd/pineconeip/tun"
"github.com/matrix-org/pinecone/multicast"
"github.com/matrix-org/pinecone/router"
)
func main() {
pk, sk, err := ed25519.GenerateKey(nil)
if err != nil {
panic(err)
}
dialer := net.Dialer{
Timeout: time.Second * 5,
KeepAlive: time.Second * 3,
}
listener := net.ListenConfig{
KeepAlive: time.Second * 3,
}
logger := log.New(os.Stdout, "", 0)
if hostPort := os.Getenv("PPROFLISTEN"); hostPort != "" {
logger.Println("Starting pprof on", hostPort)
go func() {
_ = http.ListenAndServe(hostPort, nil)
}()
}
pineconeRouter := router.NewRouter(logger, "router", sk, pk, nil)
pineconeMulticast := multicast.NewMulticast(logger, pineconeRouter)
pineconeMulticast.Start()
pineconeTUN, err := tun.NewTUN(pineconeRouter)
if err != nil {
panic(err)
}
_ = pineconeTUN
listen := flag.String("listen", "", "address to listen on")
connect := flag.String("connect", "", "peer to connect to")
flag.Parse()
if connect != nil && *connect != "" {
go func() {
conn, err := dialer.Dial("tcp", *connect)
if err != nil {
panic(err)
}
port, err := pineconeRouter.AuthenticatedConnect(conn, "", router.PeerTypeRemote)
if err != nil {
panic(err)
}
fmt.Println("Outbound connection", conn.RemoteAddr(), "is connected to port", port)
}()
}
go func() {
listener, err := listener.Listen(context.Background(), "tcp", *listen)
if err != nil {
panic(err)
}
fmt.Println("Listening on", listener.Addr())
for {
conn, err := listener.Accept()
if err != nil {
panic(err)
}
port, err := pineconeRouter.AuthenticatedConnect(conn, "", router.PeerTypeRemote)
if err != nil {
panic(err)
}
fmt.Println("Inbound connection", conn.RemoteAddr(), "is connected to port", port)
}
}()
select {}
}

115
cmd/pineconeip/tun/tun.go Normal file
View File

@@ -0,0 +1,115 @@
package tun
import (
"fmt"
"net"
"github.com/matrix-org/pinecone/router"
"github.com/matrix-org/pinecone/types"
wgtun "golang.zx2c4.com/wireguard/tun"
)
const TUN_OFFSET_BYTES = 4
type TUN struct {
r *router.Router
iface wgtun.Device
// partialToFull map[types.PublicKey]types.PublicKey
// mutex sync.RWMutex
}
/*
func (t *TUN) Lookup(partial types.PublicKey) types.PublicKey {
t.mutex.RLock()
pk, ok := t.partialToFull[partial]
t.mutex.RUnlock()
if ok {
return pk
}
full, addr, err := t.r.DHTSearch(context.Background(), partial[:], false)
if err != nil {
fmt.Println("DHT search failed:", err)
return types.PublicKey{}
}
fmt.Println("DHT search from", addr, "returned", full)
t.mutex.Lock()
t.partialToFull[partial] = full
t.mutex.Unlock()
return full
}
*/
func AddressForPublicKey(pk types.PublicKey) net.IP {
a := [16]byte{0xFD}
copy(a[1:], pk[:])
return a[:]
}
func PublicKeyForAddress(a net.IP) types.PublicKey {
if a[0] != 0xFD {
return types.PublicKey{}
}
pk := types.PublicKey{}
copy(pk[:], a[1:])
return pk
}
func NewTUN(r *router.Router) (*TUN, error) {
t := &TUN{
r: r,
// partialToFull: make(map[types.PublicKey]types.PublicKey),
}
addr := AddressForPublicKey(r.PublicKey())
if err := t.setup(addr); err != nil {
return nil, fmt.Errorf("t.setup: %w", err)
}
go t.read()
go t.write()
return t, nil
}
func (t *TUN) read() {
var buf [TUN_OFFSET_BYTES + 65536]byte
for {
n, err := t.iface.Read(buf[:], TUN_OFFSET_BYTES)
if n <= TUN_OFFSET_BYTES || err != nil {
fmt.Println("Error reading TUN:", err)
_ = t.iface.Flush()
continue
}
bs := buf[TUN_OFFSET_BYTES : TUN_OFFSET_BYTES+n]
if bs[0]&0xf0 != 0x60 {
continue
}
dst := net.IP(bs[24:40])
pk := PublicKeyForAddress(dst)
if dst[0] != 0xFD {
continue
}
ns, err := t.r.WriteTo(bs, pk)
if err != nil {
fmt.Println("t.r.WriteTo:", err)
continue
}
if ns < n {
fmt.Println("Wrote", ns, "bytes but should have wrote", n, "bytes")
continue
}
}
}
func (t *TUN) write() {
var buf [TUN_OFFSET_BYTES + 65536]byte
for {
n, _, err := t.r.ReadFrom(buf[TUN_OFFSET_BYTES:])
if err != nil {
fmt.Println("Error reading Pinecone:", err)
continue
}
_, err = t.iface.Write(buf[:TUN_OFFSET_BYTES+n], TUN_OFFSET_BYTES)
if err != nil {
fmt.Println("Error writing TUN:", err)
}
}
}

View File

@@ -0,0 +1,109 @@
package tun
import (
"encoding/binary"
"fmt"
"net"
"strconv"
"strings"
"unsafe"
"golang.org/x/sys/unix"
wgtun "golang.zx2c4.com/wireguard/tun"
)
// Configures the "utun" adapter with the correct IPv6 address and MTU.
func (tun *TUN) setup(addr net.IP) error {
iface, err := wgtun.CreateTUN("utun", 65000)
if err != nil {
panic(err)
}
tun.iface = iface
return tun.setupAddress(addr.String())
}
const (
darwin_SIOCAIFADDR_IN6 = 2155899162 // netinet6/in6_var.h
darwin_IN6_IFF_NODAD = 0x0020 // netinet6/in6_var.h
darwin_IN6_IFF_SECURED = 0x0400 // netinet6/in6_var.h
darwin_ND6_INFINITE_LIFETIME = 0xFFFFFFFF // netinet6/nd6.h
)
// nolint:structcheck
type in6_addrlifetime struct {
ia6t_expire float64 // nolint:unused
ia6t_preferred float64 // nolint:unused
ia6t_vltime uint32
ia6t_pltime uint32
}
// nolint:structcheck
type sockaddr_in6 struct {
sin6_len uint8
sin6_family uint8
sin6_port uint8 // nolint:unused
sin6_flowinfo uint32 // nolint:unused
sin6_addr [8]uint16
sin6_scope_id uint32 // nolint:unused
}
// nolint:structcheck
type in6_aliasreq struct {
ifra_name [16]byte
ifra_addr sockaddr_in6
ifra_dstaddr sockaddr_in6 // nolint:unused
ifra_prefixmask sockaddr_in6
ifra_flags uint32
ifra_lifetime in6_addrlifetime
}
// Sets the IPv6 address of the utun adapter. On Darwin/macOS this is done using
// a system socket and making direct syscalls to the kernel.
func (tun *TUN) setupAddress(addr string) error {
var fd int
var err error
if fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil {
return fmt.Errorf("unix.Socket: %w", err)
}
ifname, err := tun.iface.Name()
if err != nil {
return fmt.Errorf("tun.iface.Name: %w", err)
}
var ar in6_aliasreq
copy(ar.ifra_name[:], []byte(ifname))
ar.ifra_prefixmask.sin6_len = uint8(unsafe.Sizeof(ar.ifra_prefixmask))
b := make([]byte, 16)
binary.LittleEndian.PutUint16(b, uint16(0xFE00))
ar.ifra_prefixmask.sin6_addr[0] = uint16(binary.BigEndian.Uint16(b))
ar.ifra_addr.sin6_len = uint8(unsafe.Sizeof(ar.ifra_addr))
ar.ifra_addr.sin6_family = unix.AF_INET6
parts := strings.Split(strings.Split(addr, "/")[0], ":")
for i := 0; i < 8; i++ {
addr, _ := strconv.ParseUint(parts[i], 16, 16)
b := make([]byte, 16)
binary.LittleEndian.PutUint16(b, uint16(addr))
ar.ifra_addr.sin6_addr[i] = uint16(binary.BigEndian.Uint16(b))
}
ar.ifra_flags |= darwin_IN6_IFF_NODAD
ar.ifra_flags |= darwin_IN6_IFF_SECURED
ar.ifra_lifetime.ia6t_vltime = darwin_ND6_INFINITE_LIFETIME
ar.ifra_lifetime.ia6t_pltime = darwin_ND6_INFINITE_LIFETIME
fmt.Println("Interface name:", ifname)
fmt.Println("Interface address:", addr)
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(darwin_SIOCAIFADDR_IN6), uintptr(unsafe.Pointer(&ar))); errno != 0 {
err = errno
return fmt.Errorf("darwin_SIOCAIFADDR_IN6: %w", err)
}
return err
}

View File

@@ -0,0 +1,42 @@
package tun
import (
"fmt"
"net"
"github.com/vishvananda/netlink"
wgtun "golang.zx2c4.com/wireguard/tun"
)
func (tun *TUN) setup(addr net.IP) error {
iface, err := wgtun.CreateTUN("\000", 65000)
if err != nil {
panic(err)
}
tun.iface = iface
return tun.setupAddress(addr.String())
}
func (tun *TUN) setupAddress(addr string) error {
nladdr, err := netlink.ParseAddr(addr + "/8")
if err != nil {
return err
}
ifname, err := tun.iface.Name()
if err != nil {
return err
}
nlintf, err := netlink.LinkByName(ifname)
if err != nil {
return err
}
if err := netlink.AddrAdd(nlintf, nladdr); err != nil {
return err
}
if err := netlink.LinkSetUp(nlintf); err != nil {
return err
}
fmt.Println("Interface name:", ifname)
fmt.Println("Interface address:", addr)
return nil
}

View File

@@ -39,7 +39,7 @@ import (
func main() {
go func() {
_ = http.ListenAndServe(":65432", nil)
panic(http.ListenAndServe(":65432", nil))
}()
filename := flag.String("filename", "cmd/pineconesim/graphs/sim.txt", "the file that describes the simulated topology")

4
go.mod
View File

@@ -8,9 +8,11 @@ require (
github.com/kr/text v0.2.0 // indirect
github.com/neilalexander/utp v0.1.1-0.20210510143443-c1bac1cd577f
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/vishvananda/netlink v1.1.0 // indirect
go.uber.org/atomic v1.7.0
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169
golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
)

16
go.sum
View File

@@ -66,17 +66,33 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg=
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169 h1:fpeMGRM6A+XFcw4RPCO8s8hH7ppgrGR22pSIjwM7YUI=
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec h1:WIOBdN6Hrv84Iy+IRHHX8+fFBasdh9GX8FJlpOHNJ2I=
golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=

View File

@@ -85,10 +85,10 @@ func (r *Router) reader(conn net.Conn) {
case types.TypeVirtualSnake:
// If the frame doesn't appear as if it's meant to be for
// us then we'll drop it.
if !frame.DestinationKey.EqualTo(r.PublicKey()) {
/*if !frame.DestinationKey.EqualTo(r.PublicKey()) {
r.log.Println("Router received frame that isn't for us")
continue
}
}*/
r.recv <- frame
case types.TypeSource:

View File

@@ -318,6 +318,9 @@ func (t *virtualSnake) getVirtualSnakeNextHop(from *Peer, destKey types.PublicKe
newCandidate(peerKey, peer.port)
}
}
if canlength-PortCount == 0 {
return types.SwitchPorts{0}
}
return candidates[canlength:]
}

View File

@@ -276,8 +276,10 @@ func (p *Peer) reader() {
if !dest.started.Load() || (dest.port != 0 && !dest.alive.Load()) {
continue
}
if p.port == dest.port || p.public.EqualTo(dest.public) {
continue
if p.port != 0 && dest.port != 0 {
if p.port == dest.port || p.public.EqualTo(dest.public) {
continue
}
}
switch frame.Type {
case types.TypePathfind, types.TypeVirtualSnakePathfind:

View File

@@ -37,6 +37,24 @@ func GetFrame() *Frame {
return frame
}
func (f *Frame) Borrow() *Frame {
f.refs.Inc()
return f
}
func (f *Frame) Done() bool {
refs := f.refs.Dec()
if refs < 0 {
panic("invalid Done call")
}
if refs == 0 {
f.Reset()
framePool.Put(f)
return true
}
return false
}
type FrameVersion uint8
type FrameType uint8
@@ -88,23 +106,6 @@ func (f *Frame) Copy() *Frame {
return &copy
}
func (f *Frame) Borrow() *Frame {
f.refs.Inc()
return f
}
func (f *Frame) Done() bool {
refs := f.refs.Dec()
if refs < 0 {
panic("invalid Done call")
}
if refs == 0 {
framePool.Put(f)
return true
}
return false
}
func (f *Frame) MarshalBinary(buffer []byte) (int, error) {
copy(buffer[:4], FrameMagicBytes)
buffer[4], buffer[5] = byte(f.Version), byte(f.Type)