2015-10-15 17:21:11 -04:00
|
|
|
package sam3
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
2024-10-15 22:20:33 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2015-10-15 17:21:11 -04:00
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
2022-03-10 01:01:31 -05:00
|
|
|
"github.com/eyedeekay/i2pkeys"
|
2019-04-09 14:26:27 -04:00
|
|
|
)
|
|
|
|
|
2015-10-15 17:21:11 -04:00
|
|
|
// The RawSession provides no authentication of senders, and there is no sender
|
2016-02-10 17:54:17 -05:00
|
|
|
// address attached to datagrams, so all communication is anonymous. The
|
2015-10-15 17:21:11 -04:00
|
|
|
// messages send are however still endpoint-to-endpoint encrypted. You
|
|
|
|
// need to figure out a way to identify and authenticate clients yourself, iff
|
2016-02-10 17:54:17 -05:00
|
|
|
// that is needed. Raw datagrams may be at most 32 kB in size. There is no
|
2015-10-15 17:21:11 -04:00
|
|
|
// overhead of authentication, which is the reason to use this..
|
|
|
|
type RawSession struct {
|
2019-05-25 14:36:16 -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
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
|
2016-02-10 17:54:17 -05:00
|
|
|
// Creates a new raw 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) NewRawSession(id string, keys i2pkeys.I2PKeys, options []string, udpPort int) (*RawSession, error) {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithFields(logrus.Fields{"id": id, "udpPort": udpPort}).Debug("Creating new RawSession")
|
|
|
|
|
2015-10-15 17:21:11 -04:00
|
|
|
if udpPort > 65335 || udpPort < 0 {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithField("udpPort", udpPort).Error("Invalid UDP port")
|
|
|
|
return nil, errors.New("udpPort needs to be in the interval 0-65335")
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
if udpPort == 0 {
|
|
|
|
udpPort = 7655
|
2024-10-15 22:20:33 -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 22:20:33 -04:00
|
|
|
log.Debug("Using default UDP port 7655")
|
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 22:20:33 -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 22:20:33 -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 22:20:33 -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 22:20:33 -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())
|
2024-01-09 14:20:35 -05:00
|
|
|
if err != nil {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithError(err).Error("Failed to get local port")
|
2024-01-09 14:20:35 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
2015-10-15 17:21:11 -04:00
|
|
|
conn, err := s.newGenericSession("RAW", id, keys, options, []string{"PORT=" + lport})
|
|
|
|
if err != nil {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithError(err).Error("Failed to create new generic session")
|
2015-10-15 17:21:11 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"id": id,
|
|
|
|
"localPort": lport,
|
|
|
|
"remoteUDPAddr": rUDPAddr,
|
2024-10-16 17:21:44 -04:00
|
|
|
}).Debug("Created new RawSession")
|
2024-10-15 22:20:33 -04:00
|
|
|
|
2019-04-10 00:47:41 -04:00
|
|
|
return &RawSession{s.Config.I2PConfig.Sam(), id, conn, udpconn, keys, rUDPAddr}, nil
|
2015-10-15 17:21:11 -04:00
|
|
|
}
|
|
|
|
|
2016-02-10 17:54:17 -05:00
|
|
|
// Reads one raw datagram sent to the destination of the DatagramSession. Returns
|
2015-10-15 17:21:11 -04:00
|
|
|
// the number of bytes read. Who sent the raw message can not be determined at
|
|
|
|
// this layer - you need to do it (in a secure way!).
|
|
|
|
func (s *RawSession) Read(b []byte) (n int, err error) {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.Debug("Attempting to read raw datagram")
|
|
|
|
|
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(b)
|
|
|
|
if err != nil {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithError(err).Error("Failed to read from UDP")
|
2015-10-15 17:21:11 -04:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
if bytes.Equal(saddr.IP, s.rUDPAddr.IP) {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithField("senderIP", saddr.IP).Debug("Received datagram from SAM bridge IP")
|
2015-10-15 17:21:11 -04:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
2024-10-15 22:20:33 -04:00
|
|
|
|
|
|
|
log.WithField("bytesRead", n).Debug("Successfully read raw datagram")
|
2015-10-15 17:21:11 -04:00
|
|
|
return n, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sends one raw datagram to the destination specified. At the time of writing,
|
|
|
|
// maximum size is 32 kilobyte, but this may change in the future.
|
2019-05-25 14:36:16 -04:00
|
|
|
func (s *RawSession) WriteTo(b []byte, addr i2pkeys.I2PAddr) (n int, err error) {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithFields(logrus.Fields{
|
|
|
|
"destAddr": addr.String(),
|
|
|
|
"dataLen": len(b),
|
|
|
|
}).Debug("Attempting to write raw datagram")
|
|
|
|
|
2015-10-15 17:21:11 -04:00
|
|
|
header := []byte("3.0 " + s.id + " " + addr.String() + "\n")
|
|
|
|
msg := append(header, b...)
|
|
|
|
n, err = s.udpconn.WriteToUDP(msg, s.rUDPAddr)
|
2024-10-15 22:20:33 -04:00
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("Failed to write to UDP")
|
|
|
|
}
|
|
|
|
log.WithField("bytesWritten", n).Debug("Successfully wrote raw datagram")
|
2015-10-15 17:21:11 -04:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Closes the RawSession.
|
|
|
|
func (s *RawSession) Close() error {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.Debug("Closing RawSession")
|
|
|
|
|
2015-10-15 17:21:11 -04:00
|
|
|
err := s.conn.Close()
|
|
|
|
if err != nil {
|
2024-10-15 22:20:33 -04:00
|
|
|
log.WithError(err).Error("Failed to close connection")
|
2015-10-15 17:21:11 -04:00
|
|
|
return err
|
|
|
|
}
|
2024-10-15 22:20:33 -04:00
|
|
|
|
|
|
|
err2 := s.udpconn.Close()
|
|
|
|
if err2 != nil {
|
|
|
|
log.WithError(err2).Error("Failed to close UDP connection")
|
|
|
|
}
|
|
|
|
|
2024-10-16 17:21:44 -04:00
|
|
|
log.Debug("RawSession closed")
|
2015-10-15 17:21:11 -04:00
|
|
|
return err2
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the local I2P destination of the RawSession.
|
2019-05-25 14:36:16 -04:00
|
|
|
func (s *RawSession) LocalAddr() i2pkeys.I2PAddr {
|
2015-10-15 17:21:11 -04:00
|
|
|
return s.keys.Addr()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RawSession) SetDeadline(t time.Time) error {
|
|
|
|
return s.udpconn.SetDeadline(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RawSession) SetReadDeadline(t time.Time) error {
|
|
|
|
return s.udpconn.SetReadDeadline(t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *RawSession) SetWriteDeadline(t time.Time) error {
|
|
|
|
return s.udpconn.SetWriteDeadline(t)
|
|
|
|
}
|