]> Cypherpunks.ru repositories - nncp.git/blob - src/yggdrasil/tcpip.go
b602dc12422a02311ce672fc87166f2f12be2c52
[nncp.git] / src / yggdrasil / tcpip.go
1 //go:build !noyggdrasil
2 // +build !noyggdrasil
3
4 /*
5 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
6 Copyright (C) 2016-2022 Sergey Matveev <stargrave@stargrave.org>
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, version 3 of the License.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 Code below is heavily based on Wireguard's MIT licenced
21 golang.zx2c4.com/wireguard/tun/netstack.
22 */
23
24 package yggdrasil
25
26 import (
27         "fmt"
28         "log"
29         "net"
30
31         iwt "github.com/Arceliar/ironwood/types"
32         yaddr "github.com/yggdrasil-network/yggdrasil-go/src/address"
33         "golang.org/x/crypto/ed25519"
34         "inet.af/netstack/tcpip"
35         "inet.af/netstack/tcpip/adapters/gonet"
36         "inet.af/netstack/tcpip/buffer"
37         "inet.af/netstack/tcpip/header"
38         "inet.af/netstack/tcpip/network/ipv6"
39         "inet.af/netstack/tcpip/stack"
40         "inet.af/netstack/tcpip/transport/tcp"
41 )
42
43 const IPv6HdrSize = 40
44
45 type TCPIPEndpoint struct {
46         mtu      uint32
47         s        *stack.Stack
48         pc       net.PacketConn
49         d        stack.NetworkDispatcher
50         readBuf  []byte
51         writeBuf []byte
52         ip       yaddr.Address
53         ipToAddr map[yaddr.Address]net.Addr
54         pubToIP  map[[ed25519.PublicKeySize]byte]yaddr.Address
55 }
56
57 func (e *TCPIPEndpoint) Attach(dispatcher stack.NetworkDispatcher) { e.d = dispatcher }
58
59 func (e *TCPIPEndpoint) IsAttached() bool { return e.d != nil }
60
61 func (e *TCPIPEndpoint) MTU() uint32 { return e.mtu }
62
63 func (*TCPIPEndpoint) Capabilities() stack.LinkEndpointCapabilities { return stack.CapabilityNone }
64
65 func (*TCPIPEndpoint) MaxHeaderLength() uint16 { return 0 }
66
67 func (*TCPIPEndpoint) LinkAddress() tcpip.LinkAddress { return "" }
68
69 func (*TCPIPEndpoint) Wait() {}
70
71 func (e *TCPIPEndpoint) WritePacket(
72         _ stack.RouteInfo,
73         _ tcpip.NetworkProtocolNumber,
74         pkt *stack.PacketBuffer,
75 ) tcpip.Error {
76         vv := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
77         n, err := vv.Read(e.writeBuf)
78         if err != nil {
79                 log.Println(err)
80                 return &tcpip.ErrAborted{}
81         }
82         copy(e.ip[:], e.writeBuf[IPv6HdrSize-len(e.ip):IPv6HdrSize])
83         addr, ok := e.ipToAddr[e.ip]
84         if !ok {
85                 log.Println("no address found:", e.ip)
86                 return nil
87         }
88         _, err = e.pc.WriteTo(e.writeBuf[:n], addr)
89         if err != nil {
90                 log.Println(err)
91                 return &tcpip.ErrAborted{}
92         }
93         return nil
94 }
95
96 func (e *TCPIPEndpoint) WritePackets(
97         stack.RouteInfo,
98         stack.PacketBufferList,
99         tcpip.NetworkProtocolNumber,
100 ) (int, tcpip.Error) {
101         panic("not implemented")
102 }
103
104 func (e *TCPIPEndpoint) WriteRawPacket(*stack.PacketBuffer) tcpip.Error {
105         panic("not implemented")
106 }
107
108 func (*TCPIPEndpoint) ARPHardwareType() header.ARPHardwareType { return header.ARPHardwareNone }
109
110 func (e *TCPIPEndpoint) AddHeader(
111         tcpip.LinkAddress,
112         tcpip.LinkAddress,
113         tcpip.NetworkProtocolNumber,
114         *stack.PacketBuffer,
115 ) {
116 }
117
118 func convertToFullAddr(ip net.IP, port int) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) {
119         return tcpip.FullAddress{
120                 NIC:  1,
121                 Addr: tcpip.Address(ip),
122                 Port: uint16(port),
123         }, ipv6.ProtocolNumber
124 }
125
126 func (e *TCPIPEndpoint) DialTCP(addr *net.TCPAddr) (*gonet.TCPConn, error) {
127         if addr == nil {
128                 panic("not implemented")
129         }
130         fa, pn := convertToFullAddr(addr.IP, addr.Port)
131         return gonet.DialTCP(e.s, fa, pn)
132 }
133
134 func (e *TCPIPEndpoint) ListenTCP(addr *net.TCPAddr) (*gonet.TCPListener, error) {
135         if addr == nil {
136                 panic("not implemented")
137         }
138         fa, pn := convertToFullAddr(addr.IP, addr.Port)
139         return gonet.ListenTCP(e.s, fa, pn)
140 }
141
142 func (e *TCPIPEndpoint) Close() error {
143         e.s.RemoveNIC(1)
144         return nil
145 }
146
147 func NewTCPIPEndpoint(
148         pc net.PacketConn,
149         ipOur net.IP,
150         mtu uint32,
151 ) (*TCPIPEndpoint, error) {
152         s := stack.New(stack.Options{
153                 NetworkProtocols:   []stack.NetworkProtocolFactory{ipv6.NewProtocol},
154                 TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
155                 HandleLocal:        true,
156         })
157         e := TCPIPEndpoint{
158                 mtu:      mtu,
159                 s:        s,
160                 pc:       pc,
161                 readBuf:  make([]byte, 1<<16),
162                 writeBuf: make([]byte, 1<<16),
163                 ipToAddr: make(map[yaddr.Address]net.Addr),
164                 pubToIP:  make(map[[ed25519.PublicKeySize]byte]yaddr.Address),
165         }
166         if err := s.CreateNIC(1, &e); err != nil {
167                 return nil, fmt.Errorf("%+v", err)
168         }
169         protoAddr := tcpip.ProtocolAddress{
170                 Protocol:          ipv6.ProtocolNumber,
171                 AddressWithPrefix: tcpip.Address(ipOur).WithPrefix(),
172         }
173         if err := s.AddProtocolAddress(1, protoAddr, stack.AddressProperties{}); err != nil {
174                 return nil, fmt.Errorf("%+v", err)
175         }
176         s.AddRoute(tcpip.Route{Destination: header.IPv6EmptySubnet, NIC: 1})
177         go func() {
178                 var n int
179                 var from net.Addr
180                 var err error
181                 var pub [ed25519.PublicKeySize]byte
182                 for {
183                         n, from, err = pc.ReadFrom(e.readBuf)
184                         if err != nil {
185                                 log.Println(err)
186                                 break
187                         }
188                         copy(pub[:], from.(iwt.Addr))
189                         ip, ok := e.pubToIP[pub]
190                         if !ok {
191                                 copy(ip[:], yaddr.AddrForKey(ed25519.PublicKey(pub[:]))[:])
192                                 e.pubToIP[pub] = ip
193                                 e.ipToAddr[ip] = from
194                         }
195                         pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{
196                                 Data: buffer.NewVectorisedView(n, []buffer.View{
197                                         buffer.NewViewFromBytes(e.readBuf[:n]),
198                                 }),
199                         })
200                         e.d.DeliverNetworkPacket("", "", ipv6.ProtocolNumber, pkb)
201                 }
202         }()
203         return &e, nil
204 }