2015-10-15 17:21:11 -04:00
|
|
|
package sam3
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
2024-10-15 12:39:20 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2015-10-15 17:21:11 -04:00
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
2019-05-25 14:36:16 -04:00
|
|
|
|
2024-11-09 11:54:54 -05:00
|
|
|
"github.com/go-i2p/i2pkeys"
|
2015-10-15 17:21:11 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// The DatagramSession implements net.PacketConn. It works almost like ordinary
|
|
|
|
// UDP, except that datagrams may be at most 31kB large. These datagrams are
|
2016-02-10 17:54:17 -05:00
|
|
|
// also end-to-end encrypted, signed and includes replay-protection. And they
|
2015-10-15 17:21:11 -04:00
|
|
|
// are also built to be surveillance-resistant (yey!).
|
|
|
|
type DatagramSession struct {
|
2019-06-12 23:32:35 -04:00
|
|
|
samAddr string // address to the sam bridge (ipv4:port)
|
|
|
|
id string // tunnel name
|
|
|
|
conn net.Conn // connection to sam bridge
|
|
|
|
udpconn *net.UDPConn // used to deliver datagrams
|
|
|
|
keys i2pkeys.I2PKeys // i2p destination keys
|
|
|
|
rUDPAddr *net.UDPAddr // the SAM bridge UDP-port
|
|
|
|
remoteAddr *i2pkeys.I2PAddr // optional remote I2P address
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
|
2016-02-10 17:54:17 -05:00
|
|
|
// Creates a new datagram session. udpPort is the UDP port SAM is listening on,
|
2015-10-15 17:21:11 -04:00
|
|
|
// and if you set it to zero, it will use SAMs standard UDP port.
|
2019-05-25 14:36:16 -04:00
|
|
|
func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []string, udpPort int) (*DatagramSession, error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"id": id,
|
|
|
|
"udpPort": udpPort,
|
|
|
|
}).Debug("Creating new DatagramSession")
|
|
|
|
|
2015-10-15 17:21:11 -04:00
|
|
|
if udpPort > 65335 || udpPort < 0 {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("udpPort", udpPort).Error("Invalid UDP port")
|
2015-10-15 17:21:11 -04:00
|
|
|
return nil, errors.New("udpPort needs to be in the intervall 0-65335")
|
|
|
|
}
|
|
|
|
if udpPort == 0 {
|
|
|
|
udpPort = 7655
|
2024-10-15 12:39:20 -04:00
|
|
|
log.Debug("Using default UDP port 7655")
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
2022-05-31 23:59:37 -04:00
|
|
|
lhost, _, err := SplitHostPort(s.conn.LocalAddr().String())
|
2015-10-15 17:21:11 -04:00
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to split local host port")
|
2015-10-15 17:21:11 -04:00
|
|
|
s.Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-02-10 17:54:17 -05:00
|
|
|
lUDPAddr, err := net.ResolveUDPAddr("udp4", lhost+":0")
|
2015-10-15 17:21:11 -04:00
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to resolve local UDP address")
|
2015-10-15 17:21:11 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
udpconn, err := net.ListenUDP("udp4", lUDPAddr)
|
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to listen on UDP")
|
2015-10-15 17:21:11 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
2022-05-31 23:59:37 -04:00
|
|
|
rhost, _, err := SplitHostPort(s.conn.RemoteAddr().String())
|
2015-10-15 17:21:11 -04:00
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to split remote host port")
|
2015-10-15 17:21:11 -04:00
|
|
|
s.Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-02-10 17:54:17 -05:00
|
|
|
rUDPAddr, err := net.ResolveUDPAddr("udp4", rhost+":"+strconv.Itoa(udpPort))
|
2015-10-15 17:21:11 -04:00
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to resolve remote UDP address")
|
2015-10-15 17:21:11 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_, lport, err := net.SplitHostPort(udpconn.LocalAddr().String())
|
2022-01-10 11:19:39 -05:00
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to get local port")
|
2022-01-10 11:19:39 -05:00
|
|
|
s.Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-01-09 13:34:49 -05:00
|
|
|
conn, err := s.newGenericSession("DATAGRAM", id, keys, options, []string{" PORT=" + lport})
|
2015-10-15 17:21:11 -04:00
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to create generic session")
|
2015-10-15 17:21:11 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
2024-10-15 12:39:20 -04:00
|
|
|
|
|
|
|
log.WithField("id", id).Info("DatagramSession created successfully")
|
2019-06-12 23:32:35 -04:00
|
|
|
return &DatagramSession{s.address, id, conn, udpconn, keys, rUDPAddr, nil}, nil
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) B32() string {
|
2024-10-15 12:39:20 -04:00
|
|
|
b32 := s.keys.Addr().Base32()
|
|
|
|
log.WithField("b32", b32).Debug("Generated B32 address")
|
|
|
|
return b32
|
2016-02-17 08:47:01 -05:00
|
|
|
}
|
|
|
|
|
2021-02-27 00:02:04 -05:00
|
|
|
func (s *DatagramSession) Dial(net string, addr string) (*DatagramSession, error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"net": net,
|
|
|
|
"addr": addr,
|
|
|
|
}).Debug("Dialing address")
|
2021-02-27 00:02:04 -05:00
|
|
|
netaddr, err := s.Lookup(addr)
|
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Lookup failed")
|
2021-02-27 00:02:04 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return s.DialI2PRemote(net, netaddr)
|
|
|
|
}
|
|
|
|
|
2021-02-26 15:25:59 -05:00
|
|
|
func (s *DatagramSession) DialRemote(net, addr string) (net.PacketConn, error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"net": net,
|
|
|
|
"addr": addr,
|
|
|
|
}).Debug("Dialing remote address")
|
2021-02-26 15:25:59 -05:00
|
|
|
netaddr, err := s.Lookup(addr)
|
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Lookup failed")
|
2021-02-26 15:25:59 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return s.DialI2PRemote(net, netaddr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *DatagramSession) DialI2PRemote(net string, addr net.Addr) (*DatagramSession, error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"net": net,
|
|
|
|
"addr": addr,
|
|
|
|
}).Debug("Dialing I2P remote address")
|
2021-07-18 15:05:02 -04:00
|
|
|
switch addr.(type) {
|
|
|
|
case *i2pkeys.I2PAddr:
|
|
|
|
s.remoteAddr = addr.(*i2pkeys.I2PAddr)
|
|
|
|
case i2pkeys.I2PAddr:
|
2021-07-18 15:06:49 -04:00
|
|
|
i2paddr := addr.(i2pkeys.I2PAddr)
|
|
|
|
s.remoteAddr = &i2paddr
|
2021-07-18 15:05:02 -04:00
|
|
|
}
|
2021-02-26 15:25:59 -05:00
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
2019-06-12 23:32:35 -04:00
|
|
|
func (s *DatagramSession) RemoteAddr() net.Addr {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("remoteAddr", s.remoteAddr).Debug("Getting remote address")
|
2019-06-12 23:32:35 -04:00
|
|
|
return s.remoteAddr
|
|
|
|
}
|
|
|
|
|
2016-02-10 17:54:17 -05:00
|
|
|
// Reads one datagram sent to the destination of the DatagramSession. Returns
|
2015-10-15 17:21:11 -04:00
|
|
|
// the number of bytes read, from what address it was sent, or an error.
|
2016-02-17 08:47:01 -05:00
|
|
|
// implements net.PacketConn
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.Debug("Reading datagram")
|
2015-10-15 17:21:11 -04:00
|
|
|
// extra bytes to read the remote address of incomming datagram
|
2016-02-10 17:54:17 -05:00
|
|
|
buf := make([]byte, len(b)+4096)
|
|
|
|
|
2015-10-15 17:21:11 -04:00
|
|
|
for {
|
|
|
|
// very basic protection: only accept incomming UDP messages from the IP of the SAM bridge
|
|
|
|
var saddr *net.UDPAddr
|
|
|
|
n, saddr, err = s.udpconn.ReadFromUDP(buf)
|
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to read from UDP")
|
2019-05-25 14:36:16 -04:00
|
|
|
return 0, i2pkeys.I2PAddr(""), err
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
if bytes.Equal(saddr.IP, s.rUDPAddr.IP) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
i := bytes.IndexByte(buf, byte('\n'))
|
|
|
|
if i > 4096 || i > n {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.Error("Could not parse incoming message remote address")
|
2019-05-25 14:36:16 -04:00
|
|
|
return 0, i2pkeys.I2PAddr(""), errors.New("Could not parse incomming message remote address.")
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
2019-05-25 14:36:16 -04:00
|
|
|
raddr, err := i2pkeys.NewI2PAddrFromString(string(buf[:i]))
|
2015-10-15 17:21:11 -04:00
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Could not parse incoming message remote address")
|
2019-05-25 14:36:16 -04:00
|
|
|
return 0, i2pkeys.I2PAddr(""), errors.New("Could not parse incomming message remote address: " + err.Error())
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
// shift out the incomming address to contain only the data received
|
2016-02-10 17:54:17 -05:00
|
|
|
if (n - i + 1) > len(b) {
|
2015-10-15 17:21:11 -04:00
|
|
|
copy(b, buf[i+1:i+1+len(b)])
|
2016-02-10 17:54:17 -05:00
|
|
|
return n - (i + 1), raddr, errors.New("Datagram did not fit into your buffer.")
|
2015-10-15 17:21:11 -04:00
|
|
|
} else {
|
|
|
|
copy(b, buf[i+1:n])
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("bytesRead", n-(i+1)).Debug("Datagram read successfully")
|
2016-02-10 17:54:17 -05:00
|
|
|
return n - (i + 1), raddr, nil
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-18 00:58:45 -04:00
|
|
|
func (s *DatagramSession) Accept() (net.Conn, error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.Debug("Accept called on DatagramSession")
|
2020-10-18 00:58:45 -04:00
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
2019-06-12 23:32:35 -04:00
|
|
|
func (s *DatagramSession) Read(b []byte) (n int, err error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.Debug("Reading from DatagramSession")
|
2019-06-12 23:32:35 -04:00
|
|
|
rint, _, rerr := s.ReadFrom(b)
|
|
|
|
return rint, rerr
|
|
|
|
}
|
|
|
|
|
2016-02-10 17:54:17 -05:00
|
|
|
// Sends one signed datagram to the destination specified. At the time of
|
2015-10-15 17:21:11 -04:00
|
|
|
// writing, maximum size is 31 kilobyte, but this may change in the future.
|
|
|
|
// Implements net.PacketConn.
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"addr": addr,
|
|
|
|
"datagramLen": len(b),
|
|
|
|
}).Debug("Writing datagram")
|
2019-07-29 20:02:43 -04:00
|
|
|
header := []byte("3.1 " + s.id + " " + addr.String() + "\n")
|
2015-10-15 17:21:11 -04:00
|
|
|
msg := append(header, b...)
|
|
|
|
n, err = s.udpconn.WriteToUDP(msg, s.rUDPAddr)
|
2024-10-15 12:39:20 -04:00
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Failed to write to UDP")
|
|
|
|
} else {
|
|
|
|
log.WithField("bytesWritten", n).Debug("Datagram written successfully")
|
|
|
|
}
|
2015-10-15 17:21:11 -04:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
2019-06-12 23:32:35 -04:00
|
|
|
func (s *DatagramSession) Write(b []byte) (int, error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("dataLen", len(b)).Debug("Writing to DatagramSession")
|
2019-06-12 23:32:35 -04:00
|
|
|
return s.WriteTo(b, s.remoteAddr)
|
|
|
|
}
|
|
|
|
|
2015-10-15 17:21:11 -04:00
|
|
|
// Closes the DatagramSession. Implements net.PacketConn
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) Close() error {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.Debug("Closing DatagramSession")
|
2015-10-15 17:21:11 -04:00
|
|
|
err := s.conn.Close()
|
|
|
|
err2 := s.udpconn.Close()
|
|
|
|
if err != nil {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithError(err).Error("Failed to close connection")
|
2015-10-15 17:21:11 -04:00
|
|
|
return err
|
|
|
|
}
|
2024-10-15 12:39:20 -04:00
|
|
|
if err2 != nil {
|
|
|
|
log.WithError(err2).Error("Failed to close UDP connection")
|
|
|
|
}
|
2015-10-15 17:21:11 -04:00
|
|
|
return err2
|
|
|
|
}
|
|
|
|
|
2018-09-09 01:33:24 -04:00
|
|
|
// Returns the I2P destination of the DatagramSession.
|
2019-05-25 14:36:16 -04:00
|
|
|
func (s *DatagramSession) LocalI2PAddr() i2pkeys.I2PAddr {
|
2024-10-15 12:39:20 -04:00
|
|
|
addr := s.keys.Addr()
|
|
|
|
log.WithField("localI2PAddr", addr).Debug("Getting local I2P address")
|
|
|
|
return addr
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
|
2016-02-17 08:47:01 -05:00
|
|
|
// Implements net.PacketConn
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) LocalAddr() net.Addr {
|
2016-02-17 08:47:01 -05:00
|
|
|
return s.LocalI2PAddr()
|
|
|
|
}
|
|
|
|
|
2020-10-18 00:58:45 -04:00
|
|
|
func (s *DatagramSession) Addr() net.Addr {
|
|
|
|
return s.LocalI2PAddr()
|
|
|
|
}
|
|
|
|
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) Lookup(name string) (a net.Addr, err error) {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("name", name).Debug("Looking up address")
|
2016-02-17 08:47:01 -05:00
|
|
|
var sam *SAM
|
|
|
|
sam, err = NewSAM(s.samAddr)
|
|
|
|
if err == nil {
|
|
|
|
defer sam.Close()
|
|
|
|
a, err = sam.Lookup(name)
|
|
|
|
}
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("address", a).Debug("Lookup successful")
|
2016-02-17 08:47:01 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-02-10 17:54:17 -05:00
|
|
|
// Sets read and write deadlines for the DatagramSession. Implements
|
2015-10-15 17:21:11 -04:00
|
|
|
// net.PacketConn and does the same thing. Setting write deadlines for datagrams
|
|
|
|
// is seldom done.
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) SetDeadline(t time.Time) error {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("deadline", t).Debug("Setting deadline")
|
2015-10-15 17:21:11 -04:00
|
|
|
return s.udpconn.SetDeadline(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets read deadline for the DatagramSession. Implements net.PacketConn
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) SetReadDeadline(t time.Time) error {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("readDeadline", t).Debug("Setting read deadline")
|
2015-10-15 17:21:11 -04:00
|
|
|
return s.udpconn.SetReadDeadline(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets the write deadline for the DatagramSession. Implements net.Packetconn.
|
2019-02-09 17:01:29 -05:00
|
|
|
func (s *DatagramSession) SetWriteDeadline(t time.Time) error {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("writeDeadline", t).Debug("Setting write deadline")
|
2015-10-15 17:21:11 -04:00
|
|
|
return s.udpconn.SetWriteDeadline(t)
|
|
|
|
}
|
2019-07-30 14:50:14 -04:00
|
|
|
|
|
|
|
func (s *DatagramSession) SetWriteBuffer(bytes int) error {
|
2024-10-15 12:39:20 -04:00
|
|
|
log.WithField("bytes", bytes).Debug("Setting write buffer")
|
2019-07-30 14:50:14 -04:00
|
|
|
return s.udpconn.SetWriteBuffer(bytes)
|
|
|
|
}
|