Add the ability to set and use DatagramOptions in a DatagramSession

This commit is contained in:
eyedeekay
2024-11-22 19:16:35 -05:00
parent a22cde30eb
commit fdfa4240fb
4 changed files with 62 additions and 19 deletions

View File

@ -340,7 +340,7 @@ func NewConfig(opts ...func(*I2PConfig) error) (*I2PConfig, error) {
config.SamHost = "127.0.0.1"
config.SamPort = "7656"
config.SamMin = "3.0"
config.SamMax = "3.2"
config.SamMax = "3.3"
config.TunName = ""
config.TunType = "server"
config.Style = "STREAM"

View File

@ -3,6 +3,7 @@ package sam3
import (
"bytes"
"errors"
"fmt"
"net"
"strconv"
"time"
@ -24,11 +25,12 @@ type DatagramSession struct {
keys i2pkeys.I2PKeys // i2p destination keys
rUDPAddr *net.UDPAddr // the SAM bridge UDP-port
remoteAddr *i2pkeys.I2PAddr // optional remote I2P address
*DatagramOptions
}
// Creates a new datagram session. udpPort is the UDP port SAM is listening on,
// and if you set it to zero, it will use SAMs standard UDP port.
func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []string, udpPort int) (*DatagramSession, error) {
func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []string, udpPort int, datagramOptions ...DatagramOptions) (*DatagramSession, error) {
log.WithFields(logrus.Fields{
"id": id,
"udpPort": udpPort,
@ -80,9 +82,11 @@ func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []stri
log.WithError(err).Error("Failed to create generic session")
return nil, err
}
if len(datagramOptions) > 0 {
return &DatagramSession{s.address, id, conn, udpconn, keys, rUDPAddr, nil, &datagramOptions[0]}, nil
}
log.WithField("id", id).Info("DatagramSession created successfully")
return &DatagramSession{s.address, id, conn, udpconn, keys, rUDPAddr, nil}, nil
return &DatagramSession{s.address, id, conn, udpconn, keys, rUDPAddr, nil, nil}, nil
}
func (s *DatagramSession) B32() string {
@ -198,6 +202,9 @@ func (s *DatagramSession) WriteTo(b []byte, addr net.Addr) (n int, err error) {
"addr": addr,
"datagramLen": len(b),
}).Debug("Writing datagram")
if s.DatagramOptions != nil {
return s.WriteToWithOptions(b, addr.(i2pkeys.I2PAddr))
}
header := []byte("3.1 " + s.id + " " + addr.String() + "\n")
msg := append(header, b...)
n, err = s.udpconn.WriteToUDP(msg, s.rUDPAddr)
@ -209,6 +216,35 @@ func (s *DatagramSession) WriteTo(b []byte, addr net.Addr) (n int, err error) {
return n, err
}
type DatagramOptions struct {
SendTags int
TagThreshold int
Expires int
SendLeaseset bool
}
func (s *DatagramSession) WriteToWithOptions(b []byte, addr i2pkeys.I2PAddr) (n int, err error) {
var header bytes.Buffer
header.WriteString(fmt.Sprintf("3.3 %s %s", s.id, addr.String()))
if s.DatagramOptions != nil {
if s.DatagramOptions.SendTags > 0 {
header.WriteString(fmt.Sprintf(" SEND_TAGS=%d", s.DatagramOptions.SendTags))
}
if s.DatagramOptions.TagThreshold > 0 {
header.WriteString(fmt.Sprintf(" TAG_THRESHOLD=%d", s.DatagramOptions.TagThreshold))
}
if s.DatagramOptions.Expires > 0 {
header.WriteString(fmt.Sprintf(" EXPIRES=%d", s.DatagramOptions.Expires))
}
header.WriteString(fmt.Sprintf(" SEND_LEASESET=%v", s.DatagramOptions.SendLeaseset))
}
header.WriteString("\n")
msg := append(header.Bytes(), b...)
return s.udpconn.WriteToUDP(msg, s.rUDPAddr)
}
func (s *DatagramSession) Write(b []byte) (int, error) {
log.WithField("dataLen", len(b)).Debug("Writing to DatagramSession")
return s.WriteTo(b, s.remoteAddr)

View File

@ -372,7 +372,7 @@ func (s *PrimarySession) I2PListener(name string) (*StreamListener, error) {
// Creates a new datagram session. udpPort is the UDP port SAM is listening on,
// and if you set it to zero, it will use SAMs standard UDP port.
func (s *PrimarySession) NewDatagramSubSession(id string, udpPort int) (*DatagramSession, error) {
func (s *PrimarySession) NewDatagramSubSession(id string, udpPort int, datagramOptions ...DatagramOptions) (*DatagramSession, error) {
log.WithFields(logrus.Fields{"id": id, "udpPort": udpPort}).Debug("NewDatagramSubSession called")
if udpPort > 65335 || udpPort < 0 {
log.WithField("udpPort", udpPort).Error("Invalid UDP port")
@ -420,9 +420,17 @@ func (s *PrimarySession) NewDatagramSubSession(id string, udpPort int) (*Datagra
log.WithError(err).Error("Failed to create new generic sub-session")
return nil, err
}
if len(datagramOptions) > 0 {
return &DatagramSession{s.Config.I2PConfig.Sam(), id, conn, udpconn, s.keys, rUDPAddr, nil, &datagramOptions[0]}, nil
}
opts := &DatagramOptions{
SendTags: 0,
TagThreshold: 0,
Expires: 0,
SendLeaseset: false,
}
log.WithFields(logrus.Fields{"id": id, "localPort": lport}).Debug("Created new datagram sub-session")
return &DatagramSession{s.Config.I2PConfig.Sam(), id, conn, udpconn, s.keys, rUDPAddr, nil}, nil
return &DatagramSession{s.Config.I2PConfig.Sam(), id, conn, udpconn, s.keys, rUDPAddr, nil, opts}, nil
}
// Creates a new raw session. udpPort is the UDP port SAM is listening on,

23
raw.go
View File

@ -1,7 +1,6 @@
package sam3
import (
"bytes"
"errors"
"net"
"strconv"
@ -86,29 +85,29 @@ func (s *SAM) NewRawSession(id string, keys i2pkeys.I2PKeys, options []string, u
return &RawSession{s.Config.I2PConfig.Sam(), id, conn, udpconn, keys, rUDPAddr}, nil
}
// Reads one raw datagram sent to the destination of the DatagramSession. Returns
// Read one raw datagram sent to the destination of the DatagramSession. Returns
// 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) {
log.Debug("Attempting to read raw datagram")
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 {
log.WithError(err).Error("Failed to read from UDP")
return 0, err
}
if bytes.Equal(saddr.IP, s.rUDPAddr.IP) {
log.WithField("senderIP", saddr.IP).Debug("Received datagram from SAM bridge IP")
continue
}
break
}
log.WithField("bytesRead", n).Debug("Successfully read raw datagram")
return n, nil
// Verify source is SAM bridge
if saddr.IP.Equal(s.rUDPAddr.IP) && saddr.Port == s.rUDPAddr.Port {
log.WithField("bytesRead", n).Debug("Successfully read raw datagram")
return n, nil
}
// Log unexpected source
log.Printf("Ignored datagram from unauthorized source: %v", saddr)
continue
}
}
// Sends one raw datagram to the destination specified. At the time of writing,