fix some primary sessions, grab some defaults from environment

This commit is contained in:
idk
2022-05-31 23:59:37 -04:00
parent 089f97b99f
commit 3d289d99c6
9 changed files with 157 additions and 94 deletions

View File

@ -33,7 +33,7 @@ func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []stri
if udpPort == 0 {
udpPort = 7655
}
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String())
lhost, _, err := SplitHostPort(s.conn.LocalAddr().String())
if err != nil {
s.Close()
return nil, err
@ -46,7 +46,7 @@ func (s *SAM) NewDatagramSession(id string, keys i2pkeys.I2PKeys, options []stri
if err != nil {
return nil, err
}
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String())
rhost, _, err := SplitHostPort(s.conn.RemoteAddr().String())
if err != nil {
s.Close()
return nil, err

13
emit.go
View File

@ -3,6 +3,7 @@ package sam3
import (
"fmt"
"log"
"net"
"strings"
)
@ -107,3 +108,15 @@ func IgnorePortError(err error) error {
}
return err
}
func SplitHostPort(hostport string) (string, string, error) {
host, port, err := net.SplitHostPort(hostport)
if err != nil {
if IgnorePortError(err) == nil {
log.Println("host: " + hostport)
host = hostport
port = "0"
}
}
return host, port, nil
}

View File

@ -11,7 +11,7 @@ import (
)
func NetListener(name, samaddr, keyspath string) (net.Listener, error) {
return I2PListener(name, samaddr, keyspath)
return I2PListener(name, sam3.SAMDefaultAddr(samaddr), keyspath)
}
// I2PListener is a convenience function which takes a SAM tunnel name, a SAM address and a filename.
@ -19,7 +19,7 @@ func NetListener(name, samaddr, keyspath string) (net.Listener, error) {
// exist, keys will be generated and stored in that file.
func I2PListener(name, samaddr, keyspath string) (*sam3.StreamListener, error) {
log.Printf("Starting and registering I2P service, please wait a couple of minutes...")
listener, err := I2PStreamSession(name, samaddr, keyspath)
listener, err := I2PStreamSession(name, sam3.SAMDefaultAddr(samaddr), keyspath)
if keyspath != "" {
err = ioutil.WriteFile(keyspath+".i2p.public.txt", []byte(listener.Keys().Addr().Base32()), 0644)
@ -36,9 +36,9 @@ func I2PListener(name, samaddr, keyspath string) (*sam3.StreamListener, error) {
// of the user.
func I2PStreamSession(name, samaddr, keyspath string) (*sam3.StreamSession, error) {
log.Printf("Starting and registering I2P session...")
sam, err := sam3.NewSAM(samaddr)
sam, err := sam3.NewSAM(sam3.SAMDefaultAddr(samaddr))
if err != nil {
log.Fatalf("error connecting to SAM to %s: %s", samaddr, err)
log.Fatalf("error connecting to SAM to %s: %s", sam3.SAMDefaultAddr(samaddr), err)
}
keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil {
@ -52,9 +52,9 @@ func I2PStreamSession(name, samaddr, keyspath string) (*sam3.StreamSession, erro
// It also takes care of setting a persisitent key on behalf of the user.
func I2PDatagramSession(name, samaddr, keyspath string) (*sam3.DatagramSession, error) {
log.Printf("Starting and registering I2P session...")
sam, err := sam3.NewSAM(samaddr)
sam, err := sam3.NewSAM(sam3.SAMDefaultAddr(samaddr))
if err != nil {
log.Fatalf("error connecting to SAM to %s: %s", samaddr, err)
log.Fatalf("error connecting to SAM to %s: %s", sam3.SAMDefaultAddr(samaddr), err)
}
keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil {
@ -68,9 +68,9 @@ func I2PDatagramSession(name, samaddr, keyspath string) (*sam3.DatagramSession,
// It also takes care of setting a persisitent key on behalf of the user.
func I2PPrimarySession(name, samaddr, keyspath string) (*sam3.PrimarySession, error) {
log.Printf("Starting and registering I2P session...")
sam, err := sam3.NewSAM(samaddr)
sam, err := sam3.NewSAM(sam3.SAMDefaultAddr(samaddr))
if err != nil {
log.Fatalf("error connecting to SAM to %s: %s", samaddr, err)
log.Fatalf("error connecting to SAM to %s: %s", sam3.SAMDefaultAddr(samaddr), err)
}
keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil {
@ -80,9 +80,15 @@ func I2PPrimarySession(name, samaddr, keyspath string) (*sam3.PrimarySession, er
return gram, err
}
// GenerateOrLoadKeys is a convenience function which takes a filename and a SAM session.
// if the SAM session is nil, a new one will be created with the defaults.
// The keyspath must be the path to a place to store I2P keys. The keyspath will be suffixed with
// .i2p.private for the private keys, and public.txt for the b32 addresses.
// If the keyspath.i2p.private file does not exist, keys will be generated and stored in that file.
// if the keyspath.i2p.private does exist, keys will be loaded from that location and returned
func GenerateOrLoadKeys(keyspath string, sam *sam3.SAM) (keys *i2pkeys.I2PKeys, err error) {
if sam == nil {
sam, err = sam3.NewSAM("127.0.0.1:7657")
sam, err = sam3.NewSAM(sam3.SAMDefaultAddr("127.0.0.1:7656"))
if err != nil {
return nil, err
}
@ -112,6 +118,8 @@ func GenerateOrLoadKeys(keyspath string, sam *sam3.SAM) (keys *i2pkeys.I2PKeys,
return keys, nil
}
// GenerateKeys is a shorter version of GenerateOrLoadKeys which generates keys and stores them in a file.
// it always uses a new default SAM session.
func GenerateKeys(keyspath string) (keys *i2pkeys.I2PKeys, err error) {
return GenerateOrLoadKeys(keyspath, nil)
}

View File

@ -77,9 +77,11 @@ func (ss *PrimarySession) Keys() i2pkeys.I2PKeys {
func (sam *PrimarySession) Dial(network, addr string) (net.Conn, error) {
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)
}
return nil, fmt.Errorf("Error: Must specify a valid network type")
@ -87,52 +89,56 @@ func (sam *PrimarySession) Dial(network, addr string) (net.Conn, error) {
// DialTCP implements x/dialer
func (sam *PrimarySession) DialTCP(network string, laddr, raddr net.Addr) (net.Conn, error) {
_, ok := sam.stsess[network+raddr.String()[0:4]]
ts, ok := sam.stsess[network+raddr.String()[0:4]]
var err error
if !ok {
stsess, err := sam.NewUniqueStreamSubSession(network + raddr.String()[0:4])
ts, err = sam.NewUniqueStreamSubSession(network + raddr.String()[0:4])
if err != nil {
return nil, err
}
sam.stsess[network+raddr.String()[0:4]] = stsess
sam.stsess[network+raddr.String()[0:4]] = ts
}
return sam.stsess[network+raddr.String()[0:4]].Dial(network, raddr.String())
return ts.Dial(network, raddr.String())
}
func (sam *PrimarySession) DialTCPI2P(network string, laddr, raddr string) (net.Conn, error) {
_, ok := sam.stsess[network+raddr[0:4]]
ts, ok := sam.stsess[network+raddr[0:4]]
var err error
if !ok {
stsess, err := sam.NewUniqueStreamSubSession(network + laddr)
ts, err = sam.NewUniqueStreamSubSession(network + laddr)
if err != nil {
return nil, err
}
sam.stsess[network+raddr[0:4]] = stsess
sam.stsess[network+raddr[0:4]] = ts
}
return sam.stsess[network+raddr[0:4]].Dial(network, raddr)
return ts.Dial(network, raddr)
}
// DialUDP implements x/dialer
func (sam *PrimarySession) DialUDP(network string, laddr, raddr net.Addr) (net.PacketConn, error) {
_, ok := sam.dgsess[network+raddr.String()[0:4]]
ds, ok := sam.dgsess[network+raddr.String()[0:4]]
var err error
if !ok {
dgsess, err := sam.NewDatagramSubSession(network+raddr.String()[0:4], 0)
ds, err = sam.NewDatagramSubSession(network+raddr.String()[0:4], 0)
if err != nil {
return nil, err
}
sam.dgsess[network+raddr.String()[0:4]] = dgsess
sam.dgsess[network+raddr.String()[0:4]] = ds
}
return sam.dgsess[network+raddr.String()[0:4]].Dial(network, raddr.String())
return ds.Dial(network, raddr.String())
}
func (sam *PrimarySession) DialUDPI2P(network, laddr, raddr string) (*DatagramSession, error) {
_, ok := sam.dgsess[network+raddr[0:4]]
ds, ok := sam.dgsess[network+raddr[0:4]]
var err error
if !ok {
dgsess, err := sam.NewDatagramSubSession(network+laddr, 0)
ds, err = sam.NewDatagramSubSession(network+laddr, 0)
if err != nil {
return nil, err
}
sam.dgsess[network+raddr[0:4]] = dgsess
sam.dgsess[network+raddr[0:4]] = ds
}
return sam.dgsess[network+raddr[0:4]].Dial(network, raddr)
return ds.Dial(network, raddr)
}
func (s *PrimarySession) Lookup(name string) (a net.Addr, err error) {
@ -205,13 +211,13 @@ func (sam *PrimarySession) newGenericSubSessionWithSignatureAndPorts(style, id,
conn := sam.conn
fp := ""
tp := ""
if from != "0" {
if from != "0" && from != "" {
fp = " FROM_PORT=" + from
}
if to != "0" {
if to != "0" && to != "" {
tp = " TO_PORT=" + to
}
scmsg := []byte("SESSION ADD STYLE=" + style + fp + tp + " ID=" + id + " " + strings.Join(extras, " ") + "\n")
scmsg := []byte("SESSION ADD STYLE=" + style + " ID=" + id + fp + tp + " " + strings.Join(extras, " ") + "\n")
for m, i := 0, 0; m != len(scmsg); i++ {
if i == 15 {
conn.Close()
@ -245,7 +251,7 @@ func (sam *PrimarySession) newGenericSubSessionWithSignatureAndPorts(style, id,
return nil, errors.New("Duplicate destination")
} else if text == session_INVALID_KEY {
conn.Close()
return nil, errors.New("Invalid key")
return nil, errors.New("Invalid key - Primary Session")
} else if strings.HasPrefix(text, session_I2P_ERROR) {
conn.Close()
return nil, errors.New("I2P error " + text[len(session_I2P_ERROR):])
@ -272,7 +278,7 @@ func (sam *PrimarySession) NewUniqueStreamSubSession(id string) (*StreamSession,
if err != nil {
return nil, err
}
return &StreamSession{sam.Config.I2PConfig.Sam(), id, conn, sam.keys, time.Duration(600 * time.Second), time.Now(), Sig_NONE, randport(), "0"}, nil
return &StreamSession{sam.Config.I2PConfig.Sam(), id, conn, sam.keys, time.Duration(600 * time.Second), time.Now(), Sig_NONE, randport(), randport()}, nil
}
// Creates a new StreamSession with the I2CP- and streaminglib options as
@ -304,7 +310,7 @@ func (s *PrimarySession) NewDatagramSubSession(id string, udpPort int) (*Datagra
if udpPort == 0 {
udpPort = 7655
}
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String())
lhost, _, err := SplitHostPort(s.conn.LocalAddr().String())
if err != nil {
s.Close()
return nil, err
@ -317,7 +323,7 @@ func (s *PrimarySession) NewDatagramSubSession(id string, udpPort int) (*Datagra
if err != nil {
return nil, err
}
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String())
rhost, _, err := SplitHostPort(s.conn.RemoteAddr().String())
if err != nil {
s.Close()
return nil, err
@ -347,7 +353,7 @@ func (s *PrimarySession) NewRawSubSession(id string, udpPort int) (*RawSession,
if udpPort == 0 {
udpPort = 7655
}
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String())
lhost, _, err := SplitHostPort(s.conn.LocalAddr().String())
if err != nil {
s.Close()
return nil, err
@ -360,7 +366,7 @@ func (s *PrimarySession) NewRawSubSession(id string, udpPort int) (*RawSession,
if err != nil {
return nil, err
}
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String())
rhost, _, err := SplitHostPort(s.conn.RemoteAddr().String())
if err != nil {
s.Close()
return nil, err

View File

@ -2,12 +2,12 @@ package sam3
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"testing"
"time"
"github.com/eyedeekay/i2pkeys"
)
func Test_PrimaryStreamingDial(t *testing.T) {
@ -220,73 +220,85 @@ func ExamplePrimaryStreamListener() {
const samBridge = "127.0.0.1:7656"
earlysam, err := NewSAM(yoursam)
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.NewStreamSubSessionWithPorts("PrimaryListenerServerTunnel2", "3", "4")
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")
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 earlysam.Close()
keys, err := earlysam.NewKeys()
defer latesam.Close()
keys2, err := latesam.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()
quit := make(chan bool)
// Client connecting to the server
go func(server i2pkeys.I2PAddr) {
cs, err := sam.NewUniqueStreamSubSession("PrimaryListenerTunnel")
if err != nil {
fmt.Println(err.Error())
quit <- false
return
}
defer cs.Close()
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.NewUniqueStreamSubSession("PrimaryListenerTunnel")
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 ss.Close()
l, err := ss.Listen()
defer sc.Close()
client := http.Client{
Transport: &http.Transport{
Dial: sc.Dial,
},
}
resp, err := client.Get("http://" + ss.Addr().Base32())
if err != nil {
fmt.Println(err.Error())
return
}
conn, err := l.Accept()
defer resp.Body.Close()
r, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err.Error())
return
}
conn.Write([]byte("Hello world!"))
<-quit // waits for client to die, for example only
fmt.Println("Got response: " + string(r))
// Output:
//Hello world!
// Hello world!
}
type exitHandler struct {
}
func (e *exitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
}

4
raw.go
View File

@ -34,7 +34,7 @@ func (s *SAM) NewRawSession(id string, keys i2pkeys.I2PKeys, options []string, u
if udpPort == 0 {
udpPort = 7655
}
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String())
lhost, _, err := SplitHostPort(s.conn.LocalAddr().String())
if err != nil {
s.Close()
return nil, err
@ -47,7 +47,7 @@ func (s *SAM) NewRawSession(id string, keys i2pkeys.I2PKeys, options []string, u
if err != nil {
return nil, err
}
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String())
rhost, _, err := SplitHostPort(s.conn.RemoteAddr().String())
if err != nil {
s.Close()
return nil, err

View File

@ -108,7 +108,7 @@ func (s *StreamSession) Lookup(name string) (i2pkeys.I2PAddr, error) {
sam, err := NewSAM(s.samAddr)
if err == nil {
addr, err := sam.Lookup(name)
sam.Close()
defer sam.Close()
return addr, err
}
return i2pkeys.I2PAddr(""), err
@ -177,15 +177,19 @@ func (s *StreamSession) Dial(n, addr string) (c net.Conn, err error) {
var i2paddr i2pkeys.I2PAddr
var host string
host, _, err = net.SplitHostPort(addr)
host, _, err = SplitHostPort(addr)
//log.Println("Dialing:", host)
if err = IgnorePortError(err); err == nil {
// check for name
if strings.HasSuffix(host, ".b32.i2p") || strings.HasSuffix(host, ".i2p") {
// name lookup
i2paddr, err = s.Lookup(host)
//log.Println("Lookup:", i2paddr, err)
} else {
// probably a destination
i2paddr = i2pkeys.I2PAddr(host)
i2paddr, err = i2pkeys.NewI2PAddrFromBytes([]byte(host))
//i2paddr = i2pkeys.I2PAddr(host)
//log.Println("Destination:", i2paddr, err)
}
if err == nil {
return s.DialI2P(i2paddr)
@ -230,7 +234,7 @@ func (s *StreamSession) DialI2P(addr i2pkeys.I2PAddr) (*SAMConn, error) {
return nil, errors.New("I2P internal error")
case "RESULT=INVALID_KEY":
conn.Close()
return nil, errors.New("Invalid key")
return nil, errors.New("Invalid key - Stream Session")
case "RESULT=INVALID_ID":
conn.Close()
return nil, errors.New("Invalid tunnel ID")

View File

@ -86,7 +86,6 @@ func (l *StreamListener) AcceptI2P() (*SAMConn, error) {
if strings.HasPrefix(line, "STREAM STATUS RESULT=OK") {
// we gud read destination line
destline, err := rd.ReadString(10)
log.Println(destline)
if err == nil {
dest := ExtractDest(destline)
l.session.from = ExtractPairString(destline, "FROM_PORT")

View File

@ -1,6 +1,10 @@
package sam3
import "net/http"
import (
"net"
"net/http"
"os"
)
// Examples and suggestions for options when creating sessions.
var (
@ -64,7 +68,24 @@ func PrimarySessionString() string {
return "PRIMARY"
}
return "MASTER"
}
var PrimarySessionSwitch string = PrimarySessionString()
func getEnv(key, fallback string) string {
value, ok := os.LookupEnv(key)
if !ok {
return fallback
}
return value
}
var SAM_HOST = getEnv("sam_host", "127.0.0.1")
var SAM_PORT = getEnv("sam_port", "7656")
func SAMDefaultAddr(fallforward string) string {
if fallforward == "" {
return net.JoinHostPort(SAM_HOST, SAM_PORT)
}
return fallforward
}