1 //go:build !noyggdrasil
5 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
6 Copyright (C) 2016-2022 Sergey Matveev <stargrave@stargrave.org>
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.
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.
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/>.
20 Code below is heavily based on Wireguard's MIT licenced
21 golang.zx2c4.com/wireguard/tun/netstack.
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"
43 const IPv6HdrSize = 40
45 type TCPIPEndpoint struct {
49 d stack.NetworkDispatcher
53 ipToAddr map[yaddr.Address]net.Addr
54 pubToIP map[[ed25519.PublicKeySize]byte]yaddr.Address
57 func (e *TCPIPEndpoint) Attach(dispatcher stack.NetworkDispatcher) { e.d = dispatcher }
59 func (e *TCPIPEndpoint) IsAttached() bool { return e.d != nil }
61 func (e *TCPIPEndpoint) MTU() uint32 { return e.mtu }
63 func (*TCPIPEndpoint) Capabilities() stack.LinkEndpointCapabilities { return stack.CapabilityNone }
65 func (*TCPIPEndpoint) MaxHeaderLength() uint16 { return 0 }
67 func (*TCPIPEndpoint) LinkAddress() tcpip.LinkAddress { return "" }
69 func (*TCPIPEndpoint) Wait() {}
71 func (e *TCPIPEndpoint) WritePacket(
73 _ tcpip.NetworkProtocolNumber,
74 pkt *stack.PacketBuffer,
76 vv := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
77 n, err := vv.Read(e.writeBuf)
80 return &tcpip.ErrAborted{}
82 copy(e.ip[:], e.writeBuf[IPv6HdrSize-len(e.ip):IPv6HdrSize])
83 addr, ok := e.ipToAddr[e.ip]
85 log.Println("no address found:", e.ip)
88 _, err = e.pc.WriteTo(e.writeBuf[:n], addr)
91 return &tcpip.ErrAborted{}
96 func (e *TCPIPEndpoint) WritePackets(
98 stack.PacketBufferList,
99 tcpip.NetworkProtocolNumber,
100 ) (int, tcpip.Error) {
101 panic("not implemented")
104 func (e *TCPIPEndpoint) WriteRawPacket(*stack.PacketBuffer) tcpip.Error {
105 panic("not implemented")
108 func (*TCPIPEndpoint) ARPHardwareType() header.ARPHardwareType { return header.ARPHardwareNone }
110 func (e *TCPIPEndpoint) AddHeader(
113 tcpip.NetworkProtocolNumber,
118 func convertToFullAddr(ip net.IP, port int) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) {
119 return tcpip.FullAddress{
121 Addr: tcpip.Address(ip),
123 }, ipv6.ProtocolNumber
126 func (e *TCPIPEndpoint) DialTCP(addr *net.TCPAddr) (*gonet.TCPConn, error) {
128 panic("not implemented")
130 fa, pn := convertToFullAddr(addr.IP, addr.Port)
131 return gonet.DialTCP(e.s, fa, pn)
134 func (e *TCPIPEndpoint) ListenTCP(addr *net.TCPAddr) (*gonet.TCPListener, error) {
136 panic("not implemented")
138 fa, pn := convertToFullAddr(addr.IP, addr.Port)
139 return gonet.ListenTCP(e.s, fa, pn)
142 func (e *TCPIPEndpoint) Close() error {
147 func NewTCPIPEndpoint(
151 ) (*TCPIPEndpoint, error) {
152 s := stack.New(stack.Options{
153 NetworkProtocols: []stack.NetworkProtocolFactory{ipv6.NewProtocol},
154 TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
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),
166 if err := s.CreateNIC(1, &e); err != nil {
167 return nil, fmt.Errorf("%+v", err)
169 protoAddr := tcpip.ProtocolAddress{
170 Protocol: ipv6.ProtocolNumber,
171 AddressWithPrefix: tcpip.Address(ipOur).WithPrefix(),
173 if err := s.AddProtocolAddress(1, protoAddr, stack.AddressProperties{}); err != nil {
174 return nil, fmt.Errorf("%+v", err)
176 s.AddRoute(tcpip.Route{Destination: header.IPv6EmptySubnet, NIC: 1})
181 var pub [ed25519.PublicKeySize]byte
183 n, from, err = pc.ReadFrom(e.readBuf)
188 copy(pub[:], from.(iwt.Addr))
189 ip, ok := e.pubToIP[pub]
191 copy(ip[:], yaddr.AddrForKey(ed25519.PublicKey(pub[:]))[:])
193 e.ipToAddr[ip] = from
195 pkb := stack.NewPacketBuffer(stack.PacketBufferOptions{
196 Data: buffer.NewVectorisedView(n, []buffer.View{
197 buffer.NewViewFromBytes(e.readBuf[:n]),
200 e.d.DeliverNetworkPacket("", "", ipv6.ProtocolNumber, pkb)