├── .gitignore ├── debug.go ├── Makefile ├── proto_gen.sh ├── scripts ├── generate_node.sh ├── generate_ca.sh └── sign_node.sh ├── go.mod ├── vif.go ├── config.example.json ├── viftun.go ├── protocol ├── protocol.proto ├── protocol_grpc.pb.go └── protocol.pb.go ├── LICENSE ├── route.go ├── cmd ├── vmeshd │ └── main.go └── vnconfigsign │ └── main.go ├── README.md ├── vifservice.go ├── go.sum ├── peer.go └── node.go /.gitignore: -------------------------------------------------------------------------------- 1 | /play/ 2 | /vmeshd 3 | /vnconfigsign 4 | -------------------------------------------------------------------------------- /debug.go: -------------------------------------------------------------------------------- 1 | package vmesh 2 | 3 | var EnableDebug bool = false 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | go build ./cmd/vmeshd 3 | go build ./cmd/vnconfigsign 4 | 5 | .PHONY: all 6 | -------------------------------------------------------------------------------- /proto_gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | protoc --go_out=. --go_opt=paths=source_relative \ 4 | --go-grpc_out=. --go-grpc_opt=paths=source_relative \ 5 | protocol/protocol.proto 6 | -------------------------------------------------------------------------------- /scripts/generate_node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$1" ]; then 4 | echo "Output name needed" 5 | exit 1 6 | fi 7 | 8 | openssl genpkey -algorithm ed25519 -out "$1.key" 9 | openssl req -new -key "$1.key" -out "$1.csr" 10 | -------------------------------------------------------------------------------- /scripts/generate_ca.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$1" ]; then 4 | echo "Output name needed" 5 | exit 1 6 | fi 7 | 8 | openssl genpkey -algorithm ed25519 -out "$1.key" 9 | openssl req -new -x509 -key "$1.key" -out "$1.crt" -days 3650 10 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/losfair/vmesh 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/golang/protobuf v1.5.2 7 | github.com/google/gopacket v1.1.19 8 | github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 9 | google.golang.org/grpc v1.37.1 10 | google.golang.org/protobuf v1.26.0 11 | ) 12 | -------------------------------------------------------------------------------- /vif.go: -------------------------------------------------------------------------------- 1 | package vmesh 2 | 3 | type Vif interface { 4 | GetName() string 5 | Send([]byte) (int, error) 6 | Recv([]byte) (int, error) 7 | } 8 | 9 | type DummyVif struct{} 10 | 11 | func (*DummyVif) GetName() string { 12 | return "(dummy)" 13 | } 14 | 15 | func (*DummyVif) Send(data []byte) (int, error) { 16 | return len(data), nil 17 | } 18 | 19 | func (*DummyVif) Recv(data []byte) (int, error) { 20 | select {} 21 | } 22 | -------------------------------------------------------------------------------- /config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "listen_addr": "0.0.0.0:5120", 3 | "ca": "/your_ca/ca.crt", 4 | "cert": "/your_node/A.crt", 5 | "private_key": "/your_node/A.key", 6 | "server_name": "node1.test.example.com", 7 | "local_announcements": [ 8 | "2001:db8::/32" 9 | ], 10 | "peers": [ 11 | { 12 | "addr": "8.8.8.8:5120", 13 | "name": "node2.test.example.com" 14 | } 15 | ], 16 | "vif_type": "tun", 17 | "vif_name": "tun-vnet" 18 | } 19 | -------------------------------------------------------------------------------- /scripts/sign_node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -z "$1" ]; then 4 | echo "CA name needed" 5 | exit 1 6 | fi 7 | 8 | if [ -z "$2" ]; then 9 | echo "Node CSR path needed" 10 | exit 1 11 | fi 12 | 13 | if [ -z "$3" ]; then 14 | echo "Output path needed" 15 | exit 1 16 | fi 17 | 18 | CA_PATH=$(readlink -f "$1") 19 | CSR_PATH=$(readlink -f "$2") 20 | OUT_PATH=$(readlink -f "$3") 21 | 22 | cd $(dirname $1) 23 | 24 | openssl x509 -req -in "$CSR_PATH" -CA "$CA_PATH.crt" -CAkey "$CA_PATH.key" -CAcreateserial -out "$OUT_PATH" -days 365 25 | -------------------------------------------------------------------------------- /viftun.go: -------------------------------------------------------------------------------- 1 | package vmesh 2 | 3 | import ( 4 | "github.com/songgao/water" 5 | "log" 6 | ) 7 | 8 | type Tun struct { 9 | ifce *water.Interface 10 | } 11 | 12 | func NewTun(name string) (*Tun, error) { 13 | ifce, err := water.New(water.Config{ 14 | DeviceType: water.TUN, 15 | PlatformSpecificParams: water.PlatformSpecificParams{Name: name}, 16 | }) 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | log.Println("Created TUN interface:", ifce.Name()) 22 | 23 | return &Tun{ 24 | ifce: ifce, 25 | }, nil 26 | } 27 | 28 | func (t *Tun) GetName() string { 29 | return t.ifce.Name() 30 | } 31 | 32 | func (t *Tun) Send(data []byte) (int, error) { 33 | return t.ifce.Write(data) 34 | } 35 | 36 | func (t *Tun) Recv(data []byte) (int, error) { 37 | return t.ifce.Read(data) 38 | } 39 | -------------------------------------------------------------------------------- /protocol/protocol.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option go_package = "github.com/losfair/vmesh/protocol"; 3 | 4 | service VnetPeer { 5 | rpc Input(stream Message) returns (stream Message) {} 6 | } 7 | 8 | message Message { 9 | uint32 tag = 1; 10 | bytes payload = 2; 11 | } 12 | 13 | message Announcement { 14 | repeated Route routes = 1; 15 | } 16 | 17 | message Route { 18 | bytes prefix = 1; 19 | uint32 prefix_length = 2; 20 | repeated Hop path = 3; 21 | } 22 | 23 | message Hop { 24 | bytes id = 1; 25 | uint32 latency = 2; 26 | } 27 | 28 | message DistributedConfig { 29 | uint32 version = 1; 30 | bytes certificate = 2; 31 | bytes content = 3; 32 | } 33 | 34 | enum ChannelType { 35 | UDP = 0; 36 | } 37 | 38 | message ChannelRequest { 39 | ChannelType type = 1; 40 | bytes token = 2; 41 | } 42 | 43 | message ChannelResponse { 44 | ChannelType type = 1; 45 | bytes token = 2; 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Heyang Zhou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /route.go: -------------------------------------------------------------------------------- 1 | package vmesh 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "sync" 7 | ) 8 | 9 | type LikeRoutingTable struct { 10 | Routes [129]sync.Map // prefix_len -> (IPV6 Address ([16]byte) -> interface{}) 11 | } 12 | 13 | func (r *LikeRoutingTable) Range(callback func([16]byte, uint8, interface{}) bool) { 14 | for i := 128; i >= 0; i-- { 15 | cont := true 16 | r.Routes[i].Range(func(addr, value interface{}) bool { 17 | cont = callback(addr.([16]byte), uint8(i), value) 18 | return cont 19 | }) 20 | if !cont { 21 | return 22 | } 23 | } 24 | } 25 | 26 | func (r *LikeRoutingTable) Lookup(prefix [16]byte, prefixLen uint8, callback func(prefix [16]byte, prefixLen uint8, value interface{}) bool) error { 27 | if prefixLen > 128 { 28 | return errors.New("invalid prefix length") 29 | } 30 | 31 | for i := int(prefixLen); i >= 0; i-- { 32 | if i != 128 { 33 | prefix[i/8] &= 0xff << uint32(8-i%8) 34 | } 35 | if rt, ok := r.Routes[i].Load(prefix); ok { 36 | if !callback(prefix, uint8(i), rt) { 37 | return nil 38 | } 39 | } 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func (r *LikeRoutingTable) Delete(prefix [16]byte, prefixLen uint8) { 46 | if prefixLen > 128 { 47 | return 48 | } 49 | 50 | for i := 127; i >= int(prefixLen); i-- { 51 | prefix[i/8] &= 0xff << uint32(8-i%8) 52 | } 53 | 54 | r.Routes[int(prefixLen)].Delete(prefix) 55 | } 56 | 57 | func (r *LikeRoutingTable) Insert(prefix [16]byte, prefixLen uint8, value interface{}) error { 58 | if prefixLen > 128 { 59 | return errors.New("invalid prefix length") 60 | } 61 | 62 | for i := 127; i >= int(prefixLen); i-- { 63 | prefix[i/8] &= 0xff << uint32(8-i%8) 64 | } 65 | 66 | r.Routes[int(prefixLen)].Store(prefix, value) 67 | return nil 68 | } 69 | 70 | func (r *LikeRoutingTable) InsertCIDR(repr string, value interface{}) error { 71 | _, ipnet, err := net.ParseCIDR(repr) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | if len(ipnet.IP) != 16 { 77 | return errors.New("only ipv6 networks are supported") 78 | } 79 | 80 | prefixLen, _ := ipnet.Mask.Size() 81 | var prefix [16]byte 82 | copy(prefix[:], ipnet.IP) 83 | return r.Insert(prefix, uint8(prefixLen), value) 84 | } 85 | -------------------------------------------------------------------------------- /cmd/vmeshd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "flag" 6 | "github.com/golang/protobuf/proto" 7 | "github.com/losfair/vmesh" 8 | "github.com/losfair/vmesh/protocol" 9 | "io/ioutil" 10 | "log" 11 | "syscall" 12 | "time" 13 | ) 14 | 15 | func main() { 16 | configPathFlag := flag.String("config", "config.json", "Path to configuration") 17 | debugFlag := flag.Bool("debug", false, "Enable debug logging") 18 | tableFlag := flag.String("table", "", "Path to periodically dump the routing table to") 19 | dropPermissionsFlag := flag.Bool("drop-permissions", false, "Drop permissions from root to nobody") 20 | initialDCFlag := flag.String("initial-dc", "", "Path to initial distributed config") 21 | flag.Parse() 22 | 23 | var config vmesh.NodeConfig 24 | 25 | configRaw, err := ioutil.ReadFile(*configPathFlag) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | if err := json.Unmarshal(configRaw, &config); err != nil { 30 | log.Fatal(err) 31 | } 32 | 33 | vmesh.EnableDebug = *debugFlag 34 | 35 | node, err := vmesh.NewNode(&config) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | 40 | // Drop permissions after NewNode() which may initialize the tun device 41 | if *dropPermissionsFlag { 42 | if err := syscall.Setgid(65534); err != nil { 43 | log.Fatalln("setgid failed:", err) 44 | } 45 | if err := syscall.Setuid(65534); err != nil { 46 | log.Fatalln("setuid failed:", err) 47 | } 48 | } 49 | 50 | if len(*tableFlag) > 0 { 51 | go func() { 52 | for { 53 | data := node.BuildPrintableRoutingTable() 54 | _ = ioutil.WriteFile(*tableFlag, []byte(data), 0644) 55 | time.Sleep(10 * time.Second) 56 | } 57 | }() 58 | } 59 | 60 | if len(*initialDCFlag) > 0 { 61 | dcRaw, err := ioutil.ReadFile(*initialDCFlag) 62 | if err != nil { 63 | log.Println("Warning: Unable to read initial distributed config") 64 | } else { 65 | var dc protocol.DistributedConfig 66 | if err := proto.Unmarshal(dcRaw, &dc); err != nil { 67 | log.Println("Warning: Unable to parse initial distributed config") 68 | } else { 69 | if err := node.UpdateDistributedConfig(&dc); err != nil { 70 | log.Println("Failed to apply initial distributed config:", err) 71 | } 72 | } 73 | } 74 | } 75 | 76 | node.ConnectToAllPeers() 77 | 78 | err = node.Run() 79 | log.Fatal(err) 80 | } 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vmesh 2 | 3 | ### Introduction 4 | 5 | VMesh is a decentralized Layer 3 mesh router and protocol designed for open network interconnection. 6 | 7 | It securely handles everything you'll need to interconnect your globally distributed 8 | nodes or peer with other networks: packet routing, route announcement, authentication, 9 | distributed configuration management, prefix filtering, and more. 10 | 11 | VMesh supports only IPv6 in the routed network. 12 | 13 | ### Getting started 14 | 15 | Knowledge of routing protocols such as [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) 16 | would help a lot in understanding how VMesh works. 17 | 18 | Take a look at `config.example.json` and `scripts/` to get an idea about the detailed usage. 19 | 20 | Usually you need a globally routable IPv6 block to make full use of VMesh, but you can also 21 | request IPv6 prefix allocation and transit from an existing VMesh network through peering. 22 | (See [Peering](#peering), [Interconnect with AS209291](#as209291)) 23 | 24 | Detailed documentation is still TBD. 25 | 26 | ### Peering 27 | 28 | Specify `"external_peer_certs": ["/path/to/your/peers/cert.crt"]` in your `config.json` to 29 | allow interconnection with a node with a certificate outside your PKI tree. It's advised to 30 | prefix-filter announcements from external peers - see the "Distributed config" section for 31 | how to do that. 32 | 33 | ### Distributed config 34 | 35 | Use the `vnconfigsign` tool to sign your distributed configuration in JSON format and produce a 36 | `.bin`. Then start any one node with the `-initial-dc your_signed_config.bin` option to sync 37 | the configuration with the rest of your network. As long as any single node on your network 38 | is alive with a latest version of the distributed configuration, all directly/indirectly 39 | connected nodes will eventually be in sync. 40 | 41 | The JSON format distributed config should look like: 42 | 43 | ```json 44 | { 45 | "prefix_whitelist": { 46 | "a.vnet.example.com": [ 47 | "2001:db8:1000::/48,max_prefix_len=64", 48 | "64:ff9b::/96,max_prefix_len=96" 49 | ], 50 | "b.vnet.example.com": [ 51 | "2001:db8:2000::/48" 52 | ] 53 | } 54 | } 55 | ``` 56 | 57 | ### Interconnect with AS209291 58 | 59 | VMesh is deployed on my network (AS209291) and is handling most internal traffic among nodes in 60 | the globally distributed network. 61 | 62 | Email me at `me@connected.direct` if you want to peer. -------------------------------------------------------------------------------- /cmd/vnconfigsign/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "crypto/sha256" 8 | "crypto/tls" 9 | "crypto/x509" 10 | "encoding/hex" 11 | "flag" 12 | "fmt" 13 | "github.com/golang/protobuf/proto" 14 | "github.com/losfair/vmesh/protocol" 15 | "io/ioutil" 16 | "log" 17 | "math/big" 18 | "net/url" 19 | "path" 20 | "time" 21 | ) 22 | 23 | func main() { 24 | caCertPath := flag.String("ca-cert", "", "Path to CA certificate") 25 | caKeyPath := flag.String("ca-key", "", "Path to CA private key") 26 | configFilePath := flag.String("config", "", "Path to config file") 27 | outDir := flag.String("out-dir", "distributed-config", "Output directory") 28 | flag.Parse() 29 | 30 | configRaw, err := ioutil.ReadFile(*configFilePath) 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | 35 | caKeypair, err := tls.LoadX509KeyPair(*caCertPath, *caKeyPath) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | caCert, err := x509.ParseCertificate(caKeypair.Certificate[0]) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | 44 | configHash := sha256.Sum256(configRaw) 45 | configUrl, err := url.Parse("vnet-conf://" + hex.EncodeToString(configHash[:])) 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | 50 | currentTime := time.Now().UTC() 51 | 52 | cert := &x509.Certificate{ 53 | SerialNumber: big.NewInt(0), 54 | NotBefore: currentTime, 55 | NotAfter: currentTime.AddDate(1, 0, 0), 56 | KeyUsage: x509.KeyUsageDigitalSignature, 57 | URIs: []*url.URL{configUrl}, 58 | } 59 | priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 60 | if err != nil { 61 | log.Fatal(err) 62 | } 63 | pub := &priv.PublicKey 64 | 65 | signedCert, err := x509.CreateCertificate(rand.Reader, cert, caCert, pub, caKeypair.PrivateKey) 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | 70 | output := &protocol.DistributedConfig{ 71 | Version: 1, 72 | Certificate: signedCert, 73 | Content: configRaw, 74 | } 75 | outputRaw, err := proto.Marshal(output) 76 | if err != nil { 77 | log.Fatal(err) 78 | } 79 | 80 | outputName := fmt.Sprintf( 81 | "dconf-%d-%02d-%02d-%02d-%02d-%02d.bin", 82 | currentTime.Year(), currentTime.Month(), currentTime.Day(), 83 | currentTime.Hour(), currentTime.Minute(), currentTime.Second(), 84 | ) 85 | 86 | err = ioutil.WriteFile(path.Join(*outDir, outputName), outputRaw, 0644) 87 | if err != nil { 88 | log.Fatal(err) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /vifservice.go: -------------------------------------------------------------------------------- 1 | package vmesh 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "log" 9 | "net" 10 | "os" 11 | "sync" 12 | "sync/atomic" 13 | "time" 14 | ) 15 | 16 | type BackingService struct { 17 | id [16]byte 18 | name string 19 | network string 20 | address string 21 | 22 | mu sync.Mutex 23 | conn net.Conn 24 | lastReconnect time.Time 25 | reconnectionInProgress uint32 // atomic 26 | } 27 | 28 | func NewBackingService(name string, network, address string) (*BackingService, error) { 29 | switch network { 30 | case "unixgram": 31 | default: 32 | return nil, errors.New("unsupported network type") 33 | } 34 | 35 | var id [16]byte 36 | if _, err := rand.Read(id[:]); err != nil { 37 | return nil, err 38 | } 39 | 40 | return &BackingService{ 41 | id: id, 42 | name: name, 43 | network: network, 44 | address: address, 45 | }, nil 46 | } 47 | 48 | func (s *BackingService) GetName() string { 49 | return s.name 50 | } 51 | 52 | func (s *BackingService) Send(data []byte) (int, error) { 53 | s.mu.Lock() 54 | defer s.mu.Unlock() 55 | 56 | if s.conn != nil { 57 | if _, err := s.conn.Write(data); err != nil { 58 | log.Println("Failed to send packet to backing service:", err) 59 | } else { 60 | return len(data), nil 61 | } 62 | } else { 63 | log.Println("No connection. Triggering reconnect.") 64 | } 65 | 66 | s.triggerReconnect() 67 | return 0, errors.New("dead connection to the backing service, trying to reconnect") 68 | } 69 | 70 | func (s *BackingService) triggerReconnect() { 71 | current := time.Now() 72 | if current.Before(s.lastReconnect) || current.Sub(s.lastReconnect) > 1*time.Second { 73 | s.lastReconnect = current 74 | go s.doReconnect() 75 | } 76 | } 77 | 78 | func (s *BackingService) doReconnect() { 79 | // Ensure that at most one doReconnect() is running. 80 | if !atomic.CompareAndSwapUint32(&s.reconnectionInProgress, 0, 1) { 81 | return 82 | } 83 | defer atomic.StoreUint32(&s.reconnectionInProgress, 0) 84 | 85 | switch s.network { 86 | case "unixgram": 87 | if addr, err := net.ResolveUnixAddr(s.network, s.address); err != nil { 88 | //log.Println("Failed to resolve unix address:", err) 89 | } else { 90 | s.mu.Lock() 91 | if s.conn != nil { 92 | s.conn.Close() 93 | s.conn = nil 94 | } 95 | s.mu.Unlock() 96 | 97 | path := fmt.Sprintf("/tmp/vmesh_service_%s.sock", hex.EncodeToString(s.id[:])) 98 | _ = os.Remove(path) 99 | laddr, err := net.ResolveUnixAddr("unixgram", path) 100 | if err != nil { 101 | log.Println("Unable to resolve laddr") 102 | return 103 | } 104 | if conn, err := net.DialUnix(s.network, laddr, addr); err != nil { 105 | log.Println("Failed to dial unix socket:", err) 106 | } else { 107 | s.mu.Lock() 108 | s.conn = conn 109 | s.mu.Unlock() 110 | log.Println("Connection to unixgram socket", s.address, "established") 111 | } 112 | } 113 | default: 114 | return 115 | } 116 | } 117 | 118 | func (s *BackingService) Recv(data []byte) (int, error) { 119 | s.mu.Lock() 120 | conn := s.conn 121 | s.mu.Unlock() 122 | 123 | if conn != nil { 124 | if n, err := conn.Read(data); err == nil { 125 | return n, nil 126 | } 127 | } 128 | 129 | s.mu.Lock() 130 | s.triggerReconnect() 131 | s.mu.Unlock() 132 | 133 | return 0, errors.New("dead connection to the backing service, trying to reconnect") 134 | } 135 | -------------------------------------------------------------------------------- /protocol/protocol_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | 3 | package protocol 4 | 5 | import ( 6 | context "context" 7 | grpc "google.golang.org/grpc" 8 | codes "google.golang.org/grpc/codes" 9 | status "google.golang.org/grpc/status" 10 | ) 11 | 12 | // This is a compile-time assertion to ensure that this generated file 13 | // is compatible with the grpc package it is being compiled against. 14 | // Requires gRPC-Go v1.32.0 or later. 15 | const _ = grpc.SupportPackageIsVersion7 16 | 17 | // VnetPeerClient is the client API for VnetPeer service. 18 | // 19 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 20 | type VnetPeerClient interface { 21 | Input(ctx context.Context, opts ...grpc.CallOption) (VnetPeer_InputClient, error) 22 | } 23 | 24 | type vnetPeerClient struct { 25 | cc grpc.ClientConnInterface 26 | } 27 | 28 | func NewVnetPeerClient(cc grpc.ClientConnInterface) VnetPeerClient { 29 | return &vnetPeerClient{cc} 30 | } 31 | 32 | func (c *vnetPeerClient) Input(ctx context.Context, opts ...grpc.CallOption) (VnetPeer_InputClient, error) { 33 | stream, err := c.cc.NewStream(ctx, &VnetPeer_ServiceDesc.Streams[0], "/VnetPeer/Input", opts...) 34 | if err != nil { 35 | return nil, err 36 | } 37 | x := &vnetPeerInputClient{stream} 38 | return x, nil 39 | } 40 | 41 | type VnetPeer_InputClient interface { 42 | Send(*Message) error 43 | Recv() (*Message, error) 44 | grpc.ClientStream 45 | } 46 | 47 | type vnetPeerInputClient struct { 48 | grpc.ClientStream 49 | } 50 | 51 | func (x *vnetPeerInputClient) Send(m *Message) error { 52 | return x.ClientStream.SendMsg(m) 53 | } 54 | 55 | func (x *vnetPeerInputClient) Recv() (*Message, error) { 56 | m := new(Message) 57 | if err := x.ClientStream.RecvMsg(m); err != nil { 58 | return nil, err 59 | } 60 | return m, nil 61 | } 62 | 63 | // VnetPeerServer is the server API for VnetPeer service. 64 | // All implementations must embed UnimplementedVnetPeerServer 65 | // for forward compatibility 66 | type VnetPeerServer interface { 67 | Input(VnetPeer_InputServer) error 68 | mustEmbedUnimplementedVnetPeerServer() 69 | } 70 | 71 | // UnimplementedVnetPeerServer must be embedded to have forward compatible implementations. 72 | type UnimplementedVnetPeerServer struct { 73 | } 74 | 75 | func (UnimplementedVnetPeerServer) Input(VnetPeer_InputServer) error { 76 | return status.Errorf(codes.Unimplemented, "method Input not implemented") 77 | } 78 | func (UnimplementedVnetPeerServer) mustEmbedUnimplementedVnetPeerServer() {} 79 | 80 | // UnsafeVnetPeerServer may be embedded to opt out of forward compatibility for this service. 81 | // Use of this interface is not recommended, as added methods to VnetPeerServer will 82 | // result in compilation errors. 83 | type UnsafeVnetPeerServer interface { 84 | mustEmbedUnimplementedVnetPeerServer() 85 | } 86 | 87 | func RegisterVnetPeerServer(s grpc.ServiceRegistrar, srv VnetPeerServer) { 88 | s.RegisterService(&VnetPeer_ServiceDesc, srv) 89 | } 90 | 91 | func _VnetPeer_Input_Handler(srv interface{}, stream grpc.ServerStream) error { 92 | return srv.(VnetPeerServer).Input(&vnetPeerInputServer{stream}) 93 | } 94 | 95 | type VnetPeer_InputServer interface { 96 | Send(*Message) error 97 | Recv() (*Message, error) 98 | grpc.ServerStream 99 | } 100 | 101 | type vnetPeerInputServer struct { 102 | grpc.ServerStream 103 | } 104 | 105 | func (x *vnetPeerInputServer) Send(m *Message) error { 106 | return x.ServerStream.SendMsg(m) 107 | } 108 | 109 | func (x *vnetPeerInputServer) Recv() (*Message, error) { 110 | m := new(Message) 111 | if err := x.ServerStream.RecvMsg(m); err != nil { 112 | return nil, err 113 | } 114 | return m, nil 115 | } 116 | 117 | // VnetPeer_ServiceDesc is the grpc.ServiceDesc for VnetPeer service. 118 | // It's only intended for direct use with grpc.RegisterService, 119 | // and not to be introspected or modified (even as a copy) 120 | var VnetPeer_ServiceDesc = grpc.ServiceDesc{ 121 | ServiceName: "VnetPeer", 122 | HandlerType: (*VnetPeerServer)(nil), 123 | Methods: []grpc.MethodDesc{}, 124 | Streams: []grpc.StreamDesc{ 125 | { 126 | StreamName: "Input", 127 | Handler: _VnetPeer_Input_Handler, 128 | ServerStreams: true, 129 | ClientStreams: true, 130 | }, 131 | }, 132 | Metadata: "protocol/protocol.proto", 133 | } 134 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 4 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 5 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 8 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 9 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 10 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 11 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 12 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 13 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 14 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 15 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 16 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 17 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 18 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 19 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 20 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 21 | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= 22 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 23 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 24 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 25 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 26 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 27 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 28 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 29 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 30 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 31 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 32 | github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= 33 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 34 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 35 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 36 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 37 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 38 | github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= 39 | github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= 40 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 41 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 42 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 43 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 44 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 45 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 46 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 47 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 48 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 49 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 50 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 51 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 52 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 53 | golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= 54 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 55 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 56 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= 57 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 58 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 59 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 60 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 62 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 63 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= 64 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 65 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= 66 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 67 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 68 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 69 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 70 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 71 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 72 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 73 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 74 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 75 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 76 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 77 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 78 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 79 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 80 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 81 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 82 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 83 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 84 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 85 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 86 | google.golang.org/grpc v1.37.1 h1:ARnQJNWxGyYJpdf/JXscNlQr/uv607ZPU9Z7ogHi+iI= 87 | google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 88 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 89 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 90 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 91 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 92 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 93 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 94 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 95 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 96 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 97 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 98 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 99 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 100 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 101 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 102 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 103 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 104 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 105 | -------------------------------------------------------------------------------- /peer.go: -------------------------------------------------------------------------------- 1 | package vmesh 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/x509" 7 | "errors" 8 | "log" 9 | "math" 10 | "net" 11 | "sync" 12 | "time" 13 | 14 | "github.com/losfair/vmesh/protocol" 15 | "google.golang.org/protobuf/proto" 16 | ) 17 | 18 | type MessageTag uint32 19 | 20 | const ( 21 | MessageTag_Invalid MessageTag = iota 22 | MessageTag_IP 23 | MessageTag_Announce 24 | MessageTag_Ping 25 | MessageTag_Pong 26 | MessageTag_UpdateDistributedConfig 27 | 28 | MessageTag_ChannelRequest 29 | MessageTag_ChannelResponse 30 | ) 31 | 32 | type PeerID [32]byte 33 | 34 | const LatencySampleSize = 10 35 | 36 | type Peer struct { 37 | Node *Node 38 | LocalCert *x509.Certificate 39 | LocalID PeerID 40 | RemoteCert *x509.Certificate 41 | RemoteID PeerID 42 | RemoteName string 43 | Out chan<- *protocol.Message 44 | 45 | stop chan struct{} 46 | 47 | latencyMeasurement LatencyMeasurementState 48 | latencyResult LatencyMeasurementResult 49 | 50 | channelKey [32]byte 51 | 52 | udp UDPChannel 53 | } 54 | 55 | type LatencyMeasurementResult struct { 56 | mu sync.RWMutex 57 | 58 | latencyLog [LatencySampleSize]uint32 59 | latencyFillCount int 60 | latencyLogIndex int 61 | } 62 | 63 | type UDPChannel struct { 64 | mu sync.Mutex 65 | peerToken [32]byte 66 | peerAddr *net.UDPAddr 67 | peerUpdateTime time.Time 68 | } 69 | 70 | type LatencyMeasurementState struct { 71 | sync.Mutex 72 | inProgress bool 73 | measureStart time.Time 74 | } 75 | 76 | func (p *Peer) GetLatencyMs() uint32 { 77 | p.latencyResult.mu.RLock() 78 | defer p.latencyResult.mu.RUnlock() 79 | 80 | // We haven't got any latency information yet 81 | if p.latencyResult.latencyFillCount == 0 { 82 | return math.MaxUint32 83 | } 84 | 85 | var total uint64 86 | for i := 0; i < p.latencyResult.latencyFillCount; i++ { 87 | total += uint64(p.latencyResult.latencyLog[i]) 88 | } 89 | return uint32(total / uint64(p.latencyResult.latencyFillCount)) 90 | } 91 | 92 | func (p *Peer) PushLatencyLog(ms uint32) { 93 | p.latencyResult.mu.Lock() 94 | if p.latencyResult.latencyFillCount < LatencySampleSize { 95 | p.latencyResult.latencyFillCount += 1 96 | } 97 | p.latencyResult.latencyLog[p.latencyResult.latencyLogIndex] = ms 98 | p.latencyResult.latencyLogIndex = (p.latencyResult.latencyLogIndex + 1) % LatencySampleSize 99 | p.latencyResult.mu.Unlock() 100 | } 101 | 102 | func (p *Peer) HandleMessage(msg *protocol.Message) error { 103 | tag := MessageTag(msg.Tag) 104 | 105 | switch tag { 106 | case MessageTag_IP: 107 | if err := p.Node.DispatchIPPacket(msg.Payload); err != nil { 108 | if EnableDebug { 109 | log.Println("DispatchIPPacket error:", err) 110 | } 111 | } 112 | return nil 113 | case MessageTag_Announce: 114 | var payload protocol.Announcement 115 | if err := proto.Unmarshal(msg.Payload, &payload); err != nil { 116 | return errors.New("cannot unmarshal payload for Announce") 117 | } 118 | if len(payload.Routes) > 65536 { 119 | return errors.New("too many routes from a single peer") 120 | } 121 | 122 | for _, rt := range payload.Routes { 123 | var totalLatency uint64 124 | 125 | if len(rt.Prefix) != 16 || rt.PrefixLength > 128 { 126 | return errors.New("invalid prefix") 127 | } 128 | 129 | var prefix [16]byte 130 | copy(prefix[:], rt.Prefix) 131 | 132 | if !p.Node.DCState.PrefixIsWhitelisted(p.RemoteName, prefix, uint8(rt.PrefixLength)) { 133 | // Explicitly not whitelisted 134 | continue 135 | } 136 | 137 | if len(rt.Path) == 0 || !bytes.Equal(rt.Path[0].Id, p.RemoteID[:]) { 138 | return errors.New("invalid path") 139 | } 140 | 141 | var circularRoute bool 142 | 143 | for _, hop := range rt.Path { 144 | if bytes.Equal(hop.Id, p.LocalID[:]) { 145 | circularRoute = true 146 | break 147 | } 148 | totalLatency += uint64(hop.Latency) 149 | } 150 | 151 | if circularRoute { 152 | continue 153 | } 154 | 155 | info := RouteInfo{ 156 | Route: rt, 157 | NextPeerID: p.RemoteID, 158 | TotalLatency: totalLatency, 159 | UpdateTime: time.Now(), 160 | } 161 | 162 | addRoute := true 163 | displayRouteUpdateMessage := true 164 | 165 | if err := p.Node.RoutingTable.Lookup(prefix, uint8(rt.PrefixLength), func(gotPrefix [16]byte, gotPrefixLen uint8, _oldRoute interface{}) bool { 166 | if uint32(gotPrefixLen) != rt.PrefixLength { 167 | return false 168 | } 169 | 170 | oldRoute := _oldRoute.(RouteInfo) 171 | 172 | // Rules: 173 | // - If this route points to the local vif, do not add route. 174 | // - If the old route is too old, add route. 175 | // - (majority case) If the old peer is alive, the updated route comes from the same peer, and that peer does not have major change in its route, add route without displaying message. 176 | // - If the old peer is alive, the updated route comes from the same peer, and that peer has major change in its route, add route. 177 | // - If the old peer is alive, the updated route comes from a different peer and does not have a latency of at least 10ms lower than our current one, do not add route. 178 | // - Otherwise, add route. 179 | if len(oldRoute.Route.Path) == 0 { 180 | addRoute = false 181 | } else if info.UpdateTime.After(oldRoute.UpdateTime) && info.UpdateTime.Sub(oldRoute.UpdateTime) > RouteTimeout { 182 | // add route 183 | } else { 184 | if _, ok := p.Node.Peers.Load(oldRoute.NextPeerID); ok { 185 | if oldRoute.NextPeerID == info.NextPeerID { 186 | // Most time this branch should be hit. 187 | if hopPathSimilar(oldRoute.Route, info.Route) { 188 | displayRouteUpdateMessage = false 189 | } 190 | } else { 191 | if oldRoute.TotalLatency <= info.TotalLatency || oldRoute.TotalLatency-info.TotalLatency < 10 { 192 | addRoute = false 193 | } 194 | } 195 | } 196 | } 197 | return false 198 | }); err != nil { 199 | return err 200 | } 201 | 202 | if addRoute { 203 | if displayRouteUpdateMessage { 204 | log.Printf("Updating route. Prefix = %+v, PrefixLength = %d, NextHop = %x, Latency = %d\n", net.IP(prefix[:]), rt.PrefixLength, info.NextPeerID, info.TotalLatency) 205 | } 206 | if err := p.Node.RoutingTable.Insert(prefix, uint8(rt.PrefixLength), info); err != nil { 207 | log.Println("Unable to insert route into routing table:", err) 208 | } 209 | } 210 | } 211 | 212 | return nil 213 | case MessageTag_Ping: 214 | select { 215 | case p.Out <- &protocol.Message{Tag: uint32(MessageTag_Pong)}: 216 | default: 217 | } 218 | return nil 219 | case MessageTag_Pong: 220 | p.latencyMeasurement.Lock() 221 | defer p.latencyMeasurement.Unlock() 222 | 223 | if !p.latencyMeasurement.inProgress { 224 | return errors.New("pong received without a previous Ping") 225 | } 226 | p.latencyMeasurement.inProgress = false 227 | now := time.Now() 228 | if now.Before(p.latencyMeasurement.measureStart) { 229 | log.Println("Ignoring Pong as now.Before(p.latency.measureStart) == true") 230 | return nil 231 | } 232 | latencyMs := uint32(now.Sub(p.latencyMeasurement.measureStart).Nanoseconds() / int64(time.Millisecond)) 233 | p.PushLatencyLog(latencyMs) 234 | return nil 235 | case MessageTag_UpdateDistributedConfig: 236 | var dconf protocol.DistributedConfig 237 | if err := proto.Unmarshal(msg.Payload, &dconf); err != nil { 238 | if EnableDebug { 239 | log.Println("Unable to unmarshal received distributed config") 240 | } 241 | return nil 242 | } 243 | 244 | if err := p.Node.UpdateDistributedConfig(&dconf); err != nil { 245 | if EnableDebug { 246 | log.Println("Error updating distributed config:", err) 247 | } 248 | return nil 249 | } else { 250 | log.Println("Applied distributed config.") 251 | } 252 | return nil 253 | case MessageTag_ChannelRequest: 254 | var req protocol.ChannelRequest 255 | if err := proto.Unmarshal(msg.Payload, &req); err == nil { 256 | if req.Type == protocol.ChannelType_UDP { 257 | p.udp.mu.Lock() 258 | copy(p.udp.peerToken[:], req.Token) 259 | p.udp.peerUpdateTime = time.Now() 260 | p.udp.mu.Unlock() 261 | 262 | payload := &protocol.ChannelResponse{ 263 | Type: protocol.ChannelType_UDP, 264 | Token: p.channelKey[:], 265 | } 266 | marshaled, err := proto.Marshal(payload) 267 | if err == nil { 268 | select { 269 | case p.Out <- &protocol.Message{Tag: uint32(MessageTag_ChannelResponse), Payload: marshaled}: 270 | default: 271 | } 272 | } 273 | } 274 | } 275 | return nil 276 | case MessageTag_ChannelResponse: 277 | var resp protocol.ChannelResponse 278 | if err := proto.Unmarshal(msg.Payload, &resp); err == nil { 279 | if resp.Type == protocol.ChannelType_UDP { 280 | p.udp.mu.Lock() 281 | copy(p.udp.peerToken[:], resp.Token) 282 | p.udp.peerUpdateTime = time.Now() 283 | p.udp.mu.Unlock() 284 | } 285 | } 286 | return nil 287 | default: 288 | return nil 289 | } 290 | } 291 | 292 | func (p *Peer) Start() error { 293 | p.stop = make(chan struct{}) 294 | 295 | if _, err := rand.Read(p.channelKey[:]); err != nil { 296 | return err 297 | } 298 | 299 | go func() { 300 | ticker := time.NewTicker(1 * time.Second) 301 | defer ticker.Stop() 302 | 303 | secs := uint64(0) 304 | 305 | for ; ; secs++ { 306 | select { 307 | case <-p.stop: 308 | return 309 | case <-ticker.C: 310 | // UDP keepalive. 311 | if secs%1 == 0 { 312 | p.udp.mu.Lock() 313 | if p.udp.peerAddr != nil && p.udp.peerToken != [32]byte{} { 314 | if encoded, ok := p.encodeLocked(nil); ok { 315 | _, _ = p.Node.UDPChannelListener.WriteTo(encoded, p.udp.peerAddr) 316 | } 317 | } 318 | p.udp.mu.Unlock() 319 | } 320 | 321 | // Test latency. 322 | if (secs+1)%10 == 0 { 323 | p.latencyMeasurement.Lock() 324 | if !p.latencyMeasurement.inProgress { 325 | select { 326 | case p.Out <- &protocol.Message{Tag: uint32(MessageTag_Ping)}: 327 | p.latencyMeasurement.inProgress = true 328 | p.latencyMeasurement.measureStart = time.Now() 329 | default: 330 | } 331 | } 332 | p.latencyMeasurement.Unlock() 333 | } 334 | 335 | // Send distributed config. 336 | if (secs+2)%30 == 0 { 337 | p.Node.DCState.Lock() 338 | dconf := p.Node.DCState.RawConfig 339 | p.Node.DCState.Unlock() 340 | 341 | if dconf != nil { 342 | serialized, err := proto.Marshal(dconf) 343 | if err != nil { 344 | log.Println("Unable to marshal distributed config:", err) 345 | } else { 346 | select { 347 | case p.Out <- &protocol.Message{Tag: uint32(MessageTag_UpdateDistributedConfig), Payload: serialized}: 348 | default: 349 | } 350 | } 351 | } 352 | } 353 | 354 | // Announce routes. 355 | if (secs+3)%30 == 0 { 356 | routes := make([]*protocol.Route, 0) 357 | p.Node.RoutingTable.Range(func(prefix [16]byte, prefixLen uint8, _info interface{}) bool { 358 | info := _info.(RouteInfo) 359 | if !routeIsValid(info) { 360 | p.Node.RoutingTable.Delete(prefix, prefixLen) 361 | return true 362 | } 363 | 364 | route := info.Route 365 | route.Path = append([]*protocol.Hop{{ 366 | Id: p.LocalID[:], 367 | Latency: p.GetLatencyMs(), 368 | }}, route.Path...) 369 | routes = append(routes, route) 370 | return true 371 | }) 372 | ann := &protocol.Announcement{Routes: routes} 373 | serialized, err := proto.Marshal(ann) 374 | if err != nil { 375 | log.Println("Unable to marshal announcement:", err) 376 | } else { 377 | select { 378 | case p.Out <- &protocol.Message{Tag: uint32(MessageTag_Announce), Payload: serialized}: 379 | default: 380 | } 381 | } 382 | } 383 | } 384 | } 385 | }() 386 | return nil 387 | } 388 | 389 | func (p *Peer) Stop() { 390 | close(p.stop) 391 | } 392 | 393 | func (p *Peer) encodeLocked(payload []byte) ([]byte, bool) { 394 | outLen := 32 + 32 + len(payload) 395 | if outLen > 1500 { 396 | return nil, false 397 | } 398 | ret := make([]byte, outLen) 399 | copy(ret[0:32], p.LocalID[:]) 400 | copy(ret[32:64], p.udp.peerToken[:]) 401 | copy(ret[64:], payload) 402 | return ret, true 403 | } 404 | 405 | func (p *Peer) udpCanSendLocked() bool { 406 | t := time.Now() 407 | return p.udp.peerAddr != nil && t.After(p.udp.peerUpdateTime) && t.Sub(p.udp.peerUpdateTime) < 5*time.Second 408 | } 409 | 410 | func (p *Peer) HandleUDPRecv(raddr *net.UDPAddr, payload []byte) { 411 | if len(payload) < 64 || !bytes.Equal(payload[0:32], p.RemoteID[:]) || !bytes.Equal(payload[32:64], p.channelKey[:]) { 412 | return 413 | } 414 | 415 | p.udp.mu.Lock() 416 | p.udp.peerUpdateTime = time.Now() 417 | if p.udp.peerAddr == nil || !p.udp.peerAddr.IP.Equal(raddr.IP) || p.udp.peerAddr.Port != raddr.Port { 418 | log.Printf("Received new UDP address for peer %x: %+v\n", p.RemoteID, raddr) 419 | } 420 | p.udp.peerAddr = raddr 421 | p.udp.mu.Unlock() 422 | 423 | body := payload[64:] 424 | if len(body) > 0 { 425 | if err := p.HandleMessage(&protocol.Message{ 426 | Tag: uint32(MessageTag_IP), 427 | Payload: body, 428 | }); err != nil { 429 | if EnableDebug { 430 | log.Println(err) 431 | } 432 | } 433 | } 434 | } 435 | 436 | func (p *Peer) SendUDP(payload []byte) bool { 437 | p.udp.mu.Lock() 438 | 439 | if p.udpCanSendLocked() { 440 | if encoded, ok := p.encodeLocked(payload); ok { 441 | peerAddr := p.udp.peerAddr 442 | p.udp.mu.Unlock() 443 | 444 | if _, err := p.Node.UDPChannelListener.WriteTo(encoded, peerAddr); err == nil { 445 | return true 446 | } else { 447 | return false 448 | } 449 | } 450 | } 451 | 452 | p.udp.mu.Unlock() 453 | return false 454 | } 455 | 456 | func hopPathSimilar(left, right *protocol.Route) bool { 457 | if len(left.Path) != len(right.Path) { 458 | return false 459 | } 460 | 461 | var leftTotalLatency uint64 462 | var rightTotalLatency uint64 463 | 464 | for i, leftHop := range left.Path { 465 | rightHop := right.Path[i] 466 | if !bytes.Equal(leftHop.Id, rightHop.Id) { 467 | return false 468 | } 469 | 470 | leftLatency, rightLatency := uint64(leftHop.Latency), uint64(rightHop.Latency) 471 | if AbsDiffUint64(leftLatency, rightLatency) > 5 { 472 | return false 473 | } 474 | 475 | leftTotalLatency += leftLatency 476 | rightTotalLatency += rightLatency 477 | } 478 | 479 | return AbsDiffUint64(leftTotalLatency, rightTotalLatency) < 10 480 | } 481 | 482 | func AbsDiffUint64(left, right uint64) uint64 { 483 | if left > right { 484 | return left - right 485 | } else { 486 | return right - left 487 | } 488 | } 489 | -------------------------------------------------------------------------------- /protocol/protocol.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.25.0-devel 4 | // protoc v3.14.0 5 | // source: protocol/protocol.proto 6 | 7 | package protocol 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type ChannelType int32 24 | 25 | const ( 26 | ChannelType_UDP ChannelType = 0 27 | ) 28 | 29 | // Enum value maps for ChannelType. 30 | var ( 31 | ChannelType_name = map[int32]string{ 32 | 0: "UDP", 33 | } 34 | ChannelType_value = map[string]int32{ 35 | "UDP": 0, 36 | } 37 | ) 38 | 39 | func (x ChannelType) Enum() *ChannelType { 40 | p := new(ChannelType) 41 | *p = x 42 | return p 43 | } 44 | 45 | func (x ChannelType) String() string { 46 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 47 | } 48 | 49 | func (ChannelType) Descriptor() protoreflect.EnumDescriptor { 50 | return file_protocol_protocol_proto_enumTypes[0].Descriptor() 51 | } 52 | 53 | func (ChannelType) Type() protoreflect.EnumType { 54 | return &file_protocol_protocol_proto_enumTypes[0] 55 | } 56 | 57 | func (x ChannelType) Number() protoreflect.EnumNumber { 58 | return protoreflect.EnumNumber(x) 59 | } 60 | 61 | // Deprecated: Use ChannelType.Descriptor instead. 62 | func (ChannelType) EnumDescriptor() ([]byte, []int) { 63 | return file_protocol_protocol_proto_rawDescGZIP(), []int{0} 64 | } 65 | 66 | type Message struct { 67 | state protoimpl.MessageState 68 | sizeCache protoimpl.SizeCache 69 | unknownFields protoimpl.UnknownFields 70 | 71 | Tag uint32 `protobuf:"varint,1,opt,name=tag,proto3" json:"tag,omitempty"` 72 | Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` 73 | } 74 | 75 | func (x *Message) Reset() { 76 | *x = Message{} 77 | if protoimpl.UnsafeEnabled { 78 | mi := &file_protocol_protocol_proto_msgTypes[0] 79 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 80 | ms.StoreMessageInfo(mi) 81 | } 82 | } 83 | 84 | func (x *Message) String() string { 85 | return protoimpl.X.MessageStringOf(x) 86 | } 87 | 88 | func (*Message) ProtoMessage() {} 89 | 90 | func (x *Message) ProtoReflect() protoreflect.Message { 91 | mi := &file_protocol_protocol_proto_msgTypes[0] 92 | if protoimpl.UnsafeEnabled && x != nil { 93 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 94 | if ms.LoadMessageInfo() == nil { 95 | ms.StoreMessageInfo(mi) 96 | } 97 | return ms 98 | } 99 | return mi.MessageOf(x) 100 | } 101 | 102 | // Deprecated: Use Message.ProtoReflect.Descriptor instead. 103 | func (*Message) Descriptor() ([]byte, []int) { 104 | return file_protocol_protocol_proto_rawDescGZIP(), []int{0} 105 | } 106 | 107 | func (x *Message) GetTag() uint32 { 108 | if x != nil { 109 | return x.Tag 110 | } 111 | return 0 112 | } 113 | 114 | func (x *Message) GetPayload() []byte { 115 | if x != nil { 116 | return x.Payload 117 | } 118 | return nil 119 | } 120 | 121 | type Announcement struct { 122 | state protoimpl.MessageState 123 | sizeCache protoimpl.SizeCache 124 | unknownFields protoimpl.UnknownFields 125 | 126 | Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` 127 | } 128 | 129 | func (x *Announcement) Reset() { 130 | *x = Announcement{} 131 | if protoimpl.UnsafeEnabled { 132 | mi := &file_protocol_protocol_proto_msgTypes[1] 133 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 134 | ms.StoreMessageInfo(mi) 135 | } 136 | } 137 | 138 | func (x *Announcement) String() string { 139 | return protoimpl.X.MessageStringOf(x) 140 | } 141 | 142 | func (*Announcement) ProtoMessage() {} 143 | 144 | func (x *Announcement) ProtoReflect() protoreflect.Message { 145 | mi := &file_protocol_protocol_proto_msgTypes[1] 146 | if protoimpl.UnsafeEnabled && x != nil { 147 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 148 | if ms.LoadMessageInfo() == nil { 149 | ms.StoreMessageInfo(mi) 150 | } 151 | return ms 152 | } 153 | return mi.MessageOf(x) 154 | } 155 | 156 | // Deprecated: Use Announcement.ProtoReflect.Descriptor instead. 157 | func (*Announcement) Descriptor() ([]byte, []int) { 158 | return file_protocol_protocol_proto_rawDescGZIP(), []int{1} 159 | } 160 | 161 | func (x *Announcement) GetRoutes() []*Route { 162 | if x != nil { 163 | return x.Routes 164 | } 165 | return nil 166 | } 167 | 168 | type Route struct { 169 | state protoimpl.MessageState 170 | sizeCache protoimpl.SizeCache 171 | unknownFields protoimpl.UnknownFields 172 | 173 | Prefix []byte `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` 174 | PrefixLength uint32 `protobuf:"varint,2,opt,name=prefix_length,json=prefixLength,proto3" json:"prefix_length,omitempty"` 175 | Path []*Hop `protobuf:"bytes,3,rep,name=path,proto3" json:"path,omitempty"` 176 | } 177 | 178 | func (x *Route) Reset() { 179 | *x = Route{} 180 | if protoimpl.UnsafeEnabled { 181 | mi := &file_protocol_protocol_proto_msgTypes[2] 182 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 183 | ms.StoreMessageInfo(mi) 184 | } 185 | } 186 | 187 | func (x *Route) String() string { 188 | return protoimpl.X.MessageStringOf(x) 189 | } 190 | 191 | func (*Route) ProtoMessage() {} 192 | 193 | func (x *Route) ProtoReflect() protoreflect.Message { 194 | mi := &file_protocol_protocol_proto_msgTypes[2] 195 | if protoimpl.UnsafeEnabled && x != nil { 196 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 197 | if ms.LoadMessageInfo() == nil { 198 | ms.StoreMessageInfo(mi) 199 | } 200 | return ms 201 | } 202 | return mi.MessageOf(x) 203 | } 204 | 205 | // Deprecated: Use Route.ProtoReflect.Descriptor instead. 206 | func (*Route) Descriptor() ([]byte, []int) { 207 | return file_protocol_protocol_proto_rawDescGZIP(), []int{2} 208 | } 209 | 210 | func (x *Route) GetPrefix() []byte { 211 | if x != nil { 212 | return x.Prefix 213 | } 214 | return nil 215 | } 216 | 217 | func (x *Route) GetPrefixLength() uint32 { 218 | if x != nil { 219 | return x.PrefixLength 220 | } 221 | return 0 222 | } 223 | 224 | func (x *Route) GetPath() []*Hop { 225 | if x != nil { 226 | return x.Path 227 | } 228 | return nil 229 | } 230 | 231 | type Hop struct { 232 | state protoimpl.MessageState 233 | sizeCache protoimpl.SizeCache 234 | unknownFields protoimpl.UnknownFields 235 | 236 | Id []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` 237 | Latency uint32 `protobuf:"varint,2,opt,name=latency,proto3" json:"latency,omitempty"` 238 | } 239 | 240 | func (x *Hop) Reset() { 241 | *x = Hop{} 242 | if protoimpl.UnsafeEnabled { 243 | mi := &file_protocol_protocol_proto_msgTypes[3] 244 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 245 | ms.StoreMessageInfo(mi) 246 | } 247 | } 248 | 249 | func (x *Hop) String() string { 250 | return protoimpl.X.MessageStringOf(x) 251 | } 252 | 253 | func (*Hop) ProtoMessage() {} 254 | 255 | func (x *Hop) ProtoReflect() protoreflect.Message { 256 | mi := &file_protocol_protocol_proto_msgTypes[3] 257 | if protoimpl.UnsafeEnabled && x != nil { 258 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 259 | if ms.LoadMessageInfo() == nil { 260 | ms.StoreMessageInfo(mi) 261 | } 262 | return ms 263 | } 264 | return mi.MessageOf(x) 265 | } 266 | 267 | // Deprecated: Use Hop.ProtoReflect.Descriptor instead. 268 | func (*Hop) Descriptor() ([]byte, []int) { 269 | return file_protocol_protocol_proto_rawDescGZIP(), []int{3} 270 | } 271 | 272 | func (x *Hop) GetId() []byte { 273 | if x != nil { 274 | return x.Id 275 | } 276 | return nil 277 | } 278 | 279 | func (x *Hop) GetLatency() uint32 { 280 | if x != nil { 281 | return x.Latency 282 | } 283 | return 0 284 | } 285 | 286 | type DistributedConfig struct { 287 | state protoimpl.MessageState 288 | sizeCache protoimpl.SizeCache 289 | unknownFields protoimpl.UnknownFields 290 | 291 | Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` 292 | Certificate []byte `protobuf:"bytes,2,opt,name=certificate,proto3" json:"certificate,omitempty"` 293 | Content []byte `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` 294 | } 295 | 296 | func (x *DistributedConfig) Reset() { 297 | *x = DistributedConfig{} 298 | if protoimpl.UnsafeEnabled { 299 | mi := &file_protocol_protocol_proto_msgTypes[4] 300 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 301 | ms.StoreMessageInfo(mi) 302 | } 303 | } 304 | 305 | func (x *DistributedConfig) String() string { 306 | return protoimpl.X.MessageStringOf(x) 307 | } 308 | 309 | func (*DistributedConfig) ProtoMessage() {} 310 | 311 | func (x *DistributedConfig) ProtoReflect() protoreflect.Message { 312 | mi := &file_protocol_protocol_proto_msgTypes[4] 313 | if protoimpl.UnsafeEnabled && x != nil { 314 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 315 | if ms.LoadMessageInfo() == nil { 316 | ms.StoreMessageInfo(mi) 317 | } 318 | return ms 319 | } 320 | return mi.MessageOf(x) 321 | } 322 | 323 | // Deprecated: Use DistributedConfig.ProtoReflect.Descriptor instead. 324 | func (*DistributedConfig) Descriptor() ([]byte, []int) { 325 | return file_protocol_protocol_proto_rawDescGZIP(), []int{4} 326 | } 327 | 328 | func (x *DistributedConfig) GetVersion() uint32 { 329 | if x != nil { 330 | return x.Version 331 | } 332 | return 0 333 | } 334 | 335 | func (x *DistributedConfig) GetCertificate() []byte { 336 | if x != nil { 337 | return x.Certificate 338 | } 339 | return nil 340 | } 341 | 342 | func (x *DistributedConfig) GetContent() []byte { 343 | if x != nil { 344 | return x.Content 345 | } 346 | return nil 347 | } 348 | 349 | type ChannelRequest struct { 350 | state protoimpl.MessageState 351 | sizeCache protoimpl.SizeCache 352 | unknownFields protoimpl.UnknownFields 353 | 354 | Type ChannelType `protobuf:"varint,1,opt,name=type,proto3,enum=ChannelType" json:"type,omitempty"` 355 | Token []byte `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` 356 | } 357 | 358 | func (x *ChannelRequest) Reset() { 359 | *x = ChannelRequest{} 360 | if protoimpl.UnsafeEnabled { 361 | mi := &file_protocol_protocol_proto_msgTypes[5] 362 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 363 | ms.StoreMessageInfo(mi) 364 | } 365 | } 366 | 367 | func (x *ChannelRequest) String() string { 368 | return protoimpl.X.MessageStringOf(x) 369 | } 370 | 371 | func (*ChannelRequest) ProtoMessage() {} 372 | 373 | func (x *ChannelRequest) ProtoReflect() protoreflect.Message { 374 | mi := &file_protocol_protocol_proto_msgTypes[5] 375 | if protoimpl.UnsafeEnabled && x != nil { 376 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 377 | if ms.LoadMessageInfo() == nil { 378 | ms.StoreMessageInfo(mi) 379 | } 380 | return ms 381 | } 382 | return mi.MessageOf(x) 383 | } 384 | 385 | // Deprecated: Use ChannelRequest.ProtoReflect.Descriptor instead. 386 | func (*ChannelRequest) Descriptor() ([]byte, []int) { 387 | return file_protocol_protocol_proto_rawDescGZIP(), []int{5} 388 | } 389 | 390 | func (x *ChannelRequest) GetType() ChannelType { 391 | if x != nil { 392 | return x.Type 393 | } 394 | return ChannelType_UDP 395 | } 396 | 397 | func (x *ChannelRequest) GetToken() []byte { 398 | if x != nil { 399 | return x.Token 400 | } 401 | return nil 402 | } 403 | 404 | type ChannelResponse struct { 405 | state protoimpl.MessageState 406 | sizeCache protoimpl.SizeCache 407 | unknownFields protoimpl.UnknownFields 408 | 409 | Type ChannelType `protobuf:"varint,1,opt,name=type,proto3,enum=ChannelType" json:"type,omitempty"` 410 | Token []byte `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` 411 | } 412 | 413 | func (x *ChannelResponse) Reset() { 414 | *x = ChannelResponse{} 415 | if protoimpl.UnsafeEnabled { 416 | mi := &file_protocol_protocol_proto_msgTypes[6] 417 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 418 | ms.StoreMessageInfo(mi) 419 | } 420 | } 421 | 422 | func (x *ChannelResponse) String() string { 423 | return protoimpl.X.MessageStringOf(x) 424 | } 425 | 426 | func (*ChannelResponse) ProtoMessage() {} 427 | 428 | func (x *ChannelResponse) ProtoReflect() protoreflect.Message { 429 | mi := &file_protocol_protocol_proto_msgTypes[6] 430 | if protoimpl.UnsafeEnabled && x != nil { 431 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 432 | if ms.LoadMessageInfo() == nil { 433 | ms.StoreMessageInfo(mi) 434 | } 435 | return ms 436 | } 437 | return mi.MessageOf(x) 438 | } 439 | 440 | // Deprecated: Use ChannelResponse.ProtoReflect.Descriptor instead. 441 | func (*ChannelResponse) Descriptor() ([]byte, []int) { 442 | return file_protocol_protocol_proto_rawDescGZIP(), []int{6} 443 | } 444 | 445 | func (x *ChannelResponse) GetType() ChannelType { 446 | if x != nil { 447 | return x.Type 448 | } 449 | return ChannelType_UDP 450 | } 451 | 452 | func (x *ChannelResponse) GetToken() []byte { 453 | if x != nil { 454 | return x.Token 455 | } 456 | return nil 457 | } 458 | 459 | var File_protocol_protocol_proto protoreflect.FileDescriptor 460 | 461 | var file_protocol_protocol_proto_rawDesc = []byte{ 462 | 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 463 | 0x63, 0x6f, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x35, 0x0a, 0x07, 0x4d, 0x65, 0x73, 464 | 0x73, 0x61, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 465 | 0x0d, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 466 | 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 467 | 0x22, 0x2e, 0x0a, 0x0c, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 468 | 0x12, 0x1e, 0x0a, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 469 | 0x32, 0x06, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x73, 470 | 0x22, 0x5e, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 471 | 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 472 | 0x78, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 473 | 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 474 | 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 475 | 0x20, 0x03, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x48, 0x6f, 0x70, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 476 | 0x22, 0x2f, 0x0a, 0x03, 0x48, 0x6f, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 477 | 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 478 | 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 479 | 0x79, 0x22, 0x69, 0x0a, 0x11, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 480 | 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 481 | 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 482 | 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 483 | 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 484 | 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 485 | 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x48, 0x0a, 0x0e, 486 | 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 487 | 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x43, 488 | 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 489 | 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 490 | 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x49, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 491 | 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x04, 0x74, 0x79, 0x70, 492 | 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 493 | 0x6c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 494 | 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 495 | 0x6e, 0x2a, 0x16, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 496 | 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x00, 0x32, 0x2d, 0x0a, 0x08, 0x56, 0x6e, 0x65, 497 | 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x08, 498 | 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x08, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 499 | 0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x23, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 500 | 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x6f, 0x73, 0x66, 0x61, 0x69, 0x72, 0x2f, 0x76, 501 | 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x62, 0x06, 0x70, 502 | 0x72, 0x6f, 0x74, 0x6f, 0x33, 503 | } 504 | 505 | var ( 506 | file_protocol_protocol_proto_rawDescOnce sync.Once 507 | file_protocol_protocol_proto_rawDescData = file_protocol_protocol_proto_rawDesc 508 | ) 509 | 510 | func file_protocol_protocol_proto_rawDescGZIP() []byte { 511 | file_protocol_protocol_proto_rawDescOnce.Do(func() { 512 | file_protocol_protocol_proto_rawDescData = protoimpl.X.CompressGZIP(file_protocol_protocol_proto_rawDescData) 513 | }) 514 | return file_protocol_protocol_proto_rawDescData 515 | } 516 | 517 | var file_protocol_protocol_proto_enumTypes = make([]protoimpl.EnumInfo, 1) 518 | var file_protocol_protocol_proto_msgTypes = make([]protoimpl.MessageInfo, 7) 519 | var file_protocol_protocol_proto_goTypes = []interface{}{ 520 | (ChannelType)(0), // 0: ChannelType 521 | (*Message)(nil), // 1: Message 522 | (*Announcement)(nil), // 2: Announcement 523 | (*Route)(nil), // 3: Route 524 | (*Hop)(nil), // 4: Hop 525 | (*DistributedConfig)(nil), // 5: DistributedConfig 526 | (*ChannelRequest)(nil), // 6: ChannelRequest 527 | (*ChannelResponse)(nil), // 7: ChannelResponse 528 | } 529 | var file_protocol_protocol_proto_depIdxs = []int32{ 530 | 3, // 0: Announcement.routes:type_name -> Route 531 | 4, // 1: Route.path:type_name -> Hop 532 | 0, // 2: ChannelRequest.type:type_name -> ChannelType 533 | 0, // 3: ChannelResponse.type:type_name -> ChannelType 534 | 1, // 4: VnetPeer.Input:input_type -> Message 535 | 1, // 5: VnetPeer.Input:output_type -> Message 536 | 5, // [5:6] is the sub-list for method output_type 537 | 4, // [4:5] is the sub-list for method input_type 538 | 4, // [4:4] is the sub-list for extension type_name 539 | 4, // [4:4] is the sub-list for extension extendee 540 | 0, // [0:4] is the sub-list for field type_name 541 | } 542 | 543 | func init() { file_protocol_protocol_proto_init() } 544 | func file_protocol_protocol_proto_init() { 545 | if File_protocol_protocol_proto != nil { 546 | return 547 | } 548 | if !protoimpl.UnsafeEnabled { 549 | file_protocol_protocol_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 550 | switch v := v.(*Message); i { 551 | case 0: 552 | return &v.state 553 | case 1: 554 | return &v.sizeCache 555 | case 2: 556 | return &v.unknownFields 557 | default: 558 | return nil 559 | } 560 | } 561 | file_protocol_protocol_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 562 | switch v := v.(*Announcement); i { 563 | case 0: 564 | return &v.state 565 | case 1: 566 | return &v.sizeCache 567 | case 2: 568 | return &v.unknownFields 569 | default: 570 | return nil 571 | } 572 | } 573 | file_protocol_protocol_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 574 | switch v := v.(*Route); i { 575 | case 0: 576 | return &v.state 577 | case 1: 578 | return &v.sizeCache 579 | case 2: 580 | return &v.unknownFields 581 | default: 582 | return nil 583 | } 584 | } 585 | file_protocol_protocol_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 586 | switch v := v.(*Hop); i { 587 | case 0: 588 | return &v.state 589 | case 1: 590 | return &v.sizeCache 591 | case 2: 592 | return &v.unknownFields 593 | default: 594 | return nil 595 | } 596 | } 597 | file_protocol_protocol_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 598 | switch v := v.(*DistributedConfig); i { 599 | case 0: 600 | return &v.state 601 | case 1: 602 | return &v.sizeCache 603 | case 2: 604 | return &v.unknownFields 605 | default: 606 | return nil 607 | } 608 | } 609 | file_protocol_protocol_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { 610 | switch v := v.(*ChannelRequest); i { 611 | case 0: 612 | return &v.state 613 | case 1: 614 | return &v.sizeCache 615 | case 2: 616 | return &v.unknownFields 617 | default: 618 | return nil 619 | } 620 | } 621 | file_protocol_protocol_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { 622 | switch v := v.(*ChannelResponse); i { 623 | case 0: 624 | return &v.state 625 | case 1: 626 | return &v.sizeCache 627 | case 2: 628 | return &v.unknownFields 629 | default: 630 | return nil 631 | } 632 | } 633 | } 634 | type x struct{} 635 | out := protoimpl.TypeBuilder{ 636 | File: protoimpl.DescBuilder{ 637 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 638 | RawDescriptor: file_protocol_protocol_proto_rawDesc, 639 | NumEnums: 1, 640 | NumMessages: 7, 641 | NumExtensions: 0, 642 | NumServices: 1, 643 | }, 644 | GoTypes: file_protocol_protocol_proto_goTypes, 645 | DependencyIndexes: file_protocol_protocol_proto_depIdxs, 646 | EnumInfos: file_protocol_protocol_proto_enumTypes, 647 | MessageInfos: file_protocol_protocol_proto_msgTypes, 648 | }.Build() 649 | File_protocol_protocol_proto = out.File 650 | file_protocol_protocol_proto_rawDesc = nil 651 | file_protocol_protocol_proto_goTypes = nil 652 | file_protocol_protocol_proto_depIdxs = nil 653 | } 654 | -------------------------------------------------------------------------------- /node.go: -------------------------------------------------------------------------------- 1 | package vmesh 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/sha256" 7 | "crypto/tls" 8 | "crypto/x509" 9 | "encoding/hex" 10 | "encoding/json" 11 | "encoding/pem" 12 | "errors" 13 | "fmt" 14 | "io/ioutil" 15 | "log" 16 | "net" 17 | "sort" 18 | "strconv" 19 | "strings" 20 | "sync" 21 | "time" 22 | 23 | "github.com/google/gopacket" 24 | "github.com/google/gopacket/layers" 25 | "github.com/losfair/vmesh/protocol" 26 | "google.golang.org/grpc" 27 | "google.golang.org/grpc/credentials" 28 | "google.golang.org/grpc/keepalive" 29 | peer2 "google.golang.org/grpc/peer" 30 | "google.golang.org/protobuf/proto" 31 | ) 32 | 33 | const RetryDelay = 10 * time.Second 34 | const RouteTimeout = 1 * time.Minute 35 | 36 | type Node struct { 37 | Config *NodeConfig 38 | CAPool *x509.CertPool // Internal CA 39 | CA *x509.Certificate 40 | PeerCerts PeerCertCollection // External Peers' certificates 41 | FullCert tls.Certificate 42 | LocalID PeerID 43 | Domain string 44 | 45 | // Values of the `Peers` map can be temporarily nil to indicate a peer is being initialized. 46 | Peers sync.Map // PeerID -> *Peer 47 | 48 | RoutingTable LikeRoutingTable 49 | 50 | Vifs map[string]Vif 51 | 52 | DCState DistributedConfigState 53 | 54 | UDPChannelAddr *net.UDPAddr 55 | UDPChannelListener net.PacketConn 56 | } 57 | 58 | type PeerCertCollection struct { 59 | Certs map[PeerID]*x509.Certificate 60 | } 61 | 62 | type RouteInfo struct { 63 | Route *protocol.Route 64 | NextPeerID PeerID 65 | TotalLatency uint64 66 | UpdateTime time.Time 67 | Vif Vif // only for local routes 68 | } 69 | 70 | type NodeConfig struct { 71 | ListenAddr string `json:"listen_addr"` 72 | CAPath string `json:"ca"` 73 | ExternalPeerCertPaths []string `json:"external_peer_certs"` 74 | CertPath string `json:"cert"` 75 | PrivateKeyPath string `json:"private_key"` 76 | ServerName string `json:"server_name"` 77 | LocalAnnouncements []LocalAnnouncement `json:"local_announcements"` 78 | Peers []PeerConfig `json:"peers"` 79 | Vifs map[string]VifConfig `json:"vifs"` 80 | } 81 | 82 | type LocalAnnouncement struct { 83 | Prefix string `json:"prefix"` 84 | Vif string `json:"vif"` 85 | } 86 | 87 | type VifConfig struct { 88 | Type string `json:"type"` // required 89 | 90 | // for type: tun 91 | TunName string `json:"tun_name"` 92 | 93 | // for type: service 94 | ServiceName string `json:"service_name"` 95 | ServiceNetwork string `json:"service_network"` 96 | ServiceAddress string `json:"service_address"` 97 | } 98 | 99 | type PrefixWhitelistEntryProps struct { 100 | MaxPrefixLen uint8 101 | } 102 | 103 | func ParsePrefixWhitelistEntry(entry string) (string, PrefixWhitelistEntryProps) { 104 | parts := strings.Split(entry, ",") 105 | props := PrefixWhitelistEntryProps{ 106 | MaxPrefixLen: 128, 107 | } 108 | 109 | for i := 1; i < len(parts); i++ { 110 | parts := strings.SplitN(parts[i], "=", 2) 111 | key := parts[0] 112 | value := "true" 113 | if len(parts) == 2 { 114 | value = parts[1] 115 | } 116 | 117 | switch key { 118 | case "max_prefix_len": 119 | if mpl, err := strconv.ParseUint(value, 10, 8); err == nil { 120 | if mpl <= 128 { 121 | props.MaxPrefixLen = uint8(mpl) 122 | } 123 | } 124 | default: 125 | } 126 | } 127 | return parts[0], props 128 | } 129 | 130 | type DistributedConfigState struct { 131 | sync.Mutex 132 | updateTime time.Time 133 | Config *DistributedConfig 134 | RawConfig *protocol.DistributedConfig 135 | 136 | PrefixWhitelistTable map[string]*LikeRoutingTable // typeof value = PrefixWhitelistEntryProps 137 | } 138 | 139 | func (s *DistributedConfigState) PrefixIsWhitelisted(name string, prefix [16]byte, prefixLen uint8) bool { 140 | s.Lock() 141 | table, ok := s.PrefixWhitelistTable[name] 142 | s.Unlock() 143 | 144 | // Allow by default if no entry is found in whitelist 145 | if !ok { 146 | return true 147 | } 148 | 149 | found := false 150 | 151 | _ = table.Lookup(prefix, prefixLen, func(_ [16]byte, _ uint8, _props interface{}) bool { 152 | props := _props.(PrefixWhitelistEntryProps) 153 | if prefixLen <= props.MaxPrefixLen { 154 | found = true 155 | return false 156 | } else { 157 | return true 158 | } 159 | }) 160 | 161 | return found 162 | } 163 | 164 | func (s *DistributedConfigState) updatePrefixWhitelistTableLocked() { 165 | s.PrefixWhitelistTable = make(map[string]*LikeRoutingTable) 166 | 167 | for name, allowed := range s.Config.PrefixWhitelist { 168 | table := &LikeRoutingTable{} 169 | for _, elem := range allowed { 170 | cidr, props := ParsePrefixWhitelistEntry(elem) 171 | if err := table.InsertCIDR(cidr, props); err != nil { 172 | log.Println("failed to insert CIDR-format network into whitelist:", err) 173 | } 174 | log.Printf("Added prefix whitelist entry. Prefix = %s, MaxPrefixLen = %d\n", cidr, props.MaxPrefixLen) 175 | } 176 | s.PrefixWhitelistTable[name] = table 177 | } 178 | } 179 | 180 | type DistributedConfig struct { 181 | PrefixWhitelist map[string][]string `json:"prefix_whitelist"` // node **name** -> list of allowed prefixes 182 | } 183 | 184 | type PeerConfig struct { 185 | Addr string `json:"addr"` 186 | Name string `json:"name"` 187 | UDP bool `json:"udp"` 188 | } 189 | 190 | func (c *VifConfig) Init() (Vif, error) { 191 | switch c.Type { 192 | case "tun": 193 | return NewTun(c.TunName) 194 | case "service": 195 | return NewBackingService(c.ServiceName, c.ServiceNetwork, c.ServiceAddress) 196 | case "dummy": 197 | return (*DummyVif)(nil), nil 198 | default: 199 | return nil, errors.New("invalid vif type") 200 | } 201 | } 202 | 203 | func NewNode(config *NodeConfig) (*Node, error) { 204 | fullCert, err := tls.LoadX509KeyPair(config.CertPath, config.PrivateKeyPath) 205 | if err != nil { 206 | return nil, err 207 | } 208 | 209 | if len(fullCert.Certificate) == 0 { 210 | return nil, errors.New("no certificate") 211 | } 212 | 213 | if fullCert.Leaf, err = x509.ParseCertificate(fullCert.Certificate[0]); err != nil { 214 | return nil, errors.New("cannot parse local certificate") 215 | } 216 | 217 | // The primary/internal CA 218 | caPool := x509.NewCertPool() 219 | caRaw, err := ioutil.ReadFile(config.CAPath) 220 | if err != nil { 221 | return nil, err 222 | } 223 | caPem, _ := pem.Decode(caRaw) 224 | if caPem == nil { 225 | return nil, errors.New("pem decoding failed") 226 | } 227 | ca, err := x509.ParseCertificate(caPem.Bytes) 228 | if err != nil { 229 | return nil, err 230 | } 231 | caPool.AddCert(ca) 232 | 233 | // External peers 234 | peerCerts := PeerCertCollection{Certs: make(map[PeerID]*x509.Certificate)} 235 | for _, alt := range config.ExternalPeerCertPaths { 236 | raw, err := ioutil.ReadFile(alt) 237 | if err != nil { 238 | return nil, fmt.Errorf("failed to read peer certificate at %s: %+v", alt, err) 239 | } 240 | 241 | certPem, _ := pem.Decode(raw) 242 | if certPem == nil { 243 | return nil, errors.New("pem decoding failed") 244 | } 245 | cert, err := x509.ParseCertificate(certPem.Bytes) 246 | if err != nil { 247 | return nil, err 248 | } 249 | 250 | certID := peerIDFromCertificate(cert) 251 | peerCerts.Certs[certID] = cert 252 | } 253 | 254 | vifs := make(map[string]Vif) 255 | 256 | for key, c := range config.Vifs { 257 | vif, err := c.Init() 258 | if err != nil { 259 | return nil, fmt.Errorf("failed to init vif '%s': %+v", key, err) 260 | } 261 | vifs[key] = vif 262 | log.Printf("Initialized virtual interface '%s'\n", key) 263 | } 264 | 265 | domainParts := strings.SplitN(fullCert.Leaf.Subject.CommonName, ".", 2) 266 | if len(domainParts) != 2 { 267 | return nil, errors.New("invalid common name") 268 | } 269 | 270 | udpAddr, err := net.ResolveUDPAddr("udp", config.ListenAddr) 271 | if err != nil { 272 | return nil, err 273 | } 274 | 275 | n := &Node{ 276 | Config: config, 277 | CAPool: caPool, 278 | CA: ca, 279 | PeerCerts: peerCerts, 280 | FullCert: fullCert, 281 | LocalID: peerIDFromCertificate(fullCert.Leaf), 282 | Domain: domainParts[1], 283 | Vifs: vifs, 284 | DCState: DistributedConfigState{ 285 | PrefixWhitelistTable: make(map[string]*LikeRoutingTable), 286 | }, 287 | UDPChannelAddr: udpAddr, 288 | } 289 | 290 | log.Printf("Local ID: %x\n", n.LocalID) 291 | log.Println("Domain:", n.Domain) 292 | log.Println("Local name:", n.FullCert.Leaf.Subject.CommonName) 293 | 294 | if len(config.LocalAnnouncements) > 0 { 295 | for _, ann := range config.LocalAnnouncements { 296 | _, ipnet, err := net.ParseCIDR(ann.Prefix) 297 | if err != nil { 298 | return nil, err 299 | } 300 | 301 | if len(ipnet.IP) != 16 { 302 | return nil, errors.New("invalid ip prefix") 303 | } 304 | 305 | prefixLen, _ := ipnet.Mask.Size() 306 | var prefix [16]byte 307 | 308 | copy(prefix[:], ipnet.IP) 309 | if err := n.RoutingTable.Insert(prefix, uint8(prefixLen), RouteInfo{ 310 | Route: &protocol.Route{ 311 | Prefix: ipnet.IP.Mask(ipnet.Mask), 312 | PrefixLength: uint32(prefixLen), 313 | }, 314 | TotalLatency: 0, 315 | Vif: n.Vifs[ann.Vif], // nil by default 316 | }); err != nil { 317 | return nil, err 318 | } 319 | } 320 | } 321 | 322 | return n, nil 323 | } 324 | 325 | func (n *Node) BuildPrintableRoutingTable() string { 326 | routes := make([]string, 0) 327 | 328 | n.RoutingTable.Range(func(prefix [16]byte, prefixLen uint8, _info interface{}) bool { 329 | info := _info.(RouteInfo) 330 | prettyPath := strings.Builder{} 331 | for _, item := range info.Route.Path { 332 | prettyPath.WriteString(fmt.Sprintf(" %x (Latency: %d)\n", item.Id, item.Latency)) 333 | } 334 | routes = append( 335 | routes, 336 | fmt.Sprintf("ROUTE: %s/%d\n Latency: %d\n Path:\n%s", net.IP(info.Route.Prefix), info.Route.PrefixLength, info.TotalLatency, prettyPath.String()), 337 | ) 338 | return true 339 | }) 340 | sort.Strings(routes) 341 | return strings.Join(routes, "\n") 342 | } 343 | 344 | func (n *Node) UpdateDistributedConfig(dc *protocol.DistributedConfig) error { 345 | if dc.Version != 1 { 346 | return errors.New("unsupported distributed config version") 347 | } 348 | 349 | cert, err := x509.ParseCertificate(dc.Certificate) 350 | if err != nil { 351 | return errors.New("cannot parse certificate for DC") 352 | } 353 | 354 | _, err = cert.Verify(x509.VerifyOptions{ 355 | Roots: n.CAPool, 356 | }) 357 | if err != nil { 358 | return errors.New("cannot verify certificate for DC") 359 | } 360 | 361 | if len(cert.URIs) != 1 { 362 | return errors.New("invalid URIs in DC certificate") 363 | } 364 | 365 | if cert.URIs[0].Scheme != "vnet-conf" { 366 | return errors.New("invalid URI scheme in DC certificate") 367 | } 368 | 369 | n.DCState.Lock() 370 | defer n.DCState.Unlock() 371 | 372 | if n.DCState.Config != nil && (cert.NotBefore.Before(n.DCState.updateTime) || cert.NotBefore.Equal(n.DCState.updateTime)) { 373 | return errors.New("received DC is not newer than our current one, rejected") 374 | } 375 | 376 | hashSum, err := hex.DecodeString(cert.URIs[0].Host) 377 | if err != nil { 378 | return errors.New("invalid hash sum in DC certificate") 379 | } 380 | 381 | computedHash := sha256.Sum256(dc.Content) 382 | if !bytes.Equal(computedHash[:], hashSum) { 383 | return errors.New("hash mismatch between DC certificate and content") 384 | } 385 | 386 | var dconf DistributedConfig 387 | 388 | err = json.Unmarshal(dc.Content, &dconf) 389 | if err != nil { 390 | return errors.New("cannot decode distributed config") 391 | } 392 | 393 | n.DCState.Config = &dconf 394 | n.DCState.RawConfig = dc 395 | n.DCState.updateTime = cert.NotBefore 396 | 397 | n.DCState.updatePrefixWhitelistTableLocked() 398 | 399 | return nil 400 | } 401 | 402 | func (n *Node) DispatchIPPacket(payload []byte) error { 403 | var ip6 layers.IPv6 404 | decoded := []gopacket.LayerType{} 405 | 406 | parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv6, &ip6) 407 | parser.IgnoreUnsupported = true 408 | if err := parser.DecodeLayers(payload, &decoded); err != nil { 409 | if EnableDebug { 410 | log.Println("DecodeLayers error:", err) 411 | } 412 | return errors.New("cannot decode IP packet") 413 | } 414 | if len(decoded) == 0 || decoded[0] != layers.LayerTypeIPv6 { 415 | return errors.New("invalid protocol payload") 416 | } 417 | if len(ip6.SrcIP) != 16 || len(ip6.DstIP) != 16 { 418 | return errors.New("invalid src/dst ip") 419 | } 420 | 421 | routeInfo, nextPeer, err := n.GetRouteForAddress(ip6.DstIP) 422 | if err != nil { 423 | return err 424 | } 425 | 426 | if len(routeInfo.Route.Path) == 0 { 427 | // Dispatch to local Vif 428 | // nextPeer is nil here 429 | if nextPeer != nil { 430 | panic("inconsistent routeInfo/nextPeer") 431 | } 432 | if routeInfo.Vif != nil { 433 | if _, err := routeInfo.Vif.Send(payload); err != nil { 434 | return err 435 | } 436 | } else { 437 | return errors.New("vif unavailable") 438 | } 439 | } else { 440 | select { 441 | case nextPeer.Out <- &protocol.Message{Tag: uint32(MessageTag_IP), Payload: payload}: 442 | default: 443 | } 444 | } 445 | 446 | return nil 447 | } 448 | 449 | func (n *Node) GetRouteForAddress(_addr net.IP) (retRouteInfo RouteInfo, retPeer *Peer, retErr error) { 450 | if len(_addr) != 16 { 451 | return RouteInfo{}, nil, errors.New("invalid address") 452 | } 453 | 454 | var addr [16]byte 455 | copy(addr[:], _addr) 456 | var found bool 457 | 458 | if err := n.RoutingTable.Lookup(addr, 128, func(prefix [16]byte, prefixLen uint8, _routeInfo interface{}) bool { 459 | routeInfo := _routeInfo.(RouteInfo) 460 | if !routeIsValid(routeInfo) { 461 | n.RoutingTable.Delete(prefix, prefixLen) 462 | return true 463 | } 464 | 465 | if len(routeInfo.Route.Path) == 0 { 466 | retRouteInfo = routeInfo 467 | found = true 468 | return false // local 469 | } 470 | if peer, ok := n.Peers.Load(routeInfo.NextPeerID); ok && peer != nil { 471 | retRouteInfo = routeInfo 472 | retPeer = peer.(*Peer) 473 | found = true 474 | return false 475 | } 476 | return true 477 | }); err != nil { 478 | retErr = err 479 | return 480 | } 481 | 482 | if !found { 483 | retErr = errors.New("route not found") 484 | } 485 | return 486 | } 487 | 488 | func (n *Node) processVifPackets(vif Vif) { 489 | for { 490 | buf := make([]byte, 1500) 491 | count, err := vif.Recv(buf) 492 | if err != nil { 493 | if EnableDebug { 494 | log.Println("Vif recv error:", err) 495 | } 496 | continue 497 | } 498 | payload := buf[:count] 499 | if err := n.DispatchIPPacket(payload); err != nil { 500 | if EnableDebug { 501 | log.Println("DispatchIPPacket error:", err) 502 | } 503 | } 504 | } 505 | } 506 | 507 | func (n *Node) processUDPPackets() { 508 | buf := make([]byte, 1500) 509 | 510 | for { 511 | readN, raddr, err := n.UDPChannelListener.ReadFrom(buf) 512 | if err != nil || readN == 0 { 513 | continue 514 | } 515 | 516 | buf := buf[:readN] 517 | if len(buf) < 64 { 518 | continue 519 | } 520 | 521 | var peerID PeerID 522 | copy(peerID[:], buf[:32]) 523 | 524 | _peer, ok := n.Peers.Load(peerID) 525 | if !ok { 526 | continue 527 | } 528 | 529 | peer := _peer.(*Peer) 530 | copied := append([]byte{}, buf...) 531 | peer.HandleUDPRecv(raddr.(*net.UDPAddr), copied) 532 | } 533 | } 534 | 535 | func (n *Node) Run() error { 536 | for _, vif := range n.Vifs { 537 | go n.processVifPackets(vif) 538 | } 539 | 540 | // Insecure channel 541 | udpListener, err := net.ListenUDP("udp", n.UDPChannelAddr) 542 | if err != nil { 543 | return err 544 | } 545 | 546 | n.UDPChannelListener = udpListener 547 | go n.processUDPPackets() 548 | 549 | creds := credentials.NewTLS(&tls.Config{ 550 | Certificates: []tls.Certificate{n.FullCert}, 551 | ServerName: n.Config.ServerName, 552 | ClientAuth: tls.RequireAnyClientCert, 553 | }) 554 | 555 | server := grpc.NewServer(grpc.Creds(creds), grpc.KeepaliveParams(keepalive.ServerParameters{ 556 | Time: 30 * time.Second, 557 | Timeout: 10 * time.Second, 558 | })) 559 | service := &PeerServer{ 560 | node: n, 561 | } 562 | protocol.RegisterVnetPeerServer(server, service) 563 | 564 | tcpListener, err := net.Listen("tcp", n.Config.ListenAddr) 565 | if err != nil { 566 | return err 567 | } 568 | 569 | return server.Serve(tcpListener) 570 | } 571 | 572 | func (n *Node) ConnectToAllPeers() { 573 | for _, peer := range n.Config.Peers { 574 | go n.PersistingConnect(peer, nil) 575 | } 576 | } 577 | 578 | func (n *Node) PersistingConnect(peer PeerConfig, oldError error) { 579 | err := oldError 580 | for { 581 | if err != nil && strings.Contains(err.Error(), "detected multiple connections") { 582 | // - 1. Another thread has initiated a connection. (so it is responsible for reconnecting) 583 | // - 2. The remote peer has actively connected to us. (so the remote peer is responsible for reconnecting) 584 | // In practice we do need to reconnect here sometimes. So just sleep longer. 585 | time.Sleep(RetryDelay * 10) 586 | err = nil 587 | continue 588 | } 589 | log.Printf("Connecting to %s/%s\n", peer.Addr, peer.Name) 590 | if err = n.Connect(peer, true); err != nil { 591 | log.Printf("Connect failed, waiting for %+v. error = %+v\n", RetryDelay, err) 592 | time.Sleep(RetryDelay) 593 | continue 594 | } else { 595 | break 596 | } 597 | } 598 | } 599 | 600 | func (n *Node) Connect(peer PeerConfig, persist bool) error { 601 | creds := credentials.NewTLS(&tls.Config{ 602 | Certificates: []tls.Certificate{n.FullCert}, 603 | ServerName: peer.Name, 604 | InsecureSkipVerify: true, // verification will be handled in ProcessMessageStream 605 | }) 606 | conn, err := grpc.Dial(peer.Addr, grpc.WithTransportCredentials(creds), grpc.WithKeepaliveParams(keepalive.ClientParameters{ 607 | Time: 30 * time.Second, 608 | Timeout: 10 * time.Second, 609 | })) 610 | if err != nil { 611 | return err 612 | } 613 | client := protocol.NewVnetPeerClient(conn) 614 | session, err := client.Input(context.Background()) 615 | if err != nil { 616 | return err 617 | } 618 | 619 | go func() { 620 | err := n.ProcessMessageStream(session, &peer) 621 | 622 | closeErr := session.CloseSend() 623 | if closeErr != nil { 624 | log.Println("CloseSend() returns error:", closeErr) 625 | } 626 | 627 | log.Printf("Session closed, error = %+v\n", err) 628 | if persist { 629 | time.Sleep(RetryDelay) 630 | n.PersistingConnect(peer, err) 631 | } 632 | }() 633 | return nil 634 | } 635 | 636 | type MessageStream interface { 637 | Send(message *protocol.Message) error 638 | Recv() (*protocol.Message, error) 639 | Context() context.Context 640 | } 641 | 642 | func (n *Node) ProcessMessageStream(stream MessageStream, peerConfig *PeerConfig) error { 643 | netInfo, ok := peer2.FromContext(stream.Context()) 644 | if !ok { 645 | return errors.New("cannot get network info") 646 | } 647 | tlsInfo, ok := netInfo.AuthInfo.(credentials.TLSInfo) 648 | if !ok { 649 | return errors.New("cannot get tls info") 650 | } 651 | 652 | if len(tlsInfo.State.PeerCertificates) == 0 { 653 | return errors.New("peer did not provide any certificates") 654 | } 655 | 656 | remoteCert := tlsInfo.State.PeerCertificates[0] 657 | remoteName := remoteCert.Subject.CommonName 658 | remoteID := peerIDFromCertificate(remoteCert) 659 | 660 | _, err := remoteCert.Verify(x509.VerifyOptions{ 661 | Roots: n.CAPool, 662 | }) 663 | var remoteBelongsToInternalCA bool 664 | if err != nil { 665 | // Possibly an external peer 666 | if _, ok := n.PeerCerts.Certs[remoteID]; ok { 667 | err = nil 668 | remoteBelongsToInternalCA = false 669 | } else { 670 | return errors.New("unable to verify peer certificate") 671 | } 672 | } else { 673 | remoteBelongsToInternalCA = true 674 | } 675 | 676 | // If we are in different domains or under different CAs 677 | if !strings.HasSuffix(remoteName, "."+n.Domain) || !remoteBelongsToInternalCA { 678 | log.Printf("Attempting to establish connection with an external peer with name: %s.", remoteName) 679 | } 680 | 681 | peerOut := make(chan *protocol.Message, 128) 682 | 683 | peer := &Peer{ 684 | Node: n, 685 | LocalCert: n.FullCert.Leaf, 686 | LocalID: n.LocalID, 687 | RemoteCert: remoteCert, 688 | RemoteID: remoteID, 689 | RemoteName: remoteName, 690 | Out: peerOut, 691 | } 692 | 693 | if _, loaded := n.Peers.LoadOrStore(remoteID, nil); loaded { 694 | return errors.New("detected multiple connections from a single remote peer") 695 | } 696 | 697 | stop := make(chan struct{}) 698 | if err := peer.Start(); err != nil { 699 | n.Peers.Delete(remoteID) 700 | return err 701 | } 702 | 703 | n.Peers.Store(remoteID, peer) 704 | 705 | if peerConfig != nil { 706 | if peerConfig.UDP { 707 | if udpAddr, err := net.ResolveUDPAddr("udp", peerConfig.Addr); err == nil { 708 | peer.udp.mu.Lock() 709 | peer.udp.peerAddr = udpAddr 710 | peer.udp.mu.Unlock() 711 | 712 | marshaled, err := proto.Marshal(&protocol.ChannelRequest{ 713 | Type: protocol.ChannelType_UDP, 714 | Token: peer.channelKey[:], // initialized in peer.Start() 715 | }) 716 | if err == nil { 717 | select { 718 | case peer.Out <- &protocol.Message{Tag: uint32(MessageTag_ChannelRequest), Payload: marshaled}: 719 | default: 720 | log.Println("Warning: Failed to send channel request") 721 | } 722 | } 723 | } else { 724 | log.Println("Warning: Cannot decode peer address for UDP") 725 | } 726 | } 727 | } 728 | 729 | fullyClosed := make(chan struct{}) 730 | 731 | go func() { 732 | defer func() { 733 | peer.Stop() 734 | n.Peers.Delete(remoteID) 735 | close(fullyClosed) 736 | }() 737 | 738 | outer: 739 | for { 740 | select { 741 | case msg := <-peerOut: 742 | if MessageTag(msg.Tag) == MessageTag_IP && peer.SendUDP(msg.Payload) { 743 | goto outer 744 | } 745 | 746 | err := stream.Send(msg) 747 | if err != nil { 748 | return 749 | } 750 | case <-stop: 751 | return 752 | } 753 | } 754 | }() 755 | 756 | defer func() { 757 | close(stop) 758 | <-fullyClosed 759 | }() 760 | 761 | log.Printf("Initialized stream with peer %x (%s)\n", peer.RemoteID, peer.RemoteName) 762 | 763 | for { 764 | msg, err := stream.Recv() 765 | if err != nil { 766 | return err 767 | } 768 | if err := peer.HandleMessage(msg); err != nil { 769 | return err 770 | } 771 | } 772 | } 773 | 774 | type PeerServer struct { 775 | protocol.UnimplementedVnetPeerServer 776 | node *Node 777 | } 778 | 779 | func (p *PeerServer) Input(server protocol.VnetPeer_InputServer) error { 780 | return p.node.ProcessMessageStream(server, nil) 781 | } 782 | 783 | func peerIDFromCertificate(cert *x509.Certificate) PeerID { 784 | return sha256.Sum256(cert.Raw) 785 | } 786 | 787 | func routeIsValid(info RouteInfo) bool { 788 | if len(info.Route.Path) == 0 { 789 | // local route 790 | return true 791 | } 792 | 793 | currentTime := time.Now() 794 | if currentTime.After(info.UpdateTime) && currentTime.Sub(info.UpdateTime) > RouteTimeout { 795 | return false 796 | } 797 | return true 798 | } 799 | --------------------------------------------------------------------------------