mirror of
https://github.com/go-i2p/go-sam-go.git
synced 2025-06-15 21:28:46 -04:00
eliminate a bunch of broken crap and start over from common
This commit is contained in:
11
SAMConn.go
11
SAMConn.go
@ -1,11 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-sam-go/stream"
|
||||
)
|
||||
|
||||
// Implements net.Conn
|
||||
type SAMConn struct {
|
||||
*stream.StreamConn
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -131,99 +130,6 @@ func (sam *SAM) Lookup(name string) (i2pkeys.I2PAddr, error) {
|
||||
return sam.SAMResolver.Resolve(name)
|
||||
}
|
||||
|
||||
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
|
||||
// for a new I2P tunnel with name id, using the cypher keys specified, with the
|
||||
// I2CP/streaminglib-options as specified. Extra arguments can be specified by
|
||||
// setting extra to something else than []string{}.
|
||||
// This sam3 instance is now a session
|
||||
func (sam *SAM) NewGenericSession(style, id string, keys i2pkeys.I2PKeys, extras []string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id}).Debug("Creating new generic session")
|
||||
return sam.NewGenericSessionWithSignature(style, id, keys, SIG_EdDSA_SHA512_Ed25519, extras)
|
||||
}
|
||||
|
||||
func (sam *SAM) NewGenericSessionWithSignature(style, id string, keys i2pkeys.I2PKeys, sigType string, extras []string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id, "sigType": sigType}).Debug("Creating new generic session with signature")
|
||||
return sam.NewGenericSessionWithSignatureAndPorts(style, id, "0", "0", keys, sigType, extras)
|
||||
}
|
||||
|
||||
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
|
||||
// for a new I2P tunnel with name id, using the cypher keys specified, with the
|
||||
// I2CP/streaminglib-options as specified. Extra arguments can be specified by
|
||||
// setting extra to something else than []string{}.
|
||||
// This sam3 instance is now a session
|
||||
func (sam *SAM) NewGenericSessionWithSignatureAndPorts(style, id, from, to string, keys i2pkeys.I2PKeys, sigType string, extras []string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id, "from": from, "to": to, "sigType": sigType}).Debug("Creating new generic session with signature and ports")
|
||||
|
||||
optStr := sam.SamOptionsString()
|
||||
extraStr := strings.Join(extras, " ")
|
||||
|
||||
conn := sam.Conn
|
||||
fp := ""
|
||||
tp := ""
|
||||
if from != "0" {
|
||||
fp = " FROM_PORT=" + from
|
||||
}
|
||||
if to != "0" {
|
||||
tp = " TO_PORT=" + to
|
||||
}
|
||||
scmsg := []byte("SESSION CREATE STYLE=" + style + fp + tp + " ID=" + id + " DESTINATION=" + keys.String() + " " + optStr + extraStr + "\n")
|
||||
|
||||
log.WithField("message", string(scmsg)).Debug("Sending SESSION CREATE message")
|
||||
|
||||
for m, i := 0, 0; m != len(scmsg); i++ {
|
||||
if i == 15 {
|
||||
log.Error("Failed to write SESSION CREATE message after 15 attempts")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("writing to SAM failed")
|
||||
}
|
||||
n, err := conn.Write(scmsg[m:])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write to SAM connection")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("writing to connection failed: %w", err)
|
||||
}
|
||||
m += n
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read SAM response")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("reading from connection failed: %w", err)
|
||||
}
|
||||
text := string(buf[:n])
|
||||
log.WithField("response", text).Debug("Received SAM response")
|
||||
if strings.HasPrefix(text, SESSION_OK) {
|
||||
if keys.String() != text[len(SESSION_OK):len(text)-1] {
|
||||
log.Error("SAM created a tunnel with different keys than requested")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("SAMv3 created a tunnel with keys other than the ones we asked it for")
|
||||
}
|
||||
log.Debug("Successfully created new session")
|
||||
return conn, nil //&StreamSession{id, conn, keys, nil, sync.RWMutex{}, nil}, nil
|
||||
} else if text == SESSION_DUPLICATE_ID {
|
||||
log.Error("Duplicate tunnel name")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Duplicate tunnel name")
|
||||
} else if text == SESSION_DUPLICATE_DEST {
|
||||
log.Error("Duplicate destination")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Duplicate destination")
|
||||
} else if text == SESSION_INVALID_KEY {
|
||||
log.Error("Invalid key for SAM session")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Invalid key - SAM session")
|
||||
} else if strings.HasPrefix(text, SESSION_I2P_ERROR) {
|
||||
log.WithField("error", text[len(SESSION_I2P_ERROR):]).Error("I2P error")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("I2P error " + text[len(SESSION_I2P_ERROR):])
|
||||
} else {
|
||||
log.WithField("reply", text).Error("Unable to parse SAMv3 reply")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Unable to parse SAMv3 reply: " + text)
|
||||
}
|
||||
}
|
||||
|
||||
// close this sam session
|
||||
func (sam *SAM) Close() error {
|
||||
if sam.Conn != nil {
|
||||
|
@ -67,6 +67,7 @@ func NewSAM(address string) (*SAM, error) {
|
||||
|
||||
if err = sendHelloAndValidate(conn, s); err != nil {
|
||||
logger.WithError(err).Error("Failed to send hello and validate SAM connection")
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -75,6 +76,7 @@ func NewSAM(address string) (*SAM, error) {
|
||||
resolver, err := NewSAMResolver(s)
|
||||
if err != nil {
|
||||
logger.WithError(err).Error("Failed to create SAM resolver")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("failed to create SAM resolver: %w", err)
|
||||
}
|
||||
s.SAMResolver = *resolver
|
||||
|
107
common/session.go
Normal file
107
common/session.go
Normal file
@ -0,0 +1,107 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
"github.com/samber/oops"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
|
||||
// for a new I2P tunnel with name id, using the cypher keys specified, with the
|
||||
// I2CP/streaminglib-options as specified. Extra arguments can be specified by
|
||||
// setting extra to something else than []string{}.
|
||||
// This sam3 instance is now a session
|
||||
func (sam SAM) NewGenericSession(style, id string, keys i2pkeys.I2PKeys, extras []string) (Session, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id}).Debug("Creating new generic session")
|
||||
return sam.NewGenericSessionWithSignature(style, id, keys, SIG_EdDSA_SHA512_Ed25519, extras)
|
||||
}
|
||||
|
||||
func (sam SAM) NewGenericSessionWithSignature(style, id string, keys i2pkeys.I2PKeys, sigType string, extras []string) (Session, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id, "sigType": sigType}).Debug("Creating new generic session with signature")
|
||||
return sam.NewGenericSessionWithSignatureAndPorts(style, id, "0", "0", keys, sigType, extras)
|
||||
}
|
||||
|
||||
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
|
||||
// for a new I2P tunnel with name id, using the cypher keys specified, with the
|
||||
// I2CP/streaminglib-options as specified. Extra arguments can be specified by
|
||||
// setting extra to something else than []string{}.
|
||||
// This sam3 instance is now a session
|
||||
func (sam SAM) NewGenericSessionWithSignatureAndPorts(style, id, from, to string, keys i2pkeys.I2PKeys, sigType string, extras []string) (Session, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id, "from": from, "to": to, "sigType": sigType}).Debug("Creating new generic session with signature and ports")
|
||||
|
||||
optStr := sam.SamOptionsString()
|
||||
extraStr := strings.Join(extras, " ")
|
||||
|
||||
conn := sam.Conn
|
||||
fp := ""
|
||||
tp := ""
|
||||
if from != "0" {
|
||||
fp = " FROM_PORT=" + from
|
||||
}
|
||||
if to != "0" {
|
||||
tp = " TO_PORT=" + to
|
||||
}
|
||||
scmsg := []byte("SESSION CREATE STYLE=" + style + fp + tp + " ID=" + id + " DESTINATION=" + keys.String() + " " + optStr + extraStr + "\n")
|
||||
|
||||
log.WithField("message", string(scmsg)).Debug("Sending SESSION CREATE message")
|
||||
|
||||
n, err := conn.Write(scmsg)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write to SAM connection")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("writing to connection failed: %w", err)
|
||||
}
|
||||
if n != len(scmsg) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"written": n,
|
||||
"total": len(scmsg),
|
||||
}).Error("Incomplete write to SAM connection")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("incomplete write to connection")
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read SAM response")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("reading from connection failed: %w", err)
|
||||
}
|
||||
text := string(buf[:n])
|
||||
log.WithField("response", text).Debug("Received SAM response")
|
||||
if strings.HasPrefix(text, SESSION_OK) {
|
||||
if keys.String() != text[len(SESSION_OK):len(text)-1] {
|
||||
log.Error("SAM created a tunnel with different keys than requested")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("SAMv3 created a tunnel with keys other than the ones we asked it for")
|
||||
}
|
||||
log.Debug("Successfully created new session")
|
||||
return &BaseSession{
|
||||
id: id,
|
||||
conn: conn,
|
||||
keys: keys,
|
||||
SAM: sam,
|
||||
}, nil
|
||||
} else if text == SESSION_DUPLICATE_ID {
|
||||
log.Error("Duplicate tunnel name")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Duplicate tunnel name")
|
||||
} else if text == SESSION_DUPLICATE_DEST {
|
||||
log.Error("Duplicate destination")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Duplicate destination")
|
||||
} else if text == SESSION_INVALID_KEY {
|
||||
log.Error("Invalid key for SAM session")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Invalid key - SAM session")
|
||||
} else if strings.HasPrefix(text, SESSION_I2P_ERROR) {
|
||||
log.WithField("error", text[len(SESSION_I2P_ERROR):]).Error("I2P error")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("I2P error " + text[len(SESSION_I2P_ERROR):])
|
||||
} else {
|
||||
log.WithField("reply", text).Error("Unable to parse SAMv3 reply")
|
||||
conn.Close()
|
||||
return nil, oops.Errorf("Unable to parse SAMv3 reply: " + text)
|
||||
}
|
||||
}
|
@ -87,3 +87,46 @@ func (opts Options) AsList() (ls []string) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Session interface {
|
||||
net.Conn
|
||||
ID() string
|
||||
Keys() i2pkeys.I2PKeys
|
||||
Close() error
|
||||
// Add other session methods as needed
|
||||
}
|
||||
|
||||
type BaseSession struct {
|
||||
id string
|
||||
conn net.Conn
|
||||
keys i2pkeys.I2PKeys
|
||||
SAM SAM
|
||||
}
|
||||
|
||||
func (bs *BaseSession) ID() string { return bs.id }
|
||||
func (bs *BaseSession) Keys() i2pkeys.I2PKeys { return bs.keys }
|
||||
func (bs *BaseSession) Read(b []byte) (int, error) { return bs.conn.Read(b) }
|
||||
func (bs *BaseSession) Write(b []byte) (int, error) { return bs.conn.Write(b) }
|
||||
func (bs *BaseSession) Close() error { return bs.conn.Close() }
|
||||
|
||||
func (bs *BaseSession) LocalAddr() net.Addr {
|
||||
return bs.conn.LocalAddr()
|
||||
}
|
||||
func (bs *BaseSession) RemoteAddr() net.Addr {
|
||||
return bs.conn.RemoteAddr()
|
||||
}
|
||||
func (bs *BaseSession) SetDeadline(t time.Time) error {
|
||||
return bs.conn.SetDeadline(t)
|
||||
}
|
||||
func (bs *BaseSession) SetReadDeadline(t time.Time) error {
|
||||
return bs.conn.SetReadDeadline(t)
|
||||
}
|
||||
func (bs *BaseSession) SetWriteDeadline(t time.Time) error {
|
||||
return bs.conn.SetWriteDeadline(t)
|
||||
}
|
||||
func (bs *BaseSession) From() string {
|
||||
return bs.SAM.Fromport
|
||||
}
|
||||
func (bs *BaseSession) To() string {
|
||||
return bs.SAM.Toport
|
||||
}
|
||||
|
63
config.go
63
config.go
@ -1,63 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
)
|
||||
|
||||
// I2PConfig is a struct which manages I2P configuration options
|
||||
type I2PConfig struct {
|
||||
common.I2PConfig
|
||||
}
|
||||
|
||||
func NewConfig(opts ...func(*I2PConfig) error) (*I2PConfig, error) {
|
||||
var config I2PConfig
|
||||
config.SamHost = "127.0.0.1"
|
||||
config.SamPort = 7656
|
||||
config.SamMin = common.DEFAULT_SAM_MIN
|
||||
config.SamMax = common.DEFAULT_SAM_MAX
|
||||
config.TunName = ""
|
||||
config.TunType = "server"
|
||||
config.Style = common.SESSION_STYLE_STREAM
|
||||
config.InLength = 3
|
||||
config.OutLength = 3
|
||||
config.InQuantity = 2
|
||||
config.OutQuantity = 2
|
||||
config.InVariance = 1
|
||||
config.OutVariance = 1
|
||||
config.InBackupQuantity = 3
|
||||
config.OutBackupQuantity = 3
|
||||
config.InAllowZeroHop = false
|
||||
config.OutAllowZeroHop = false
|
||||
config.EncryptLeaseSet = false
|
||||
config.LeaseSetKey = ""
|
||||
config.LeaseSetPrivateKey = ""
|
||||
config.LeaseSetPrivateSigningKey = ""
|
||||
config.FastRecieve = false
|
||||
config.UseCompression = true
|
||||
config.ReduceIdle = false
|
||||
config.ReduceIdleTime = 15
|
||||
config.ReduceIdleQuantity = 4
|
||||
config.CloseIdle = false
|
||||
config.CloseIdleTime = 300000
|
||||
config.MessageReliability = "none"
|
||||
for _, o := range opts {
|
||||
if err := o(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// options map
|
||||
type Options map[string]string
|
||||
|
||||
// obtain sam options as list of strings
|
||||
func (opts Options) AsList() (ls []string) {
|
||||
for k, v := range opts {
|
||||
ls = append(ls, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
return
|
||||
}
|
14
datagram.go
14
datagram.go
@ -1,14 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-sam-go/datagram"
|
||||
)
|
||||
|
||||
// The DatagramSession implements net.PacketConn. It works almost like ordinary
|
||||
// UDP, except that datagrams may be at most 31kB large. These datagrams are
|
||||
// also end-to-end encrypted, signed and includes replay-protection. And they
|
||||
// are also built to be surveillance-resistant (yey!).
|
||||
type DatagramSession struct {
|
||||
datagram.DatagramSession
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package datagram
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"id": id,
|
||||
"udpPort": udpPort,
|
||||
}).Debug("Creating new DatagramSession")
|
||||
|
||||
if udpPort > 65335 || udpPort < 0 {
|
||||
log.WithField("udpPort", udpPort).Error("Invalid UDP port")
|
||||
return nil, errors.New("udpPort needs to be in the intervall 0-65335")
|
||||
}
|
||||
if udpPort == 0 {
|
||||
udpPort = 7655
|
||||
log.Debug("Using default UDP port 7655")
|
||||
}
|
||||
lhost, _, err := common.SplitHostPort(s.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to split local host port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
lUDPAddr, err := net.ResolveUDPAddr("udp4", lhost+":0")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve local UDP address")
|
||||
return nil, err
|
||||
}
|
||||
udpconn, err := net.ListenUDP("udp4", lUDPAddr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to listen on UDP")
|
||||
return nil, err
|
||||
}
|
||||
rhost, _, err := common.SplitHostPort(s.RemoteAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to split remote host port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
rUDPAddr, err := net.ResolveUDPAddr("udp4", rhost+":"+strconv.Itoa(udpPort))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve remote UDP address")
|
||||
return nil, err
|
||||
}
|
||||
_, lport, err := net.SplitHostPort(udpconn.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get local port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
conn, err := s.NewGenericSession("DATAGRAM", id, keys, []string{" PORT=" + lport})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create generic session")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithField("id", id).Info("DatagramSession created successfully")
|
||||
datagramSession := &DatagramSession{
|
||||
SAM: s,
|
||||
UDPConn: udpconn,
|
||||
SAMUDPAddress: rUDPAddr,
|
||||
RemoteI2PAddr: nil,
|
||||
}
|
||||
datagramSession.Conn = conn
|
||||
return datagramSession, nil
|
||||
// return &DatagramSession{s.address, id, conn, udpconn, keys, rUDPAddr, nil}, nil
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package datagram
|
||||
|
||||
import "github.com/go-i2p/logger"
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
@ -1,209 +0,0 @@
|
||||
package datagram
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (s *DatagramSession) B32() string {
|
||||
b32 := s.DestinationKeys.Addr().Base32()
|
||||
log.WithField("b32", b32).Debug("Generated B32 address")
|
||||
return b32
|
||||
}
|
||||
|
||||
func (s *DatagramSession) Dial(net, addr string) (*DatagramSession, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"net": net,
|
||||
"addr": addr,
|
||||
}).Debug("Dialing address")
|
||||
netaddr, err := s.Lookup(addr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Lookup failed")
|
||||
return nil, err
|
||||
}
|
||||
return s.DialI2PRemote(net, netaddr)
|
||||
}
|
||||
|
||||
func (s *DatagramSession) DialRemote(net, addr string) (net.PacketConn, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"net": net,
|
||||
"addr": addr,
|
||||
}).Debug("Dialing remote address")
|
||||
netaddr, err := s.Lookup(addr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Lookup failed")
|
||||
return nil, err
|
||||
}
|
||||
return s.DialI2PRemote(net, netaddr)
|
||||
}
|
||||
|
||||
func (s *DatagramSession) DialI2PRemote(net string, addr net.Addr) (*DatagramSession, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"net": net,
|
||||
"addr": addr,
|
||||
}).Debug("Dialing I2P remote address")
|
||||
switch addr.(type) {
|
||||
case *i2pkeys.I2PAddr:
|
||||
s.RemoteI2PAddr = addr.(*i2pkeys.I2PAddr)
|
||||
case i2pkeys.I2PAddr:
|
||||
i2paddr := addr.(i2pkeys.I2PAddr)
|
||||
s.RemoteI2PAddr = &i2paddr
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *DatagramSession) RemoteAddr() net.Addr {
|
||||
log.WithField("remoteAddr", s.RemoteI2PAddr).Debug("Getting remote address")
|
||||
return s.RemoteI2PAddr
|
||||
}
|
||||
|
||||
// Reads one datagram sent to the destination of the DatagramSession. Returns
|
||||
// the number of bytes read, from what address it was sent, or an error.
|
||||
// implements net.PacketConn
|
||||
func (s *DatagramSession) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
log.Debug("Reading datagram")
|
||||
// extra bytes to read the remote address of incomming datagram
|
||||
buf := make([]byte, len(b)+4096)
|
||||
|
||||
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 {
|
||||
log.WithError(err).Error("Failed to read from UDP")
|
||||
return 0, i2pkeys.I2PAddr(""), err
|
||||
}
|
||||
if bytes.Equal(saddr.IP, s.SAMUDPAddress.IP) {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
i := bytes.IndexByte(buf, byte('\n'))
|
||||
if i > 4096 || i > n {
|
||||
log.Error("Could not parse incoming message remote address")
|
||||
return 0, i2pkeys.I2PAddr(""), errors.New("Could not parse incomming message remote address.")
|
||||
}
|
||||
raddr, err := i2pkeys.NewI2PAddrFromString(string(buf[:i]))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not parse incoming message remote address")
|
||||
return 0, i2pkeys.I2PAddr(""), errors.New("Could not parse incomming message remote address: " + err.Error())
|
||||
}
|
||||
// shift out the incomming address to contain only the data received
|
||||
if (n - i + 1) > len(b) {
|
||||
copy(b, buf[i+1:i+1+len(b)])
|
||||
return n - (i + 1), raddr, errors.New("Datagram did not fit into your buffer.")
|
||||
} else {
|
||||
copy(b, buf[i+1:n])
|
||||
log.WithField("bytesRead", n-(i+1)).Debug("Datagram read successfully")
|
||||
return n - (i + 1), raddr, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DatagramSession) Accept() (net.Conn, error) {
|
||||
log.Debug("Accept called on DatagramSession")
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *DatagramSession) Read(b []byte) (n int, err error) {
|
||||
log.Debug("Reading from DatagramSession")
|
||||
rint, _, rerr := s.ReadFrom(b)
|
||||
return rint, rerr
|
||||
}
|
||||
|
||||
// Sends one signed datagram to the destination specified. At the time of
|
||||
// writing, maximum size is 31 kilobyte, but this may change in the future.
|
||||
// Implements net.PacketConn.
|
||||
func (s *DatagramSession) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"addr": addr,
|
||||
"datagramLen": len(b),
|
||||
}).Debug("Writing datagram")
|
||||
header := []byte("3.1 " + s.ID() + " " + addr.String() + "\n")
|
||||
msg := append(header, b...)
|
||||
n, err = s.UDPConn.WriteToUDP(msg, s.SAMUDPAddress)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write to UDP")
|
||||
} else {
|
||||
log.WithField("bytesWritten", n).Debug("Datagram written successfully")
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (s *DatagramSession) Write(b []byte) (int, error) {
|
||||
log.WithField("dataLen", len(b)).Debug("Writing to DatagramSession")
|
||||
return s.WriteTo(b, s.RemoteI2PAddr)
|
||||
}
|
||||
|
||||
// Closes the DatagramSession. Implements net.PacketConn
|
||||
func (s *DatagramSession) Close() error {
|
||||
log.Debug("Closing DatagramSession")
|
||||
err := s.Conn.Close()
|
||||
err2 := s.UDPConn.Close()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to close connection")
|
||||
return err
|
||||
}
|
||||
if err2 != nil {
|
||||
log.WithError(err2).Error("Failed to close UDP connection")
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
// Returns the I2P destination of the DatagramSession.
|
||||
func (s *DatagramSession) LocalI2PAddr() i2pkeys.I2PAddr {
|
||||
addr := s.DestinationKeys.Addr()
|
||||
log.WithField("localI2PAddr", addr).Debug("Getting local I2P address")
|
||||
return addr
|
||||
}
|
||||
|
||||
// Implements net.PacketConn
|
||||
func (s *DatagramSession) LocalAddr() net.Addr {
|
||||
return s.LocalI2PAddr()
|
||||
}
|
||||
|
||||
func (s *DatagramSession) Addr() net.Addr {
|
||||
return s.LocalI2PAddr()
|
||||
}
|
||||
|
||||
func (s *DatagramSession) Lookup(name string) (a net.Addr, err error) {
|
||||
log.WithField("name", name).Debug("Looking up address")
|
||||
var sam *common.SAM
|
||||
sam, err = common.NewSAM(s.Sam())
|
||||
if err == nil {
|
||||
defer sam.Close()
|
||||
a, err = sam.Lookup(name)
|
||||
}
|
||||
log.WithField("address", a).Debug("Lookup successful")
|
||||
return
|
||||
}
|
||||
|
||||
// Sets read and write deadlines for the DatagramSession. Implements
|
||||
// net.PacketConn and does the same thing. Setting write deadlines for datagrams
|
||||
// is seldom done.
|
||||
func (s *DatagramSession) SetDeadline(t time.Time) error {
|
||||
log.WithField("deadline", t).Debug("Setting deadline")
|
||||
return s.UDPConn.SetDeadline(t)
|
||||
}
|
||||
|
||||
// Sets read deadline for the DatagramSession. Implements net.PacketConn
|
||||
func (s *DatagramSession) SetReadDeadline(t time.Time) error {
|
||||
log.WithField("readDeadline", t).Debug("Setting read deadline")
|
||||
return s.UDPConn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// Sets the write deadline for the DatagramSession. Implements net.Packetconn.
|
||||
func (s *DatagramSession) SetWriteDeadline(t time.Time) error {
|
||||
log.WithField("writeDeadline", t).Debug("Setting write deadline")
|
||||
return s.UDPConn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (s *DatagramSession) SetWriteBuffer(bytes int) error {
|
||||
log.WithField("bytes", bytes).Debug("Setting write buffer")
|
||||
return s.UDPConn.SetWriteBuffer(bytes)
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package datagram
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
)
|
||||
|
||||
type SAM common.SAM
|
||||
|
||||
// The DatagramSession implements net.PacketConn. It works almost like ordinary
|
||||
// UDP, except that datagrams may be at most 31kB large. These datagrams are
|
||||
// also end-to-end encrypted, signed and includes replay-protection. And they
|
||||
// are also built to be surveillance-resistant (yey!).
|
||||
type DatagramSession struct {
|
||||
*SAM
|
||||
UDPConn *net.UDPConn // used to deliver datagrams
|
||||
SAMUDPAddress *net.UDPAddr // the SAM bridge UDP-port
|
||||
RemoteI2PAddr *i2pkeys.I2PAddr // optional remote I2P address
|
||||
}
|
183
datagram_test.go
183
datagram_test.go
@ -1,183 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_DatagramServerClient(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test_DatagramServerClient")
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
// fmt.Println("\tServer: My address: " + keys.Addr().Base32())
|
||||
fmt.Println("\tServer: Creating tunnel")
|
||||
ds, err := sam.NewDatagramSession("DGserverTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
|
||||
if err != nil {
|
||||
fmt.Println("Server: Failed to create tunnel: " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
c, w := make(chan bool), make(chan bool)
|
||||
go func(c, w chan (bool)) {
|
||||
sam2, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer sam2.Close()
|
||||
keys, err := sam2.NewKeys()
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Creating tunnel")
|
||||
ds2, err := sam2.NewDatagramSession("DGclientTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer ds2.Close()
|
||||
// fmt.Println("\tClient: Servers address: " + ds.LocalAddr().Base32())
|
||||
// fmt.Println("\tClient: Clients address: " + ds2.LocalAddr().Base32())
|
||||
fmt.Println("\tClient: Tries to send datagram to server")
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
_, err = ds2.WriteTo([]byte("Hello datagram-world! <3 <3 <3 <3 <3 <3"), ds.LocalAddr())
|
||||
if err != nil {
|
||||
fmt.Println("\tClient: Failed to send datagram: " + err.Error())
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
case <-w:
|
||||
fmt.Println("\tClient: Sent datagram, quitting.")
|
||||
return
|
||||
}
|
||||
}
|
||||
c <- true
|
||||
}(c, w)
|
||||
buf := make([]byte, 512)
|
||||
fmt.Println("\tServer: ReadFrom() waiting...")
|
||||
n, _, err := ds.ReadFrom(buf)
|
||||
w <- true
|
||||
if err != nil {
|
||||
fmt.Println("\tServer: Failed to ReadFrom(): " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tServer: Received datagram: " + string(buf[:n]))
|
||||
// fmt.Println("\tServer: Senders address was: " + saddr.Base32())
|
||||
}
|
||||
|
||||
func ExampleDatagramSession() {
|
||||
// Creates a new DatagramSession, which behaves just like a net.PacketConn.
|
||||
|
||||
const samBridge = "127.0.0.1:7656"
|
||||
|
||||
sam, err := NewSAM(samBridge)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
myself := keys.Addr()
|
||||
|
||||
// See the example Option_* variables.
|
||||
dg, err := sam.NewDatagramSession("DGTUN", keys, Options_Small, 0)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
someone, err := sam.Lookup("zzz.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
dg.WriteTo([]byte("Hello stranger!"), someone)
|
||||
dg.WriteTo([]byte("Hello myself!"), myself)
|
||||
|
||||
buf := make([]byte, 31*1024)
|
||||
n, _, err := dg.ReadFrom(buf)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println("Got message: '" + string(buf[:n]) + "'")
|
||||
fmt.Println("Got message: " + string(buf[:n]))
|
||||
|
||||
return
|
||||
// Output:
|
||||
// Got message: Hello myself!
|
||||
}
|
||||
|
||||
func ExampleMiniDatagramSession() {
|
||||
// Creates a new DatagramSession, which behaves just like a net.PacketConn.
|
||||
|
||||
const samBridge = "127.0.0.1:7656"
|
||||
|
||||
sam, err := NewSAM(samBridge)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
myself := keys.Addr()
|
||||
|
||||
// See the example Option_* variables.
|
||||
dg, err := sam.NewDatagramSession("MINIDGTUN", keys, Options_Small, 0)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
someone, err := sam.Lookup("zzz.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
err = dg.SetWriteBuffer(14 * 1024)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
dg.WriteTo([]byte("Hello stranger!"), someone)
|
||||
dg.WriteTo([]byte("Hello myself!"), myself)
|
||||
|
||||
buf := make([]byte, 31*1024)
|
||||
n, _, err := dg.ReadFrom(buf)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
log.Println("Got message: '" + string(buf[:n]) + "'")
|
||||
fmt.Println("Got message: " + string(buf[:n]))
|
||||
|
||||
return
|
||||
// Output:
|
||||
// Got message: Hello myself!
|
||||
}
|
437
emit-options.go
437
emit-options.go
@ -1,437 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/oops"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Option is a SAMEmit Option
|
||||
type Option func(*SAMEmit) error
|
||||
|
||||
// SetType sets the type of the forwarder server
|
||||
func SetType(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if s == "STREAM" {
|
||||
c.Style = s
|
||||
log.WithField("style", s).Debug("Set session style")
|
||||
return nil
|
||||
} else if s == "DATAGRAM" {
|
||||
c.Style = s
|
||||
log.WithField("style", s).Debug("Set session style")
|
||||
return nil
|
||||
} else if s == "RAW" {
|
||||
c.Style = s
|
||||
log.WithField("style", s).Debug("Set session style")
|
||||
return nil
|
||||
}
|
||||
log.WithField("style", s).Error("Invalid session style")
|
||||
return oops.Errorf("Invalid session STYLE=%s, must be STREAM, DATAGRAM, or RAW", s)
|
||||
}
|
||||
}
|
||||
|
||||
// SetSAMAddress sets the SAM address all-at-once
|
||||
func SetSAMAddress(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
sp := strings.Split(s, ":")
|
||||
if len(sp) > 2 {
|
||||
log.WithField("address", s).Error("Invalid SAM address")
|
||||
return oops.Errorf("Invalid address string: %s", s)
|
||||
}
|
||||
if len(sp) == 2 {
|
||||
port, err := strconv.Atoi(sp[1])
|
||||
if err != nil {
|
||||
log.WithField("port", sp[1]).Error("Invalid SAM port: non-number")
|
||||
return oops.Errorf("Invalid SAM port %s; non-number", sp[1])
|
||||
}
|
||||
c.I2PConfig.SamPort = port
|
||||
}
|
||||
c.I2PConfig.SamHost = sp[0]
|
||||
log.WithFields(logrus.Fields{
|
||||
"host": c.I2PConfig.SamHost,
|
||||
"port": c.I2PConfig.SamPort,
|
||||
}).Debug("Set SAM address")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetSAMHost sets the host of the SAMEmit's SAM bridge
|
||||
func SetSAMHost(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.SamHost = s
|
||||
log.WithField("host", s).Debug("Set SAM host")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetSAMPort sets the port of the SAMEmit's SAM bridge using a string
|
||||
func SetSAMPort(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
port, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
log.WithField("port", s).Error("Invalid SAM port: non-number")
|
||||
return oops.Errorf("Invalid SAM port %s; non-number", s)
|
||||
}
|
||||
if port < 65536 && port > -1 {
|
||||
c.I2PConfig.SamPort = port
|
||||
log.WithField("port", s).Debug("Set SAM port")
|
||||
return nil
|
||||
}
|
||||
log.WithField("port", port).Error("Invalid SAM port")
|
||||
return oops.Errorf("Invalid SAM port: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetName sets the host of the SAMEmit's SAM bridge
|
||||
func SetName(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.TunName = s
|
||||
log.WithField("name", s).Debug("Set tunnel name")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetInLength sets the number of hops inbound
|
||||
func SetInLength(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if u < 7 && u >= 0 {
|
||||
c.I2PConfig.InLength = u
|
||||
log.WithField("inLength", u).Debug("Set inbound tunnel length")
|
||||
return nil
|
||||
}
|
||||
log.WithField("inLength", u).Error("Invalid inbound tunnel length")
|
||||
return oops.Errorf("Invalid inbound tunnel length: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetOutLength sets the number of hops outbound
|
||||
func SetOutLength(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if u < 7 && u >= 0 {
|
||||
c.I2PConfig.OutLength = u
|
||||
log.WithField("outLength", u).Debug("Set outbound tunnel length")
|
||||
return nil
|
||||
}
|
||||
log.WithField("outLength", u).Error("Invalid outbound tunnel length")
|
||||
return oops.Errorf("Invalid outbound tunnel length: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetInVariance sets the variance of a number of hops inbound
|
||||
func SetInVariance(i int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if i < 7 && i > -7 {
|
||||
c.I2PConfig.InVariance = i
|
||||
log.WithField("inVariance", i).Debug("Set inbound tunnel variance")
|
||||
return nil
|
||||
}
|
||||
log.WithField("inVariance", i).Error("Invalid inbound tunnel variance")
|
||||
return oops.Errorf("Invalid inbound tunnel variance: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetOutVariance sets the variance of a number of hops outbound
|
||||
func SetOutVariance(i int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if i < 7 && i > -7 {
|
||||
c.I2PConfig.OutVariance = i
|
||||
log.WithField("outVariance", i).Debug("Set outbound tunnel variance")
|
||||
return nil
|
||||
}
|
||||
log.WithField("outVariance", i).Error("Invalid outbound tunnel variance")
|
||||
return oops.Errorf("Invalid outbound tunnel variance: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetInQuantity sets the inbound tunnel quantity
|
||||
func SetInQuantity(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if u <= 16 && u > 0 {
|
||||
c.I2PConfig.InQuantity = u
|
||||
log.WithField("inQuantity", u).Debug("Set inbound tunnel quantity")
|
||||
return nil
|
||||
}
|
||||
log.WithField("inQuantity", u).Error("Invalid inbound tunnel quantity")
|
||||
return oops.Errorf("Invalid inbound tunnel quantity: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetOutQuantity sets the outbound tunnel quantity
|
||||
func SetOutQuantity(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if u <= 16 && u > 0 {
|
||||
c.I2PConfig.OutQuantity = u
|
||||
log.WithField("outQuantity", u).Debug("Set outbound tunnel quantity")
|
||||
return nil
|
||||
}
|
||||
log.WithField("outQuantity", u).Error("Invalid outbound tunnel quantity")
|
||||
return oops.Errorf("Invalid outbound tunnel quantity: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetInBackups sets the inbound tunnel backups
|
||||
func SetInBackups(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if u < 6 && u >= 0 {
|
||||
c.I2PConfig.InBackupQuantity = u
|
||||
log.WithField("inBackups", u).Debug("Set inbound tunnel backups")
|
||||
return nil
|
||||
}
|
||||
log.WithField("inBackups", u).Error("Invalid inbound tunnel backup quantity")
|
||||
return oops.Errorf("Invalid inbound tunnel backup quantity: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetOutBackups sets the inbound tunnel backups
|
||||
func SetOutBackups(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if u < 6 && u >= 0 {
|
||||
c.I2PConfig.OutBackupQuantity = u
|
||||
log.WithField("outBackups", u).Debug("Set outbound tunnel backups")
|
||||
return nil
|
||||
}
|
||||
log.WithField("outBackups", u).Error("Invalid outbound tunnel backup quantity")
|
||||
return oops.Errorf("Invalid outbound tunnel backup quantity: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetEncrypt tells the router to use an encrypted leaseset
|
||||
func SetEncrypt(b bool) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if b {
|
||||
c.I2PConfig.EncryptLeaseSet = true
|
||||
return nil
|
||||
}
|
||||
c.I2PConfig.EncryptLeaseSet = false
|
||||
log.WithField("encrypt", b).Debug("Set lease set encryption")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetLeaseSetKey sets the host of the SAMEmit's SAM bridge
|
||||
func SetLeaseSetKey(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.LeaseSetKey = s
|
||||
log.WithField("leaseSetKey", s).Debug("Set lease set key")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetLeaseSetPrivateKey sets the host of the SAMEmit's SAM bridge
|
||||
func SetLeaseSetPrivateKey(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.LeaseSetPrivateKey = s
|
||||
log.WithField("leaseSetPrivateKey", s).Debug("Set lease set private key")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetLeaseSetPrivateSigningKey sets the host of the SAMEmit's SAM bridge
|
||||
func SetLeaseSetPrivateSigningKey(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.LeaseSetPrivateSigningKey = s
|
||||
log.WithField("leaseSetPrivateSigningKey", s).Debug("Set lease set private signing key")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetMessageReliability sets the host of the SAMEmit's SAM bridge
|
||||
func SetMessageReliability(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.MessageReliability = s
|
||||
log.WithField("messageReliability", s).Debug("Set message reliability")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetAllowZeroIn tells the tunnel to accept zero-hop peers
|
||||
func SetAllowZeroIn(b bool) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if b {
|
||||
c.I2PConfig.InAllowZeroHop = true
|
||||
return nil
|
||||
}
|
||||
c.I2PConfig.InAllowZeroHop = false
|
||||
log.WithField("allowZeroIn", b).Debug("Set allow zero-hop inbound")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetAllowZeroOut tells the tunnel to accept zero-hop peers
|
||||
func SetAllowZeroOut(b bool) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if b {
|
||||
c.I2PConfig.OutAllowZeroHop = true
|
||||
return nil
|
||||
}
|
||||
c.I2PConfig.OutAllowZeroHop = false
|
||||
log.WithField("allowZeroOut", b).Debug("Set allow zero-hop outbound")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetCompress tells clients to use compression
|
||||
func SetCompress(b bool) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if b {
|
||||
c.I2PConfig.UseCompression = true
|
||||
return nil
|
||||
}
|
||||
c.I2PConfig.UseCompression = false
|
||||
log.WithField("compress", b).Debug("Set compression")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetFastRecieve tells clients to use compression
|
||||
func SetFastRecieve(b bool) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if b {
|
||||
c.I2PConfig.FastRecieve = true
|
||||
return nil
|
||||
}
|
||||
c.I2PConfig.FastRecieve = false
|
||||
log.WithField("fastReceive", b).Debug("Set fast receive")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetReduceIdle tells the connection to reduce it's tunnels during extended idle time.
|
||||
func SetReduceIdle(b bool) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if b {
|
||||
c.I2PConfig.ReduceIdle = true
|
||||
return nil
|
||||
}
|
||||
c.I2PConfig.ReduceIdle = false
|
||||
log.WithField("reduceIdle", b).Debug("Set reduce idle")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetReduceIdleTime sets the time to wait before reducing tunnels to idle levels
|
||||
func SetReduceIdleTime(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.ReduceIdleTime = 300000
|
||||
if u >= 6 {
|
||||
idleTime := (u * 60) * 1000
|
||||
c.I2PConfig.ReduceIdleTime = idleTime
|
||||
log.WithField("reduceIdleTime", idleTime).Debug("Set reduce idle time")
|
||||
return nil
|
||||
}
|
||||
log.WithField("minutes", u).Error("Invalid reduce idle timeout")
|
||||
return oops.Errorf("Invalid reduce idle timeout (Measured in minutes) %v", u)
|
||||
}
|
||||
}
|
||||
|
||||
// SetReduceIdleTimeMs sets the time to wait before reducing tunnels to idle levels in milliseconds
|
||||
func SetReduceIdleTimeMs(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.ReduceIdleTime = 300000
|
||||
if u >= 300000 {
|
||||
c.I2PConfig.ReduceIdleTime = u
|
||||
log.WithField("reduceIdleTimeMs", u).Debug("Set reduce idle time in milliseconds")
|
||||
return nil
|
||||
}
|
||||
log.WithField("milliseconds", u).Error("Invalid reduce idle timeout")
|
||||
return oops.Errorf("Invalid reduce idle timeout (Measured in milliseconds) %v", u)
|
||||
}
|
||||
}
|
||||
|
||||
// SetReduceIdleQuantity sets minimum number of tunnels to reduce to during idle time
|
||||
func SetReduceIdleQuantity(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if u < 5 {
|
||||
c.I2PConfig.ReduceIdleQuantity = u
|
||||
log.WithField("reduceIdleQuantity", u).Debug("Set reduce idle quantity")
|
||||
return nil
|
||||
}
|
||||
log.WithField("quantity", u).Error("Invalid reduce tunnel quantity")
|
||||
return oops.Errorf("Invalid reduce idle tunnel quantity: out of range")
|
||||
}
|
||||
}
|
||||
|
||||
// SetCloseIdle tells the connection to close it's tunnels during extended idle time.
|
||||
func SetCloseIdle(b bool) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if b {
|
||||
c.I2PConfig.CloseIdle = true
|
||||
return nil
|
||||
}
|
||||
c.I2PConfig.CloseIdle = false
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SetCloseIdleTime sets the time to wait before closing tunnels to idle levels
|
||||
func SetCloseIdleTime(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.CloseIdleTime = 300000
|
||||
if u >= 6 {
|
||||
idleTime := (u * 60) * 1000
|
||||
c.I2PConfig.CloseIdleTime = idleTime
|
||||
log.WithFields(logrus.Fields{
|
||||
"minutes": u,
|
||||
"milliseconds": idleTime,
|
||||
}).Debug("Set close idle time")
|
||||
return nil
|
||||
}
|
||||
log.WithField("minutes", u).Error("Invalid close idle timeout")
|
||||
return oops.Errorf("Invalid close idle timeout (Measured in minutes) %v", u)
|
||||
}
|
||||
}
|
||||
|
||||
// SetCloseIdleTimeMs sets the time to wait before closing tunnels to idle levels in milliseconds
|
||||
func SetCloseIdleTimeMs(u int) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
c.I2PConfig.CloseIdleTime = 300000
|
||||
if u >= 300000 {
|
||||
c.I2PConfig.CloseIdleTime = u
|
||||
log.WithField("closeIdleTimeMs", u).Debug("Set close idle time in milliseconds")
|
||||
return nil
|
||||
}
|
||||
return oops.Errorf("Invalid close idle timeout (Measured in milliseconds) %v", u)
|
||||
}
|
||||
}
|
||||
|
||||
// SetAccessListType tells the system to treat the AccessList as a whitelist
|
||||
func SetAccessListType(s string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if s == "whitelist" {
|
||||
c.I2PConfig.AccessListType = "whitelist"
|
||||
log.Debug("Set access list type to whitelist")
|
||||
return nil
|
||||
} else if s == "blacklist" {
|
||||
c.I2PConfig.AccessListType = "blacklist"
|
||||
log.Debug("Set access list type to blacklist")
|
||||
return nil
|
||||
} else if s == "none" {
|
||||
c.I2PConfig.AccessListType = ""
|
||||
log.Debug("Set access list type to none")
|
||||
return nil
|
||||
} else if s == "" {
|
||||
c.I2PConfig.AccessListType = ""
|
||||
log.Debug("Set access list type to none")
|
||||
return nil
|
||||
}
|
||||
return oops.Errorf("Invalid Access list type (whitelist, blacklist, none)")
|
||||
}
|
||||
}
|
||||
|
||||
// SetAccessList tells the system to treat the AccessList as a whitelist
|
||||
func SetAccessList(s []string) func(*SAMEmit) error {
|
||||
return func(c *SAMEmit) error {
|
||||
if len(s) > 0 {
|
||||
for _, a := range s {
|
||||
c.I2PConfig.AccessList = append(c.I2PConfig.AccessList, a)
|
||||
}
|
||||
log.WithField("accessList", s).Debug("Set access list")
|
||||
return nil
|
||||
}
|
||||
log.Debug("No access list set (empty list provided)")
|
||||
return nil
|
||||
}
|
||||
}
|
142
emit.go
142
emit.go
@ -1,142 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type SAMEmit struct {
|
||||
common.SAMEmit
|
||||
}
|
||||
|
||||
func (e *SAMEmit) SamOptionsString() string {
|
||||
optStr := strings.Join(e.I2PConfig.Print(), " ")
|
||||
log.WithField("optStr", optStr).Debug("Generated option string")
|
||||
return optStr
|
||||
}
|
||||
|
||||
func (e *SAMEmit) Hello() string {
|
||||
hello := fmt.Sprintf("HELLO VERSION MIN=%s MAX=%s \n", e.I2PConfig.MinSAM(), e.I2PConfig.MaxSAM())
|
||||
log.WithField("hello", hello).Debug("Generated HELLO command")
|
||||
return hello
|
||||
}
|
||||
|
||||
func (e *SAMEmit) HelloBytes() []byte {
|
||||
return []byte(e.Hello())
|
||||
}
|
||||
|
||||
func (e *SAMEmit) GenerateDestination() string {
|
||||
dest := fmt.Sprintf("DEST GENERATE %s \n", e.I2PConfig.SignatureType())
|
||||
log.WithField("destination", dest).Debug("Generated DEST GENERATE command")
|
||||
return dest
|
||||
}
|
||||
|
||||
func (e *SAMEmit) GenerateDestinationBytes() []byte {
|
||||
return []byte(e.GenerateDestination())
|
||||
}
|
||||
|
||||
func (e *SAMEmit) Lookup(name string) string {
|
||||
lookup := fmt.Sprintf("NAMING LOOKUP NAME=%s \n", name)
|
||||
log.WithField("lookup", lookup).Debug("Generated NAMING LOOKUP command")
|
||||
return lookup
|
||||
}
|
||||
|
||||
func (e *SAMEmit) LookupBytes(name string) []byte {
|
||||
return []byte(e.Lookup(name))
|
||||
}
|
||||
|
||||
func (e *SAMEmit) Create() string {
|
||||
create := fmt.Sprintf(
|
||||
// //1 2 3 4 5 6 7
|
||||
"SESSION CREATE %s%s%s%s%s%s%s \n",
|
||||
e.I2PConfig.SessionStyle(), // 1
|
||||
e.I2PConfig.FromPort(), // 2
|
||||
e.I2PConfig.ToPort(), // 3
|
||||
e.I2PConfig.ID(), // 4
|
||||
e.I2PConfig.DestinationKey(), // 5
|
||||
e.I2PConfig.SignatureType(), // 6
|
||||
e.SamOptionsString(), // 7
|
||||
)
|
||||
log.WithField("create", create).Debug("Generated SESSION CREATE command")
|
||||
return create
|
||||
}
|
||||
|
||||
func (e *SAMEmit) CreateBytes() []byte {
|
||||
fmt.Println("sam command: " + e.Create())
|
||||
return []byte(e.Create())
|
||||
}
|
||||
|
||||
func (e *SAMEmit) Connect(dest string) string {
|
||||
connect := fmt.Sprintf(
|
||||
"STREAM CONNECT ID=%s %s %s DESTINATION=%s \n",
|
||||
e.I2PConfig.ID(),
|
||||
e.I2PConfig.FromPort(),
|
||||
e.I2PConfig.ToPort(),
|
||||
dest,
|
||||
)
|
||||
log.WithField("connect", connect).Debug("Generated STREAM CONNECT command")
|
||||
return connect
|
||||
}
|
||||
|
||||
func (e *SAMEmit) ConnectBytes(dest string) []byte {
|
||||
return []byte(e.Connect(dest))
|
||||
}
|
||||
|
||||
func (e *SAMEmit) Accept() string {
|
||||
accept := fmt.Sprintf(
|
||||
"STREAM ACCEPT ID=%s %s %s",
|
||||
e.I2PConfig.ID(),
|
||||
e.I2PConfig.FromPort(),
|
||||
e.I2PConfig.ToPort(),
|
||||
)
|
||||
log.WithField("accept", accept).Debug("Generated STREAM ACCEPT command")
|
||||
return accept
|
||||
}
|
||||
|
||||
func (e *SAMEmit) AcceptBytes() []byte {
|
||||
return []byte(e.Accept())
|
||||
}
|
||||
|
||||
func NewEmit(opts ...func(*SAMEmit) error) (*SAMEmit, error) {
|
||||
var emit SAMEmit
|
||||
for _, o := range opts {
|
||||
if err := o(&emit); err != nil {
|
||||
log.WithError(err).Error("Failed to apply option")
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
log.Debug("New SAMEmit instance created")
|
||||
return &emit, nil
|
||||
}
|
||||
|
||||
func IgnorePortError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(err.Error(), "missing port in address") {
|
||||
log.Debug("Ignoring 'missing port in address' error")
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SplitHostPort(hostport string) (string, string, error) {
|
||||
host, port, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
if IgnorePortError(err) == nil {
|
||||
log.WithField("host", hostport).Debug("Using full string as host, port set to 0")
|
||||
host = hostport
|
||||
port = "0"
|
||||
}
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"host": host,
|
||||
"port": port,
|
||||
}).Debug("Split host and port")
|
||||
return host, port, nil
|
||||
}
|
7
log.go
7
log.go
@ -1,7 +0,0 @@
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/logger"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
28
primary.go
28
primary.go
@ -1,28 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-sam-go/primary"
|
||||
)
|
||||
|
||||
const (
|
||||
session_ADDOK = "SESSION STATUS RESULT=OK"
|
||||
)
|
||||
|
||||
// Represents a primary session.
|
||||
type PrimarySession struct {
|
||||
*primary.PrimarySession
|
||||
}
|
||||
|
||||
var PrimarySessionSwitch = "MASTER"
|
||||
|
||||
func (p *PrimarySession) NewStreamSubSession(id string) (*StreamSession, error) {
|
||||
log.WithField("id", id).Debug("NewStreamSubSession called")
|
||||
session, err := p.PrimarySession.NewStreamSubSession(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &StreamSession{
|
||||
StreamSession: session,
|
||||
}, nil
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package primary
|
||||
|
||||
const SESSION_ADDOK = "SESSION STATUS RESULT=OK"
|
@ -1,73 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/go-sam-go/datagram"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// 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) (*datagram.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")
|
||||
return nil, errors.New("udpPort needs to be in the intervall 0-65335")
|
||||
}
|
||||
if udpPort == 0 {
|
||||
udpPort = 7655
|
||||
log.Debug("Using default UDP port 7655")
|
||||
}
|
||||
lhost, _, err := common.SplitHostPort(s.conn.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to split local host port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
lUDPAddr, err := net.ResolveUDPAddr("udp4", lhost+":0")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve local UDP address")
|
||||
return nil, err
|
||||
}
|
||||
udpconn, err := net.ListenUDP("udp4", lUDPAddr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to listen on UDP")
|
||||
return nil, err
|
||||
}
|
||||
rhost, _, err := common.SplitHostPort(s.conn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to split remote host port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
rUDPAddr, err := net.ResolveUDPAddr("udp4", rhost+":"+strconv.Itoa(udpPort))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve remote UDP address")
|
||||
return nil, err
|
||||
}
|
||||
_, lport, err := net.SplitHostPort(udpconn.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get local port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
conn, err := s.NewGenericSubSession("DATAGRAM", id, []string{"PORT=" + lport})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic sub-session")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{"id": id, "localPort": lport}).Debug("Created new datagram sub-session")
|
||||
datagramSession := &datagram.DatagramSession{
|
||||
SAM: (*datagram.SAM)(s.SAM),
|
||||
SAMUDPAddress: rUDPAddr,
|
||||
UDPConn: udpconn,
|
||||
RemoteI2PAddr: nil,
|
||||
}
|
||||
datagramSession.Conn = conn
|
||||
return datagramSession, nil
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/go-sam-go/datagram"
|
||||
"github.com/samber/oops"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (sam *PrimarySession) Dial(network, addr string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"network": network, "addr": addr}).Debug("Dial() called")
|
||||
if network == "udp" || network == "udp4" || network == "udp6" {
|
||||
// return sam.DialUDPI2P(network, network+addr[0:4], addr)
|
||||
return sam.DialUDPI2P(network, network+addr[0:4], addr)
|
||||
}
|
||||
if network == "tcp" || network == "tcp4" || network == "tcp6" {
|
||||
// return sam.DialTCPI2P(network, network+addr[0:4], addr)
|
||||
return sam.DialTCPI2P(network, network+addr[0:4], addr)
|
||||
}
|
||||
log.WithField("network", network).Error("Invalid network type")
|
||||
return nil, oops.Errorf("Error: Must specify a valid network type")
|
||||
}
|
||||
|
||||
// DialTCP implements x/dialer
|
||||
func (sam *PrimarySession) DialTCP(network string, laddr, raddr net.Addr) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"network": network, "laddr": laddr, "raddr": raddr}).Debug("DialTCP() called")
|
||||
ts, ok := sam.stsess[network+raddr.String()[0:4]]
|
||||
var err error
|
||||
if !ok {
|
||||
ts, err = sam.NewUniqueStreamSubSession(network + raddr.String()[0:4])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new unique stream sub-session")
|
||||
return nil, err
|
||||
}
|
||||
sam.stsess[network+raddr.String()[0:4]] = ts
|
||||
ts, _ = sam.stsess[network+raddr.String()[0:4]]
|
||||
}
|
||||
return ts.Dial(network, raddr.String())
|
||||
}
|
||||
|
||||
func (sam *PrimarySession) DialTCPI2P(network, laddr, raddr string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"network": network, "laddr": laddr, "raddr": raddr}).Debug("DialTCPI2P() called")
|
||||
ts, ok := sam.stsess[network+raddr[0:4]]
|
||||
var err error
|
||||
if !ok {
|
||||
ts, err = sam.NewUniqueStreamSubSession(network + laddr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new unique stream sub-session")
|
||||
return nil, err
|
||||
}
|
||||
sam.stsess[network+raddr[0:4]] = ts
|
||||
ts, _ = sam.stsess[network+raddr[0:4]]
|
||||
}
|
||||
return ts.Dial(network, raddr)
|
||||
}
|
||||
|
||||
// DialUDP implements x/dialer
|
||||
func (sam *PrimarySession) DialUDP(network string, laddr, raddr net.Addr) (net.PacketConn, error) {
|
||||
log.WithFields(logrus.Fields{"network": network, "laddr": laddr, "raddr": raddr}).Debug("DialUDP() called")
|
||||
ds, ok := sam.dgsess[network+raddr.String()[0:4]]
|
||||
var err error
|
||||
if !ok {
|
||||
ds, err = sam.NewDatagramSubSession(network+raddr.String()[0:4], 0)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new datagram sub-session")
|
||||
return nil, err
|
||||
}
|
||||
sam.dgsess[network+raddr.String()[0:4]] = ds
|
||||
ds, _ = sam.dgsess[network+raddr.String()[0:4]]
|
||||
}
|
||||
return ds.Dial(network, raddr.String())
|
||||
}
|
||||
|
||||
func (sam *PrimarySession) DialUDPI2P(network, laddr, raddr string) (*datagram.DatagramSession, error) {
|
||||
log.WithFields(logrus.Fields{"network": network, "laddr": laddr, "raddr": raddr}).Debug("DialUDPI2P() called")
|
||||
ds, ok := sam.dgsess[network+raddr[0:4]]
|
||||
var err error
|
||||
if !ok {
|
||||
ds, err = sam.NewDatagramSubSession(network+laddr, 0)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new datagram sub-session")
|
||||
return nil, err
|
||||
}
|
||||
sam.dgsess[network+raddr[0:4]] = ds
|
||||
ds, _ = sam.dgsess[network+raddr[0:4]]
|
||||
}
|
||||
return ds.Dial(network, raddr)
|
||||
}
|
||||
|
||||
func (s *PrimarySession) Lookup(name string) (a net.Addr, err error) {
|
||||
log.WithField("name", name).Debug("Lookup() called")
|
||||
var sam *common.SAM
|
||||
name = strings.Split(name, ":")[0]
|
||||
sam, err = common.NewSAM(s.samAddr)
|
||||
if err == nil {
|
||||
log.WithField("addr", a).Debug("Lookup successful")
|
||||
defer sam.Close()
|
||||
a, err = sam.Lookup(name)
|
||||
}
|
||||
log.WithError(err).Error("Lookup failed")
|
||||
return
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
)
|
||||
|
||||
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
|
||||
// for a new I2P tunnel with name id, using the cypher keys specified, with the
|
||||
// I2CP/streaminglib-options as specified. Extra arguments can be specified by
|
||||
// setting extra to something else than []string{}.
|
||||
// This sam3 instance is now a session
|
||||
func (sam *PrimarySession) NewGenericSubSession(style, id string, extras []string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id, "extras": extras}).Debug("newGenericSubSession called")
|
||||
return sam.NewGenericSubSessionWithSignature(style, id, extras)
|
||||
}
|
||||
|
||||
func (sam *PrimarySession) NewGenericSubSessionWithSignature(style, id string, extras []string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id, "extras": extras}).Debug("newGenericSubSessionWithSignature called")
|
||||
return sam.NewGenericSubSessionWithSignatureAndPorts(style, id, "0", "0", extras)
|
||||
}
|
||||
|
||||
// Creates a new session with the style of either "STREAM", "DATAGRAM" or "RAW",
|
||||
// for a new I2P tunnel with name id, using the cypher keys specified, with the
|
||||
// I2CP/streaminglib-options as specified. Extra arguments can be specified by
|
||||
// setting extra to something else than []string{}.
|
||||
// This sam3 instance is now a session
|
||||
func (sam *PrimarySession) NewGenericSubSessionWithSignatureAndPorts(style, id, from, to string, extras []string) (net.Conn, error) {
|
||||
log.WithFields(logrus.Fields{"style": style, "id": id, "from": from, "to": to, "extras": extras}).Debug("newGenericSubSessionWithSignatureAndPorts called")
|
||||
|
||||
conn := sam.conn
|
||||
fp := ""
|
||||
tp := ""
|
||||
if from != "0" && from != "" {
|
||||
fp = " FROM_PORT=" + from
|
||||
}
|
||||
if to != "0" && to != "" {
|
||||
tp = " TO_PORT=" + to
|
||||
}
|
||||
scmsg := []byte("SESSION ADD STYLE=" + style + " ID=" + id + fp + tp + " " + strings.Join(extras, " ") + "\n")
|
||||
|
||||
log.WithField("message", string(scmsg)).Debug("Sending SESSION ADD message")
|
||||
|
||||
for m, i := 0, 0; m != len(scmsg); i++ {
|
||||
if i == 15 {
|
||||
conn.Close()
|
||||
log.Error("Writing to SAM failed after 15 attempts")
|
||||
return nil, errors.New("writing to SAM failed")
|
||||
}
|
||||
n, err := conn.Write(scmsg[m:])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write to SAM connection")
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
m += n
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read from SAM connection")
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
text := string(buf[:n])
|
||||
log.WithField("response", text).Debug("Received response from SAM")
|
||||
// log.Println("SAM:", text)
|
||||
if strings.HasPrefix(text, SESSION_ADDOK) {
|
||||
//if sam.keys.String() != text[len(common.SESSION_ADDOK):len(text)-1] {
|
||||
//conn.Close()
|
||||
//return nil, errors.New("SAMv3 created a tunnel with keys other than the ones we asked it for")
|
||||
//}
|
||||
log.Debug("Session added successfully")
|
||||
return conn, nil //&StreamSession{id, conn, keys, nil, sync.RWMutex{}, nil}, nil
|
||||
} else if text == common.SESSION_DUPLICATE_ID {
|
||||
log.Error("Duplicate tunnel name")
|
||||
conn.Close()
|
||||
return nil, errors.New("Duplicate tunnel name")
|
||||
} else if text == common.SESSION_DUPLICATE_DEST {
|
||||
log.Error("Duplicate destination")
|
||||
conn.Close()
|
||||
return nil, errors.New("Duplicate destination")
|
||||
} else if text == common.SESSION_INVALID_KEY {
|
||||
log.Error("Invalid key - Primary Session")
|
||||
conn.Close()
|
||||
return nil, errors.New("Invalid key - Primary Session")
|
||||
} else if strings.HasPrefix(text, common.SESSION_I2P_ERROR) {
|
||||
log.WithField("error", text[len(common.SESSION_I2P_ERROR):]).Error("I2P error")
|
||||
conn.Close()
|
||||
return nil, errors.New("I2P error " + text[len(common.SESSION_I2P_ERROR):])
|
||||
} else {
|
||||
log.WithField("reply", text).Error("Unable to parse SAMv3 reply")
|
||||
conn.Close()
|
||||
return nil, errors.New("Unable to parse SAMv3 reply: " + text)
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/logger"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
@ -1,76 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/go-sam-go/datagram"
|
||||
"github.com/go-i2p/go-sam-go/stream"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var PrimarySessionSwitch string = "MASTER"
|
||||
|
||||
// Creates a new PrimarySession with the I2CP- and streaminglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *SAM) NewPrimarySession(id string, keys i2pkeys.I2PKeys, options []string) (*PrimarySession, error) {
|
||||
log.WithFields(logrus.Fields{"id": id, "options": options}).Debug("NewPrimarySession() called")
|
||||
return sam.newPrimarySession(PrimarySessionSwitch, id, keys, options)
|
||||
}
|
||||
|
||||
func (sam *SAM) newPrimarySession(primarySessionSwitch, id string, keys i2pkeys.I2PKeys, options []string) (*PrimarySession, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"primarySessionSwitch": primarySessionSwitch,
|
||||
"id": id,
|
||||
"options": options,
|
||||
}).Debug("newPrimarySession() called")
|
||||
|
||||
conn, err := sam.NewGenericSession(primarySessionSwitch, id, keys, options)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic session")
|
||||
return nil, err
|
||||
}
|
||||
return &PrimarySession{
|
||||
SAM: sam,
|
||||
samAddr: "",
|
||||
id: id,
|
||||
conn: conn,
|
||||
keys: keys,
|
||||
Timeout: 0,
|
||||
Deadline: time.Time{},
|
||||
sigType: "",
|
||||
Config: common.SAMEmit{},
|
||||
stsess: map[string]*stream.StreamSession{},
|
||||
dgsess: map[string]*datagram.DatagramSession{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Creates a new PrimarySession with the I2CP- and PRIMARYinglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *SAM) NewPrimarySessionWithSignature(id string, keys i2pkeys.I2PKeys, options []string, sigType string) (*PrimarySession, error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"id": id,
|
||||
"options": options,
|
||||
"sigType": sigType,
|
||||
}).Debug("NewPrimarySessionWithSignature() called")
|
||||
|
||||
conn, err := sam.NewGenericSessionWithSignature(PrimarySessionSwitch, id, keys, sigType, options)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic session with signature")
|
||||
return nil, err
|
||||
}
|
||||
return &PrimarySession{
|
||||
SAM: sam,
|
||||
samAddr: "",
|
||||
id: id,
|
||||
conn: conn,
|
||||
keys: keys,
|
||||
Timeout: 0,
|
||||
Deadline: time.Time{},
|
||||
sigType: sigType,
|
||||
Config: common.SAMEmit{},
|
||||
stsess: map[string]*stream.StreamSession{},
|
||||
dgsess: map[string]*datagram.DatagramSession{},
|
||||
}, nil
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/go-sam-go/raw"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Creates a new raw 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) NewRawSubSession(id string, udpPort int) (*raw.RawSession, error) {
|
||||
log.WithFields(logrus.Fields{"id": id, "udpPort": udpPort}).Debug("NewRawSubSession called")
|
||||
|
||||
if udpPort > 65335 || udpPort < 0 {
|
||||
log.WithField("udpPort", udpPort).Error("Invalid UDP port")
|
||||
return nil, errors.New("udpPort needs to be in the intervall 0-65335")
|
||||
}
|
||||
if udpPort == 0 {
|
||||
udpPort = 7655
|
||||
log.Debug("Using default UDP port 7655")
|
||||
}
|
||||
lhost, _, err := common.SplitHostPort(s.conn.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to split local host port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
lUDPAddr, err := net.ResolveUDPAddr("udp4", lhost+":0")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve local UDP address")
|
||||
return nil, err
|
||||
}
|
||||
udpconn, err := net.ListenUDP("udp4", lUDPAddr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to listen on UDP")
|
||||
return nil, err
|
||||
}
|
||||
rhost, _, err := common.SplitHostPort(s.conn.RemoteAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to split remote host port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
rUDPAddr, err := net.ResolveUDPAddr("udp4", rhost+":"+strconv.Itoa(udpPort))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve remote UDP address")
|
||||
return nil, err
|
||||
}
|
||||
_, lport, err := net.SplitHostPort(udpconn.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get local port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
// conn, err := s.newGenericSubSession("RAW", id, s.keys, options, []string{"PORT=" + lport})
|
||||
conn, err := s.NewGenericSubSession("RAW", id, []string{"PORT=" + lport})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic sub-session")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{"id": id, "localPort": lport}).Debug("Created new raw sub-session")
|
||||
rawSession := &raw.RawSession{
|
||||
SAM: (*raw.SAM)(s.SAM),
|
||||
SAMUDPConn: udpconn,
|
||||
SAMUDPAddr: rUDPAddr,
|
||||
}
|
||||
rawSession.Conn = conn
|
||||
return rawSession, nil
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/go-sam-go/stream"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Creates a new stream.StreamSession with the I2CP- and streaminglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *PrimarySession) NewStreamSubSession(id string) (*stream.StreamSession, error) {
|
||||
log.WithField("id", id).Debug("NewStreamSubSession called")
|
||||
conn, err := sam.NewGenericSubSession("STREAM", id, []string{})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic sub-session")
|
||||
return nil, err
|
||||
}
|
||||
return newFromPrimary(sam, conn), nil
|
||||
}
|
||||
|
||||
// Creates a new stream.StreamSession with the I2CP- and streaminglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *PrimarySession) NewUniqueStreamSubSession(id string) (*stream.StreamSession, error) {
|
||||
log.WithField("id", id).Debug("NewUniqueStreamSubSession called")
|
||||
conn, err := sam.NewGenericSubSession("STREAM", id, []string{})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic sub-session")
|
||||
return nil, err
|
||||
}
|
||||
return newFromPrimary(sam, conn), nil
|
||||
}
|
||||
|
||||
// Creates a new stream.StreamSession with the I2CP- and streaminglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *PrimarySession) NewStreamSubSessionWithPorts(id, from, to string) (*stream.StreamSession, error) {
|
||||
log.WithFields(logrus.Fields{"id": id, "from": from, "to": to}).Debug("NewStreamSubSessionWithPorts called")
|
||||
conn, err := sam.NewGenericSubSessionWithSignatureAndPorts("STREAM", id, from, to, []string{})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic sub-session with signature and ports")
|
||||
return nil, err
|
||||
}
|
||||
return newFromPrimary(sam, conn), nil
|
||||
}
|
||||
|
||||
func newFromPrimary(sam *PrimarySession, conn net.Conn) *stream.StreamSession {
|
||||
streamSession := &stream.StreamSession{
|
||||
SAM: &stream.SAM{
|
||||
SAM: (*common.SAM)(sam.SAM),
|
||||
},
|
||||
}
|
||||
streamSession.Conn = conn
|
||||
|
||||
return streamSession
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/go-sam-go/datagram"
|
||||
"github.com/go-i2p/go-sam-go/stream"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
)
|
||||
|
||||
type SAM common.SAM
|
||||
|
||||
// Represents a primary session.
|
||||
type PrimarySession struct {
|
||||
*SAM
|
||||
samAddr string // address to the sam bridge (ipv4:port)
|
||||
id string // tunnel name
|
||||
conn net.Conn // connection to sam
|
||||
keys i2pkeys.I2PKeys // i2p destination keys
|
||||
Timeout time.Duration
|
||||
Deadline time.Time
|
||||
sigType string
|
||||
Config common.SAMEmit
|
||||
stsess map[string]*stream.StreamSession
|
||||
dgsess map[string]*datagram.DatagramSession
|
||||
// from string
|
||||
// to string
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_PrimaryDatagramServerClient(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test_PrimaryDatagramServerClient")
|
||||
earlysam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer earlysam.Close()
|
||||
keys, err := earlysam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
sam, err := earlysam.NewPrimarySession("PrimaryTunnel", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
// fmt.Println("\tServer: My address: " + keys.Addr().Base32())
|
||||
fmt.Println("\tServer: Creating tunnel")
|
||||
ds, err := sam.NewDatagramSubSession("PrimaryTunnel"+RandString(), 0)
|
||||
if err != nil {
|
||||
fmt.Println("Server: Failed to create tunnel: " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer ds.Close()
|
||||
c, w := make(chan bool), make(chan bool)
|
||||
go func(c, w chan (bool)) {
|
||||
sam2, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer sam2.Close()
|
||||
keys, err := sam2.NewKeys()
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Creating tunnel")
|
||||
ds2, err := sam2.NewDatagramSession("PRIMARYClientTunnel", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer ds2.Close()
|
||||
// fmt.Println("\tClient: Servers address: " + ds.LocalAddr().Base32())
|
||||
// fmt.Println("\tClient: Clients address: " + ds2.LocalAddr().Base32())
|
||||
fmt.Println("\tClient: Tries to send primary to server")
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
_, err = ds2.WriteTo([]byte("Hello primary-world! <3 <3 <3 <3 <3 <3"), ds.LocalAddr())
|
||||
if err != nil {
|
||||
fmt.Println("\tClient: Failed to send primary: " + err.Error())
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
case <-w:
|
||||
fmt.Println("\tClient: Sent primary, quitting.")
|
||||
return
|
||||
}
|
||||
}
|
||||
c <- true
|
||||
}(c, w)
|
||||
buf := make([]byte, 512)
|
||||
fmt.Println("\tServer: ReadFrom() waiting...")
|
||||
n, _, err := ds.ReadFrom(buf)
|
||||
w <- true
|
||||
if err != nil {
|
||||
fmt.Println("\tServer: Failed to ReadFrom(): " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tServer: Received primary: " + string(buf[:n]))
|
||||
// fmt.Println("\tServer: Senders address was: " + saddr.Base32())
|
||||
}
|
||||
|
||||
func ExamplePrimaryDatagramSession() {
|
||||
// Creates a new PrimarySession, then creates a Datagram subsession on top of it
|
||||
|
||||
const samBridge = "127.0.0.1:7656"
|
||||
|
||||
earlysam, err := NewSAM(samBridge)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer earlysam.Close()
|
||||
keys, err := earlysam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
myself := keys.Addr()
|
||||
|
||||
sam, err := earlysam.NewPrimarySession("PrimaryTunnel", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
|
||||
// See the example Option_* variables.
|
||||
dg, err := sam.NewDatagramSubSession("DGTUN"+RandString(), 0)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer dg.Close()
|
||||
someone, err := earlysam.Lookup("zzz.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
dg.WriteTo([]byte("Hello stranger!"), someone)
|
||||
dg.WriteTo([]byte("Hello myself!"), myself)
|
||||
|
||||
buf := make([]byte, 31*1024)
|
||||
n, _, err := dg.ReadFrom(buf)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println("Got message: '" + string(buf[:n]) + "'")
|
||||
fmt.Println("Got message: " + string(buf[:n]))
|
||||
|
||||
return
|
||||
// Output:
|
||||
// Got message: Hello myself!
|
||||
}
|
@ -1,307 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_PrimaryStreamingDial(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
fmt.Println("Test_PrimaryStreamingDial")
|
||||
earlysam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer earlysam.Close()
|
||||
keys, err := earlysam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
sam, err := earlysam.NewPrimarySession("PrimaryTunnel", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
fmt.Println("\tBuilding tunnel")
|
||||
ss, err := sam.NewStreamSubSession("primaryStreamTunnel")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer ss.Close()
|
||||
fmt.Println("\tNotice: This may fail if your I2P node is not well integrated in the I2P network.")
|
||||
fmt.Println("\tLooking up i2p-projekt.i2p")
|
||||
forumAddr, err := earlysam.Lookup("i2p-projekt.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tDialing i2p-projekt.i2p(", forumAddr.Base32(), forumAddr.DestHash().Hash(), ")")
|
||||
conn, err := ss.DialI2P(forumAddr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
fmt.Println("\tSending HTTP GET /")
|
||||
if _, err := conn.Write([]byte("GET /\n")); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if !strings.Contains(strings.ToLower(string(buf[:n])), "http") && !strings.Contains(strings.ToLower(string(buf[:n])), "html") {
|
||||
fmt.Printf("\tProbably failed to StreamSession.DialI2P(i2p-projekt.i2p)? It replied %d bytes, but nothing that looked like http/html", n)
|
||||
} else {
|
||||
fmt.Println("\tRead HTTP/HTML from i2p-projekt.i2p")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PrimaryStreamingServerClient(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test_StreamingServerClient")
|
||||
earlysam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer earlysam.Close()
|
||||
keys, err := earlysam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
sam, err := earlysam.NewPrimarySession("PrimaryServerClientTunnel", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
fmt.Println("\tServer: Creating tunnel")
|
||||
ss, err := sam.NewUniqueStreamSubSession("PrimaryServerClientTunnel")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer ss.Close()
|
||||
time.Sleep(time.Second * 10)
|
||||
c, w := make(chan bool), make(chan bool)
|
||||
go func(c, w chan (bool)) {
|
||||
if !(<-w) {
|
||||
return
|
||||
}
|
||||
/*
|
||||
sam2, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer sam2.Close()
|
||||
keys, err := sam2.NewKeys()
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
*/
|
||||
|
||||
fmt.Println("\tClient: Creating tunnel")
|
||||
ss2, err := sam.NewStreamSubSession("primaryExampleClientTun")
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer ss2.Close()
|
||||
fmt.Println("\tClient: Connecting to server")
|
||||
conn, err := ss2.DialI2P(ss.Addr())
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Connected to tunnel")
|
||||
defer conn.Close()
|
||||
_, err = conn.Write([]byte("Hello world <3 <3 <3 <3 <3 <3"))
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
c <- true
|
||||
}(c, w)
|
||||
l, err := ss.Listen()
|
||||
if err != nil {
|
||||
fmt.Println("ss.Listen(): " + err.Error())
|
||||
t.Fail()
|
||||
w <- false
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
w <- true
|
||||
fmt.Println("\tServer: Accept()ing on tunnel")
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
fmt.Println("Failed to Accept(): " + err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
buf := make([]byte, 512)
|
||||
n, err := conn.Read(buf)
|
||||
fmt.Printf("\tClient exited successfully: %t\n", <-c)
|
||||
fmt.Println("\tServer: received from Client: " + string(buf[:n]))
|
||||
}
|
||||
|
||||
func ExamplePrimaryStreamSession() {
|
||||
// Creates a new StreamingSession, dials to idk.i2p and gets a SAMConn
|
||||
// which behaves just like a normal net.Conn.
|
||||
|
||||
const samBridge = "127.0.0.1:7656"
|
||||
|
||||
earlysam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
defer earlysam.Close()
|
||||
keys, err := earlysam.NewKeys()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
sam, err := earlysam.NewPrimarySession("PrimaryStreamSessionTunnel", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
conn, err := sam.Dial("tcp", "idk.i2p") // someone.Base32())
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
fmt.Println("Sending HTTP GET /")
|
||||
if _, err := conn.Write([]byte("GET /\n")); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if !strings.Contains(strings.ToLower(string(buf[:n])), "http") && !strings.Contains(strings.ToLower(string(buf[:n])), "html") {
|
||||
fmt.Printf("Probably failed to StreamSession.DialI2P(idk.i2p)? It replied %d bytes, but nothing that looked like http/html", n)
|
||||
log.Printf("Probably failed to StreamSession.DialI2P(idk.i2p)? It replied %d bytes, but nothing that looked like http/html", n)
|
||||
} else {
|
||||
fmt.Println("Read HTTP/HTML from idk.i2p")
|
||||
log.Println("Read HTTP/HTML from idk.i2p")
|
||||
}
|
||||
// Output:
|
||||
// Sending HTTP GET /
|
||||
// Read HTTP/HTML from idk.i2p
|
||||
}
|
||||
|
||||
func ExamplePrimaryStreamListener() {
|
||||
// One server Accept()ing on a StreamListener, and one client that Dials
|
||||
// through I2P to the server. Server writes "Hello world!" through a SAMConn
|
||||
// (which implements net.Conn) and the client prints the message.
|
||||
|
||||
const samBridge = "127.0.0.1:7656"
|
||||
|
||||
var ss *StreamSession
|
||||
go func() {
|
||||
earlysam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
defer earlysam.Close()
|
||||
keys, err := earlysam.NewKeys()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
sam, err := earlysam.NewPrimarySession("PrimaryListenerTunnel", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
ss, err = sam.NewStreamSubSession("PrimaryListenerServerTunnel2")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer ss.Close()
|
||||
l, err := ss.Listen()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
// fmt.Println("Serving on primary listener", l.Addr().String())
|
||||
if err := http.Serve(l, &exitHandler{}); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}()
|
||||
time.Sleep(time.Second * 10)
|
||||
latesam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
defer latesam.Close()
|
||||
keys2, err := latesam.NewKeys()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
sc, err := latesam.NewStreamSession("PrimaryListenerClientTunnel2", keys2, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer sc.Close()
|
||||
client := http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: sc.Dial,
|
||||
},
|
||||
}
|
||||
// resp, err := client.Get("http://" + "idk.i2p") //ss.Addr().Base32())
|
||||
resp, err := client.Get("http://" + ss.Addr().Base32())
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
r, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Println("Got response: " + string(r))
|
||||
|
||||
// Output:
|
||||
// Got response: Hello world!
|
||||
}
|
||||
|
||||
type exitHandler struct{}
|
||||
|
||||
func (e *exitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Hello world!"))
|
||||
}
|
16
raw.go
16
raw.go
@ -1,16 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-sam-go/raw"
|
||||
)
|
||||
|
||||
// The RawSession provides no authentication of senders, and there is no sender
|
||||
// address attached to datagrams, so all communication is anonymous. The
|
||||
// messages send are however still endpoint-to-endpoint encrypted. You
|
||||
// need to figure out a way to identify and authenticate clients yourself, iff
|
||||
// that is needed. Raw datagrams may be at most 32 kB in size. There is no
|
||||
// overhead of authentication, which is the reason to use this..
|
||||
type RawSession struct {
|
||||
*raw.RawSession
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package raw
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/logger"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
73
raw/raw.go
73
raw/raw.go
@ -1,73 +0,0 @@
|
||||
package raw
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Creates a new raw 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) NewRawSession(id string, keys i2pkeys.I2PKeys, options []string, udpPort int) (*RawSession, error) {
|
||||
log.WithFields(logrus.Fields{"id": id, "udpPort": udpPort}).Debug("Creating new RawSession")
|
||||
|
||||
if udpPort > 65335 || udpPort < 0 {
|
||||
log.WithField("udpPort", udpPort).Error("Invalid UDP port")
|
||||
return nil, errors.New("udpPort needs to be in the interval 0-65335")
|
||||
}
|
||||
if udpPort == 0 {
|
||||
udpPort = 7655
|
||||
log.Debug("Using default UDP port 7655")
|
||||
}
|
||||
lhost, _, err := common.SplitHostPort(s.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.Debug("Using default UDP port 7655")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
lUDPAddr, err := net.ResolveUDPAddr("udp4", lhost+":0")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve local UDP address")
|
||||
return nil, err
|
||||
}
|
||||
udpconn, err := net.ListenUDP("udp4", lUDPAddr)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to listen on UDP")
|
||||
return nil, err
|
||||
}
|
||||
rhost, _, err := common.SplitHostPort(s.RemoteAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to split remote host port")
|
||||
s.Close()
|
||||
return nil, err
|
||||
}
|
||||
rUDPAddr, err := net.ResolveUDPAddr("udp4", rhost+":"+strconv.Itoa(udpPort))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve remote UDP address")
|
||||
return nil, err
|
||||
}
|
||||
_, lport, err := net.SplitHostPort(udpconn.LocalAddr().String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get local port")
|
||||
return nil, err
|
||||
}
|
||||
conn, err := s.NewGenericSession("RAW", id, keys, []string{"PORT=" + lport})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new generic session")
|
||||
return nil, err
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"id": id,
|
||||
"localPort": lport,
|
||||
"remoteUDPAddr": rUDPAddr,
|
||||
}).Debug("Created new RawSession")
|
||||
rawSession := &RawSession{
|
||||
SAM: s,
|
||||
}
|
||||
rawSession.Conn = conn
|
||||
return rawSession, nil
|
||||
}
|
21
raw/types.go
21
raw/types.go
@ -1,21 +0,0 @@
|
||||
package raw
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
)
|
||||
|
||||
type SAM common.SAM
|
||||
|
||||
// The RawSession provides no authentication of senders, and there is no sender
|
||||
// address attached to datagrams, so all communication is anonymous. The
|
||||
// messages send are however still endpoint-to-endpoint encrypted. You
|
||||
// need to figure out a way to identify and authenticate clients yourself, iff
|
||||
// that is needed. Raw datagrams may be at most 32 kB in size. There is no
|
||||
// overhead of authentication, which is the reason to use this..
|
||||
type RawSession struct {
|
||||
*SAM
|
||||
SAMUDPConn *net.UDPConn // used to deliver datagrams
|
||||
SAMUDPAddr *net.UDPAddr // the SAM bridge UDP-port
|
||||
}
|
25
resolver.go
25
resolver.go
@ -1,25 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
type SAMResolver struct {
|
||||
*SAM
|
||||
}
|
||||
|
||||
func NewSAMResolver(parent *SAM) (*SAMResolver, error) {
|
||||
log.Debug("Creating new SAMResolver from existing SAM instance")
|
||||
var s SAMResolver
|
||||
s.SAM = parent
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func NewFullSAMResolver(address string) (*SAMResolver, error) {
|
||||
log.WithField("address", address).Debug("Creating new full SAMResolver")
|
||||
var s SAMResolver
|
||||
var err error
|
||||
s.SAM, err = NewSAM(address)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new SAM instance")
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
81
sam3.go
81
sam3.go
@ -1,81 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
"github.com/go-i2p/go-sam-go/datagram"
|
||||
"github.com/go-i2p/go-sam-go/primary"
|
||||
"github.com/go-i2p/go-sam-go/stream"
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
)
|
||||
|
||||
// Used for controlling I2Ps SAMv3.
|
||||
type SAM struct {
|
||||
*common.SAM
|
||||
}
|
||||
|
||||
// Creates a new stream session by wrapping stream.NewStreamSession
|
||||
func (s *SAM) NewStreamSession(id string, keys i2pkeys.I2PKeys, options []string) (*StreamSession, error) {
|
||||
sam := &stream.SAM{
|
||||
SAM: s.SAM,
|
||||
}
|
||||
ss, err := sam.NewStreamSession(id, keys, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
streamSession := &StreamSession{
|
||||
StreamSession: ss,
|
||||
}
|
||||
return streamSession, nil
|
||||
}
|
||||
|
||||
// Creates a new Datagram session by wrapping datagram.NewDatagramSession
|
||||
func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []string, port int) (*DatagramSession, error) {
|
||||
sam := datagram.SAM(*s.SAM)
|
||||
dgs, err := sam.NewDatagramSession(id, keys, options, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
datagramSession := DatagramSession{
|
||||
DatagramSession: *dgs,
|
||||
}
|
||||
return &datagramSession, nil
|
||||
}
|
||||
|
||||
func (s *SAM) NewPrimarySession(id string, keys i2pkeys.I2PKeys, options []string) (*PrimarySession, error) {
|
||||
sam := primary.SAM(*s.SAM)
|
||||
ps, err := sam.NewPrimarySession(id, keys, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
primarySession := PrimarySession{
|
||||
PrimarySession: ps,
|
||||
}
|
||||
return &primarySession, nil
|
||||
}
|
||||
|
||||
func RandString() string {
|
||||
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
n := 4
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
log.WithField("randomString", string(b)).Debug("Generated random string")
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Creates a new controller for the I2P routers SAM bridge.
|
||||
func NewSAM(address string) (*SAM, error) {
|
||||
is, err := common.NewSAM(address)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new SAM instance")
|
||||
return nil, err
|
||||
}
|
||||
s := &SAM{
|
||||
SAM: is,
|
||||
}
|
||||
return s, nil
|
||||
}
|
165
sam3_test.go
165
sam3_test.go
@ -1,165 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const yoursam = "127.0.0.1:7656"
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
fmt.Println("Test_Basic")
|
||||
fmt.Println("\tAttaching to SAM at " + yoursam)
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("\tCreating new keys...")
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
} else {
|
||||
fmt.Println("\tAddress created: " + keys.Addr().Base32())
|
||||
fmt.Println("\tI2PKeys: " + string(keys.String())[:50] + "(...etc)")
|
||||
}
|
||||
|
||||
addr2, err := sam.Lookup("zzz.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
} else {
|
||||
fmt.Println("\tzzz.i2p = " + addr2.Base32())
|
||||
}
|
||||
|
||||
if err := sam.Close(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func Test_GenericSession(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
fmt.Println("Test_GenericSession")
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
} else {
|
||||
conn1, err := sam.newGenericSession("STREAM", "testTun", keys, []string{})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
} else {
|
||||
conn1.Close()
|
||||
}
|
||||
conn2, err := sam.newGenericSession("STREAM", "testTun", keys, []string{"inbound.length=1", "outbound.length=1", "inbound.lengthVariance=1", "outbound.lengthVariance=1", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
} else {
|
||||
conn2.Close()
|
||||
}
|
||||
conn3, err := sam.newGenericSession("DATAGRAM", "testTun", keys, []string{"inbound.length=1", "outbound.length=1", "inbound.lengthVariance=1", "outbound.lengthVariance=1", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
} else {
|
||||
conn3.Close()
|
||||
}
|
||||
}
|
||||
if err := sam.Close(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func Test_RawServerClient(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test_RawServerClient")
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tServer: Creating tunnel")
|
||||
rs, err := sam.NewDatagramSession("RAWserverTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
|
||||
if err != nil {
|
||||
fmt.Println("Server: Failed to create tunnel: " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
c, w := make(chan bool), make(chan bool)
|
||||
go func(c, w chan (bool)) {
|
||||
sam2, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer sam2.Close()
|
||||
keys, err := sam2.NewKeys()
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Creating tunnel")
|
||||
rs2, err := sam2.NewDatagramSession("RAWclientTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"}, 0)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer rs2.Close()
|
||||
fmt.Println("\tClient: Tries to send raw datagram to server")
|
||||
for {
|
||||
select {
|
||||
default:
|
||||
_, err = rs2.WriteTo([]byte("Hello raw-world! <3 <3 <3 <3 <3 <3"), rs.LocalAddr())
|
||||
if err != nil {
|
||||
fmt.Println("\tClient: Failed to send raw datagram: " + err.Error())
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
case <-w:
|
||||
fmt.Println("\tClient: Sent raw datagram, quitting.")
|
||||
return
|
||||
}
|
||||
}
|
||||
c <- true
|
||||
}(c, w)
|
||||
buf := make([]byte, 512)
|
||||
fmt.Println("\tServer: Read() waiting...")
|
||||
n, _, err := rs.ReadFrom(buf)
|
||||
w <- true
|
||||
if err != nil {
|
||||
fmt.Println("\tServer: Failed to Read(): " + err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tServer: Received datagram: " + string(buf[:n]))
|
||||
// fmt.Println("\tServer: Senders address was: " + saddr.Base32())
|
||||
}
|
18
stream.go
18
stream.go
@ -1,18 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-sam-go/stream"
|
||||
)
|
||||
|
||||
// Represents a streaming session.
|
||||
type StreamSession struct {
|
||||
*stream.StreamSession
|
||||
}
|
||||
|
||||
/*
|
||||
func (s *StreamSession) Cancel() chan *StreamSession {
|
||||
ch := make(chan *StreamSession)
|
||||
ch <- s
|
||||
return ch
|
||||
}*/
|
@ -77,13 +77,13 @@ func (s *StreamSession) Dial(n, addr string) (c net.Conn, err error) {
|
||||
// Dials to an I2P destination and returns a SAMConn, which implements a net.Conn.
|
||||
func (s *StreamSession) DialI2P(addr i2pkeys.I2PAddr) (*StreamConn, error) {
|
||||
log.WithField("addr", addr).Debug("DialI2P called")
|
||||
sam, err := common.NewSAM(s.Sam())
|
||||
sam, err := common.NewSAM(s.SAM().Sam())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new SAM instance")
|
||||
return nil, err
|
||||
}
|
||||
conn := sam.Conn
|
||||
_, err = conn.Write([]byte("STREAM CONNECT ID=" + s.ID() + s.FromPort() + s.ToPort() + " DESTINATION=" + addr.Base64() + " SILENT=false\n"))
|
||||
_, err = conn.Write([]byte("STREAM CONNECT ID=" + s.SAM().ID() + s.SAM().FromPort() + s.SAM().ToPort() + " DESTINATION=" + addr.Base64() + " SILENT=false\n"))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write STREAM CONNECT command")
|
||||
conn.Close()
|
||||
|
@ -4,7 +4,7 @@ import "github.com/sirupsen/logrus"
|
||||
|
||||
// create a new stream listener to accept inbound connections
|
||||
func (s *StreamSession) Listen() (*StreamListener, error) {
|
||||
log.WithFields(logrus.Fields{"id": s.ID(), "laddr": s.Addr()}).Debug("Creating new StreamListener")
|
||||
log.WithFields(logrus.Fields{"id": s.SAM().ID(), "laddr": s.Addr()}).Debug("Creating new StreamListener")
|
||||
return &StreamListener{
|
||||
session: s,
|
||||
}, nil
|
||||
|
@ -14,17 +14,17 @@ import (
|
||||
)
|
||||
|
||||
func (l *StreamListener) From() string {
|
||||
return l.session.Fromport
|
||||
return l.session.SAM().Fromport
|
||||
}
|
||||
|
||||
func (l *StreamListener) To() string {
|
||||
return l.session.Toport
|
||||
return l.session.SAM().Toport
|
||||
}
|
||||
|
||||
// get our address
|
||||
// implements net.Listener
|
||||
func (l *StreamListener) Addr() net.Addr {
|
||||
return l.session.DestinationKeys.Addr()
|
||||
return l.session.Addr()
|
||||
}
|
||||
|
||||
// implements net.Listener
|
||||
@ -40,12 +40,12 @@ func (l *StreamListener) Accept() (net.Conn, error) {
|
||||
// accept a new inbound connection
|
||||
func (l *StreamListener) AcceptI2P() (*StreamConn, error) {
|
||||
log.Debug("StreamListener.AcceptI2P() called")
|
||||
s, err := common.NewSAM(l.session.Sam())
|
||||
s, err := common.NewSAM(l.session.SAM().Sam())
|
||||
if err == nil {
|
||||
log.Debug("Connected to SAM bridge")
|
||||
// we connected to sam
|
||||
// send accept() command
|
||||
_, err = io.WriteString(s.Conn, "STREAM ACCEPT ID="+l.session.ID()+" SILENT=false\n")
|
||||
_, err = io.WriteString(s.Conn, "STREAM ACCEPT ID="+l.session.SAM().ID()+" SILENT=false\n")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to send STREAM ACCEPT command")
|
||||
s.Close()
|
||||
@ -67,8 +67,8 @@ func (l *StreamListener) AcceptI2P() (*StreamConn, error) {
|
||||
destline, err := rd.ReadString(10)
|
||||
if err == nil {
|
||||
dest := common.ExtractDest(destline)
|
||||
l.session.Fromport = common.ExtractPairString(destline, "FROM_PORT")
|
||||
l.session.Toport = common.ExtractPairString(destline, "TO_PORT")
|
||||
l.session.SAM().Fromport = common.ExtractPairString(destline, "FROM_PORT")
|
||||
l.session.SAM().Toport = common.ExtractPairString(destline, "TO_PORT")
|
||||
// return wrapped connection
|
||||
dest = strings.Trim(dest, "\n")
|
||||
log.WithFields(logrus.Fields{
|
||||
|
@ -11,49 +11,49 @@ import (
|
||||
|
||||
// Read reads data from the stream.
|
||||
func (s *StreamSession) Read(buf []byte) (int, error) {
|
||||
return s.Conn.Read(buf)
|
||||
return s.SAM().Conn.Read(buf)
|
||||
}
|
||||
|
||||
// Write sends data over the stream.
|
||||
func (s *StreamSession) Write(data []byte) (int, error) {
|
||||
return s.Conn.Write(data)
|
||||
return s.SAM().Conn.Write(data)
|
||||
}
|
||||
|
||||
func (s *StreamSession) SetDeadline(t time.Time) error {
|
||||
log.WithField("deadline", t).Debug("Setting deadline for StreamSession")
|
||||
return s.Conn.SetDeadline(t)
|
||||
return s.SAM().Conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (s *StreamSession) SetReadDeadline(t time.Time) error {
|
||||
log.WithField("readDeadline", t).Debug("Setting read deadline for StreamSession")
|
||||
return s.Conn.SetReadDeadline(t)
|
||||
return s.SAM().Conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (s *StreamSession) SetWriteDeadline(t time.Time) error {
|
||||
log.WithField("writeDeadline", t).Debug("Setting write deadline for StreamSession")
|
||||
return s.Conn.SetWriteDeadline(t)
|
||||
return s.SAM().Conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (s *StreamSession) From() string {
|
||||
return s.Fromport
|
||||
return s.SAM().Fromport
|
||||
}
|
||||
|
||||
func (s *StreamSession) To() string {
|
||||
return s.Toport
|
||||
return s.SAM().Toport
|
||||
}
|
||||
|
||||
func (s *StreamSession) SignatureType() string {
|
||||
return s.SignatureType()
|
||||
return s.SAM().SignatureType()
|
||||
}
|
||||
|
||||
func (s *StreamSession) Close() error {
|
||||
log.WithField("id", s.ID()).Debug("Closing StreamSession")
|
||||
return s.Conn.Close()
|
||||
log.WithField("id", s.SAM().ID()).Debug("Closing StreamSession")
|
||||
return s.SAM().Conn.Close()
|
||||
}
|
||||
|
||||
// Returns the I2P destination (the address) of the stream session
|
||||
func (s *StreamSession) Addr() i2pkeys.I2PAddr {
|
||||
return s.Addr()
|
||||
return s.Keys().Address
|
||||
}
|
||||
|
||||
func (s *StreamSession) LocalAddr() net.Addr {
|
||||
@ -62,13 +62,13 @@ func (s *StreamSession) LocalAddr() net.Addr {
|
||||
|
||||
// Returns the keys associated with the stream session
|
||||
func (s *StreamSession) Keys() i2pkeys.I2PKeys {
|
||||
return *s.DestinationKeys
|
||||
return *s.SAM().DestinationKeys
|
||||
}
|
||||
|
||||
// lookup name, convenience function
|
||||
func (s *StreamSession) Lookup(name string) (i2pkeys.I2PAddr, error) {
|
||||
log.WithField("name", name).Debug("Looking up address")
|
||||
sam, err := common.NewSAM(s.Sam())
|
||||
sam, err := common.NewSAM(s.SAM().Sam())
|
||||
if err == nil {
|
||||
addr, err := sam.Lookup(name)
|
||||
defer sam.Close()
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
// Creates a new StreamSession with the I2CP- and streaminglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *SAM) NewStreamSession(id string, keys i2pkeys.I2PKeys, options []string) (*StreamSession, error) {
|
||||
func (sam SAM) NewStreamSession(id string, keys i2pkeys.I2PKeys, options []string) (*StreamSession, error) {
|
||||
log.WithFields(logrus.Fields{"id": id, "options": options}).Debug("Creating new StreamSession")
|
||||
conn, err := sam.NewGenericSession("STREAM", id, keys, []string{})
|
||||
if err != nil {
|
||||
@ -15,7 +15,7 @@ func (sam *SAM) NewStreamSession(id string, keys i2pkeys.I2PKeys, options []stri
|
||||
}
|
||||
log.WithField("id", id).Debug("Created new StreamSession")
|
||||
streamSession := &StreamSession{
|
||||
SAM: sam,
|
||||
sam: sam,
|
||||
}
|
||||
streamSession.Conn = conn
|
||||
return streamSession, nil
|
||||
@ -23,7 +23,7 @@ func (sam *SAM) NewStreamSession(id string, keys i2pkeys.I2PKeys, options []stri
|
||||
|
||||
// Creates a new StreamSession with the I2CP- and streaminglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *SAM) NewStreamSessionWithSignature(id string, keys i2pkeys.I2PKeys, options []string, sigType string) (*StreamSession, error) {
|
||||
func (sam SAM) NewStreamSessionWithSignature(id string, keys i2pkeys.I2PKeys, options []string, sigType string) (*StreamSession, error) {
|
||||
log.WithFields(logrus.Fields{"id": id, "options": options, "sigType": sigType}).Debug("Creating new StreamSession with signature")
|
||||
conn, err := sam.NewGenericSessionWithSignature("STREAM", id, keys, sigType, []string{})
|
||||
if err != nil {
|
||||
@ -32,7 +32,7 @@ func (sam *SAM) NewStreamSessionWithSignature(id string, keys i2pkeys.I2PKeys, o
|
||||
log.WithFields(logrus.Fields{"id": id, "sigType": sigType}).Debug("Created new StreamSession with signature")
|
||||
log.WithField("id", id).Debug("Created new StreamSession")
|
||||
streamSession := &StreamSession{
|
||||
SAM: sam,
|
||||
sam: sam,
|
||||
}
|
||||
streamSession.Conn = conn
|
||||
return streamSession, nil
|
||||
@ -40,7 +40,7 @@ func (sam *SAM) NewStreamSessionWithSignature(id string, keys i2pkeys.I2PKeys, o
|
||||
|
||||
// Creates a new StreamSession with the I2CP- and streaminglib options as
|
||||
// specified. See the I2P documentation for a full list of options.
|
||||
func (sam *SAM) NewStreamSessionWithSignatureAndPorts(id, from, to string, keys i2pkeys.I2PKeys, options []string, sigType string) (*StreamSession, error) {
|
||||
func (sam SAM) NewStreamSessionWithSignatureAndPorts(id, from, to string, keys i2pkeys.I2PKeys, options []string, sigType string) (*StreamSession, error) {
|
||||
log.WithFields(logrus.Fields{"id": id, "from": from, "to": to, "options": options, "sigType": sigType}).Debug("Creating new StreamSession with signature and ports")
|
||||
conn, err := sam.NewGenericSessionWithSignatureAndPorts("STREAM", id, from, to, keys, sigType, []string{})
|
||||
if err != nil {
|
||||
@ -49,7 +49,7 @@ func (sam *SAM) NewStreamSessionWithSignatureAndPorts(id, from, to string, keys
|
||||
log.WithFields(logrus.Fields{"id": id, "from": from, "to": to, "sigType": sigType}).Debug("Created new StreamSession with signature and ports")
|
||||
log.WithField("id", id).Debug("Created new StreamSession")
|
||||
streamSession := &StreamSession{
|
||||
SAM: sam,
|
||||
sam: sam,
|
||||
}
|
||||
streamSession.Conn = conn
|
||||
return streamSession, nil
|
||||
|
@ -2,8 +2,6 @@ package stream
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-i2p/go-sam-go/common"
|
||||
)
|
||||
|
||||
func TestNewStreamSession_Integration(t *testing.T) {
|
||||
@ -36,13 +34,10 @@ func TestNewStreamSession_Integration(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create a fresh SAM connection for each test
|
||||
commonSam, err := common.NewSAM("127.0.0.1:7656")
|
||||
sam, err := NewSAM("127.0.0.1:7656")
|
||||
if err != nil {
|
||||
t.Fatalf("NewSAM() error = %v", err)
|
||||
}
|
||||
defer commonSam.Close()
|
||||
|
||||
sam := &SAM{SAM: commonSam}
|
||||
|
||||
// Generate keys through the SAM bridge
|
||||
keys, err := sam.NewKeys()
|
||||
@ -58,6 +53,7 @@ func TestNewStreamSession_Integration(t *testing.T) {
|
||||
if err == nil {
|
||||
session.Close()
|
||||
}
|
||||
sam.Close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,19 @@ import (
|
||||
)
|
||||
|
||||
type SAM struct {
|
||||
*common.SAM
|
||||
common.SAM
|
||||
}
|
||||
|
||||
// Represents a streaming session.
|
||||
type StreamSession struct {
|
||||
*SAM
|
||||
sam SAM
|
||||
Timeout time.Duration
|
||||
Deadline time.Time
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (s *StreamSession) SAM() *SAM {
|
||||
return &s.sam
|
||||
}
|
||||
|
||||
type StreamListener struct {
|
||||
|
@ -1,10 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-sam-go/stream"
|
||||
)
|
||||
|
||||
type StreamListener struct {
|
||||
*stream.StreamListener
|
||||
}
|
284
stream_test.go
284
stream_test.go
@ -1,284 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-i2p/i2pkeys"
|
||||
)
|
||||
|
||||
func Test_StreamingDial(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
fmt.Println("Test_StreamingDial")
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tBuilding tunnel")
|
||||
ss, err := sam.NewStreamSession("streamTun", keys, []string{"inbound.length=1", "outbound.length=1", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tNotice: This may fail if your I2P node is not well integrated in the I2P network.")
|
||||
fmt.Println("\tLooking up i2p-projekt.i2p")
|
||||
forumAddr, err := sam.Lookup("i2p-projekt.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tDialing i2p-projekt.i2p(", forumAddr.Base32(), forumAddr.DestHash().Hash(), ")")
|
||||
conn, err := ss.DialI2P(forumAddr)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
fmt.Println("\tSending HTTP GET /")
|
||||
if _, err := conn.Write([]byte("GET /\n")); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if !strings.Contains(strings.ToLower(string(buf[:n])), "http") && !strings.Contains(strings.ToLower(string(buf[:n])), "html") {
|
||||
fmt.Printf("\tProbably failed to StreamSession.DialI2P(i2p-projekt.i2p)? It replied %d bytes, but nothing that looked like http/html", n)
|
||||
} else {
|
||||
fmt.Println("\tRead HTTP/HTML from i2p-projekt.i2p")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_StreamingServerClient(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test_StreamingServerClient")
|
||||
sam, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
fmt.Println("\tServer: Creating tunnel")
|
||||
ss, err := sam.NewStreamSession("serverTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c, w := make(chan bool), make(chan bool)
|
||||
go func(c, w chan (bool)) {
|
||||
if !(<-w) {
|
||||
return
|
||||
}
|
||||
sam2, err := NewSAM(yoursam)
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
defer sam2.Close()
|
||||
keys, err := sam2.NewKeys()
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Creating tunnel")
|
||||
ss2, err := sam2.NewStreamSession("clientTun", keys, []string{"inbound.length=0", "outbound.length=0", "inbound.lengthVariance=0", "outbound.lengthVariance=0", "inbound.quantity=1", "outbound.quantity=1"})
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Connecting to server")
|
||||
conn, err := ss2.DialI2P(ss.Addr())
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
fmt.Println("\tClient: Connected to tunnel")
|
||||
defer conn.Close()
|
||||
_, err = conn.Write([]byte("Hello world <3 <3 <3 <3 <3 <3"))
|
||||
if err != nil {
|
||||
c <- false
|
||||
return
|
||||
}
|
||||
c <- true
|
||||
}(c, w)
|
||||
l, err := ss.Listen()
|
||||
if err != nil {
|
||||
fmt.Println("ss.Listen(): " + err.Error())
|
||||
t.Fail()
|
||||
w <- false
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
w <- true
|
||||
fmt.Println("\tServer: Accept()ing on tunnel")
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
fmt.Println("Failed to Accept(): " + err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
buf := make([]byte, 512)
|
||||
n, err := conn.Read(buf)
|
||||
fmt.Printf("\tClient exited successfully: %t\n", <-c)
|
||||
fmt.Println("\tServer: received from Client: " + string(buf[:n]))
|
||||
}
|
||||
|
||||
func ExampleStreamSession() {
|
||||
// Creates a new StreamingSession, dials to idk.i2p and gets a SAMConn
|
||||
// which behaves just like a normal net.Conn.
|
||||
|
||||
const samBridge = "127.0.0.1:7656"
|
||||
|
||||
sam, err := NewSAM(samBridge)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
// See the example Option_* variables.
|
||||
ss, err := sam.NewStreamSession("stream_example", keys, Options_Small)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
someone, err := sam.Lookup("idk.i2p")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := ss.DialI2P(someone)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
fmt.Println("Sending HTTP GET /")
|
||||
if _, err := conn.Write([]byte("GET /\n")); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
n, err := conn.Read(buf)
|
||||
if !strings.Contains(strings.ToLower(string(buf[:n])), "http") && !strings.Contains(strings.ToLower(string(buf[:n])), "html") {
|
||||
fmt.Printf("Probably failed to StreamSession.DialI2P(idk.i2p)? It replied %d bytes, but nothing that looked like http/html", n)
|
||||
log.Printf("Probably failed to StreamSession.DialI2P(idk.i2p)? It replied %d bytes, but nothing that looked like http/html", n)
|
||||
} else {
|
||||
fmt.Println("Read HTTP/HTML from idk.i2p")
|
||||
log.Println("Read HTTP/HTML from idk.i2p")
|
||||
}
|
||||
return
|
||||
|
||||
// Output:
|
||||
// Sending HTTP GET /
|
||||
// Read HTTP/HTML from idk.i2p
|
||||
}
|
||||
|
||||
func ExampleStreamListener() {
|
||||
// One server Accept()ing on a StreamListener, and one client that Dials
|
||||
// through I2P to the server. Server writes "Hello world!" through a SAMConn
|
||||
// (which implements net.Conn) and the client prints the message.
|
||||
|
||||
const samBridge = "127.0.0.1:7656"
|
||||
|
||||
sam, err := NewSAM(samBridge)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer sam.Close()
|
||||
keys, err := sam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
quit := make(chan bool)
|
||||
|
||||
// Client connecting to the server
|
||||
go func(server i2pkeys.I2PAddr) {
|
||||
csam, err := NewSAM(samBridge)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer csam.Close()
|
||||
keys, err := csam.NewKeys()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
cs, err := csam.NewStreamSession("client_example", keys, Options_Small)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
quit <- false
|
||||
return
|
||||
}
|
||||
conn, err := cs.DialI2P(server)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
quit <- false
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 256)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
quit <- false
|
||||
return
|
||||
}
|
||||
fmt.Println(string(buf[:n]))
|
||||
quit <- true
|
||||
}(keys.Addr()) // end of client
|
||||
|
||||
ss, err := sam.NewStreamSession("server_example", keys, Options_Small)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
l, err := ss.Listen()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
conn.Write([]byte("Hello world!"))
|
||||
|
||||
<-quit // waits for client to die, for example only
|
||||
|
||||
// Output:
|
||||
// Hello world!
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
// package sam3 wraps the original sam3 API from github.com/go-i2p/sam3
|
||||
package sam3
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Examples and suggestions for options when creating sessions.
|
||||
var (
|
||||
// Suitable options if you are shuffling A LOT of traffic. If unused, this
|
||||
// will waste your resources.
|
||||
Options_Humongous = []string{
|
||||
"inbound.length=3", "outbound.length=3",
|
||||
"inbound.lengthVariance=1", "outbound.lengthVariance=1",
|
||||
"inbound.backupQuantity=3", "outbound.backupQuantity=3",
|
||||
"inbound.quantity=6", "outbound.quantity=6",
|
||||
}
|
||||
|
||||
// Suitable for shuffling a lot of traffic.
|
||||
Options_Large = []string{
|
||||
"inbound.length=3", "outbound.length=3",
|
||||
"inbound.lengthVariance=1", "outbound.lengthVariance=1",
|
||||
"inbound.backupQuantity=1", "outbound.backupQuantity=1",
|
||||
"inbound.quantity=4", "outbound.quantity=4",
|
||||
}
|
||||
|
||||
// Suitable for shuffling a lot of traffic quickly with minimum
|
||||
// anonymity. Uses 1 hop and multiple tunnels.
|
||||
Options_Wide = []string{
|
||||
"inbound.length=1", "outbound.length=1",
|
||||
"inbound.lengthVariance=1", "outbound.lengthVariance=1",
|
||||
"inbound.backupQuantity=2", "outbound.backupQuantity=2",
|
||||
"inbound.quantity=3", "outbound.quantity=3",
|
||||
}
|
||||
|
||||
// Suitable for shuffling medium amounts of traffic.
|
||||
Options_Medium = []string{
|
||||
"inbound.length=3", "outbound.length=3",
|
||||
"inbound.lengthVariance=1", "outbound.lengthVariance=1",
|
||||
"inbound.backupQuantity=0", "outbound.backupQuantity=0",
|
||||
"inbound.quantity=2", "outbound.quantity=2",
|
||||
}
|
||||
|
||||
// Sensible defaults for most people
|
||||
Options_Default = []string{
|
||||
"inbound.length=3", "outbound.length=3",
|
||||
"inbound.lengthVariance=0", "outbound.lengthVariance=0",
|
||||
"inbound.backupQuantity=1", "outbound.backupQuantity=1",
|
||||
"inbound.quantity=1", "outbound.quantity=1",
|
||||
}
|
||||
|
||||
// Suitable only for small dataflows, and very short lasting connections:
|
||||
// You only have one tunnel in each direction, so if any of the nodes
|
||||
// through which any of your two tunnels pass through go offline, there will
|
||||
// be a complete halt in the dataflow, until a new tunnel is built.
|
||||
Options_Small = []string{
|
||||
"inbound.length=3", "outbound.length=3",
|
||||
"inbound.lengthVariance=1", "outbound.lengthVariance=1",
|
||||
"inbound.backupQuantity=0", "outbound.backupQuantity=0",
|
||||
"inbound.quantity=1", "outbound.quantity=1",
|
||||
}
|
||||
|
||||
// Does not use any anonymization, you connect directly to others tunnel
|
||||
// endpoints, thus revealing your identity but not theirs. Use this only
|
||||
// if you don't care.
|
||||
Options_Warning_ZeroHop = []string{
|
||||
"inbound.length=0", "outbound.length=0",
|
||||
"inbound.lengthVariance=0", "outbound.lengthVariance=0",
|
||||
"inbound.backupQuantity=0", "outbound.backupQuantity=0",
|
||||
"inbound.quantity=2", "outbound.quantity=2",
|
||||
}
|
||||
)
|
||||
|
||||
func getEnv(key, fallback string) string {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if !ok {
|
||||
log.WithFields(logrus.Fields{
|
||||
"key": key,
|
||||
"fallback": fallback,
|
||||
}).Debug("Environment variable not set, using fallback")
|
||||
return fallback
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"key": key,
|
||||
"value": value,
|
||||
}).Debug("Retrieved environment variable")
|
||||
return value
|
||||
}
|
||||
|
||||
var (
|
||||
SAM_HOST = getEnv("sam_host", "127.0.0.1")
|
||||
SAM_PORT = getEnv("sam_port", "7656")
|
||||
)
|
||||
|
||||
func SAMDefaultAddr(fallforward string) string {
|
||||
if fallforward == "" {
|
||||
addr := net.JoinHostPort(SAM_HOST, SAM_PORT)
|
||||
log.WithField("addr", addr).Debug("Using default SAM address")
|
||||
return addr
|
||||
}
|
||||
log.WithField("addr", fallforward).Debug("Using fallforward SAM address")
|
||||
return fallforward
|
||||
}
|
||||
|
||||
func GenerateOptionString(opts []string) string {
|
||||
optStr := strings.Join(opts, " ")
|
||||
log.WithField("options", optStr).Debug("Generating option string")
|
||||
if strings.Contains(optStr, "i2cp.leaseSetEncType") {
|
||||
log.Debug("i2cp.leaseSetEncType already present in options")
|
||||
return optStr
|
||||
}
|
||||
finalOpts := optStr + " i2cp.leaseSetEncType=4,0"
|
||||
log.WithField("finalOptions", finalOpts).Debug("Added default i2cp.leaseSetEncType to options")
|
||||
return finalOpts
|
||||
// return optStr + " i2cp.leaseSetEncType=4,0"
|
||||
}
|
Reference in New Issue
Block a user