README
¶
DerpNET
(Ab)using Tailscale's DERP servers to connect any two machines without a Tailscale account.
Tailscale operates many DERP servers which implement the DERP protocol. DERP servers support routing a packet to any client connected to the same DERP server using their curve25519 address.
We (ab)use this routing to implement UDP-like connections through DERP server. Instead of IP addresses, we use curve25519 public keys as the address. TCP-like stream semantics are added by running QUIC on top of the UDP-like connection.
This project is not affiliated with Tailscale in any way. I've used it to connect to small HTTP servers on my personal machine. It is not optimized for high bandwidth.
Usage
To install the binary, run:
go install github.com/ntnj/derpnet/cmd/derpconnect@latest
Find a DERP server closest to you from here. Use it as the value of --derp
flags in the commands below.
To expose a port running on a server:
derpconnect --derp=... serve <port>
The above command will print a public key, which you can use on different client machine.
On a client machine, run:
derpconnect --derp=... join <pubkey> <listen_port>
This will start listening on <listen_port>
, and any connections to that port are forwarded to <port>
on the server.
Use as a library
To get a UDP like connection, you can use derpnet.ListenPacket
, which is similar to net.ListenPacket
function:
import github.com/ntnj/derpnet
conn, err := derpnet.ListenPacket("<derp>.tailscale.com", <privatekeybytes>)
n, err := conn.WriteTo(<msg>, <pubkeybytes>)
n, addr, err := conn.ReadFrom(<bytes>)
TCP-like semantics are added based on QUIC streams implemented with quic-go.
On server side:
import github.com/ntnj/derpnet/derpquic
l, err := derpquic.Listen("<derp>.tailscale.com", <privatekeybytes>)
for {
conn, err := l.Accept()
// conn implements net.Conn
}
On the client:
import github.com/ntnj/derpnet/derpquic
d, err := derpquic.NewDialer("<derp>.tailscale.com", <privatekeybytes>)
conn, err := d.Dial(<pubkeybytes>)
// conn implements net.Conn
Caveats
- It doesn't attempt to establish P2P connections like Tailscale does, so will be limited by DERP server's bandwidth and latency.
- quic-go doesn't currently allow setting configurable packet size and uses a default of 1200, which causes a large amount of packets to be sent to DERP server for connections sending a lot of data.
- It doesn't currently handle reconnecting to DERP server in case the connection to the DERP server drops.
Documentation
¶
Index ¶
- Variables
- func ListenPacket(derpURL string, key Key) (net.PacketConn, error)
- type Addr
- type Key
- type ListenConfig
- type PacketConn
- func (c *PacketConn) Close() error
- func (c *PacketConn) LocalAddr() net.Addr
- func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
- func (*PacketConn) SetDeadline(t time.Time) error
- func (c *PacketConn) SetReadDeadline(t time.Time) error
- func (*PacketConn) SetWriteDeadline(t time.Time) error
- func (c *PacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error)
- type PublicKey
Constants ¶
This section is empty.
Variables ¶
var Debug = false
Functions ¶
func ListenPacket ¶
func ListenPacket(derpURL string, key Key) (net.PacketConn, error)
ListenPacket connects to a DERP server URL with the provided private key. It returns net.PacketConn derpURL should be a valid server name compatible with the Tailscale's DERP protocol. key should have a length of 32 bytes
Types ¶
type Addr ¶
type Addr []byte
Addr implements net.Addr, and represents the public addr of the connection.
func (Addr) EncodedString ¶
type ListenConfig ¶
type ListenConfig struct{}
func (*ListenConfig) ListenPacket ¶
func (lc *ListenConfig) ListenPacket(ctx context.Context, derpURL string, key Key) (net.PacketConn, error)
ListenPacket connects to a DERP server URL with the provided private key.
type PacketConn ¶
type PacketConn struct {
// contains filtered or unexported fields
}
PacketConn implements net.PacketConn.
func (*PacketConn) LocalAddr ¶
func (c *PacketConn) LocalAddr() net.Addr
LocalAddr implements net.PacketConn.
func (*PacketConn) SetDeadline ¶
func (*PacketConn) SetDeadline(t time.Time) error
SetDeadline implements net.PacketConn.
func (*PacketConn) SetReadDeadline ¶
func (c *PacketConn) SetReadDeadline(t time.Time) error
SetReadDeadline implements net.PacketConn.
func (*PacketConn) SetWriteDeadline ¶
func (*PacketConn) SetWriteDeadline(t time.Time) error
SetWriteDeadline implements net.PacketConn.