11 Commits

Author SHA1 Message Date
idk
0e87ddfa4b Bump and create a tag for @allhailjarjar's checkin. 2021-10-29 16:25:10 -04:00
idk
9e3532c81b Merge pull request #8 from allhailjarjar/master
Readme update and code cleanup from @allhailjarjar approved @eyedeekay
2021-10-29 16:19:21 -04:00
idk
ca8d8688cb Split key generation out in helper 2021-10-27 22:38:52 -04:00
idk
ef67dc1e44 Split key generation out in helper 2021-10-27 22:38:21 -04:00
allhailjarjar666
9a162e9502 Readme update and code cleanup 2021-10-04 21:00:03 -04:00
idk
31b8d62f04 Allow passing either pointer or instance to DialI2PRemote in DatagramSession 2021-07-18 15:06:49 -04:00
idk
d191b3404e Allow passing either pointer or instance to DialI2PRemote in DatagramSession 2021-07-18 15:05:36 -04:00
idk
1de06ec9b9 Allow passing either pointer or instance to DialI2PRemote in DatagramSession 2021-07-18 15:05:02 -04:00
idk
ed814a2fc6 Add SetReadDeadline and SetWriteDeadline to StreamSession 2021-04-15 21:11:56 -04:00
idk
746084e65f Add localaddr to streamsession 2021-04-15 20:51:07 -04:00
idk
1a55eb6e90 Merge branch 'easy-keys' into 'master'
Support SAMv3.3 PRIMARY sessions and all 3 types of SubSessions

See merge request idk/sam3!1
2021-04-15 00:50:41 +00:00
8 changed files with 199 additions and 190 deletions

View File

@@ -1,6 +1,6 @@
USER_GH=eyedeekay
VERSION=0.33.001
VERSION=0.33.01
packagename=sam3
echo:

View File

@@ -23,7 +23,7 @@ This library is much better than ccondom (that use BOB), much more stable and mu
**Does not work:**
* Everything works! :D
* Stream Forwarding
* Probably needs some real-world testing
## Documentation ##
@@ -38,16 +38,17 @@ This library is much better than ccondom (that use BOB), much more stable and mu
package main
import (
"github.com/majestrate/i2p-tools/sam3"
"github.com/eyedeekay/sam3"
"github.com/eyedeekay/sam3/i2pkeys"
"fmt"
)
const yoursam = "127.0.0.1:7656" // sam bridge
func client(server I2PAddr) {
sam, _ := NewSAM(yoursam)
func client(server i2pkeys.I2PAddr) {
sam, _ := sam3.NewSAM(yoursam)
keys, _ := sam.NewKeys()
stream, _ := sam.NewStreamSession("clientTun", keys, Options_Small)
stream, _ := sam.NewStreamSession("clientTun", keys, sam3.Options_Small)
fmt.Println("Client: Connecting to " + server.Base32())
conn, _ := stream.DialI2P(server)
conn.Write([]byte("Hello world!"))
@@ -57,11 +58,9 @@ func client(server I2PAddr) {
func main() {
sam, _ := NewSAM(yoursam)
keys, _ := sam.NewKeys()
stream, _ := sam.NewStreamSession("serverTun", keys, Options_Medium)
stream, _ := sam.NewStreamSession("serverTun", keys, sam3.Options_Medium)
listener, _ := stream.Listen()
go client(keys.Addr())
stream, _ := sam.NewStreamSession("serverTun", keys, Options_Medium)
listener, _ := stream.Listen()
conn, _ := listener.Accept()
buf := make([]byte, 4096)
n, _ := conn.Read(buf)

View File

@@ -1,9 +1,10 @@
package sam3
import (
"github.com/eyedeekay/sam3/i2pkeys"
"net"
"time"
"github.com/eyedeekay/sam3/i2pkeys"
)
/*

View File

@@ -84,7 +84,13 @@ func (s *DatagramSession) DialRemote(net, addr string) (net.PacketConn, error) {
}
func (s *DatagramSession) DialI2PRemote(net string, addr net.Addr) (*DatagramSession, error) {
s.remoteAddr = addr.(*i2pkeys.I2PAddr)
switch addr.(type) {
case *i2pkeys.I2PAddr:
s.remoteAddr = addr.(*i2pkeys.I2PAddr)
case i2pkeys.I2PAddr:
i2paddr := addr.(i2pkeys.I2PAddr)
s.remoteAddr = &i2paddr
}
return s, nil
}

View File

@@ -27,7 +27,8 @@ func I2PListener(name, samaddr, keyspath string) (*sam3.StreamListener, error) {
log.Fatalf("error storing I2P base32 address in adjacent text file, %s", err)
}
}
return listener.Listen() //, err
log.Printf("Listening on: %s", listener.Addr().Base32())
return listener.Listen()
}
// I2PStreamSession is a convenience function which returns a sam3.StreamSession instead
@@ -39,30 +40,9 @@ func I2PStreamSession(name, samaddr, keyspath string) (*sam3.StreamSession, erro
if err != nil {
log.Fatalf("error connecting to SAM to %s: %s", samaddr, err)
}
var keys *i2pkeys.I2PKeys
if keyspath != "" {
if _, err := os.Stat(keyspath + ".i2p.private"); os.IsNotExist(err) {
f, err := os.Create(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to open I2P keyfile for writing: %s", err)
}
defer f.Close()
tkeys, err := sam.NewKeys()
if err != nil {
log.Fatalf("unable to generate I2P Keys, %s", err)
}
keys = &tkeys
err = i2pkeys.StoreKeysIncompat(*keys, f)
if err != nil {
log.Fatalf("unable to save newly generated I2P Keys, %s", err)
}
} else {
tkeys, err := i2pkeys.LoadKeys(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to load I2P Keys: %e", err)
}
keys = &tkeys
}
keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil {
return nil, err
}
stream, err := sam.NewStreamSession(name, *keys, sam3.Options_Medium)
return stream, err
@@ -76,30 +56,9 @@ func I2PDatagramSession(name, samaddr, keyspath string) (*sam3.DatagramSession,
if err != nil {
log.Fatalf("error connecting to SAM to %s: %s", samaddr, err)
}
var keys *i2pkeys.I2PKeys
if keyspath != "" {
if _, err := os.Stat(keyspath + ".i2p.private"); os.IsNotExist(err) {
f, err := os.Create(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to open I2P keyfile for writing: %s", err)
}
defer f.Close()
tkeys, err := sam.NewKeys()
if err != nil {
log.Fatalf("unable to generate I2P Keys, %s", err)
}
keys = &tkeys
err = i2pkeys.StoreKeysIncompat(*keys, f)
if err != nil {
log.Fatalf("unable to save newly generated I2P Keys, %s", err)
}
} else {
tkeys, err := i2pkeys.LoadKeys(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to load I2P Keys: %e", err)
}
keys = &tkeys
}
keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil {
return nil, err
}
gram, err := sam.NewDatagramSession(name, *keys, sam3.Options_Medium, 0)
return gram, err
@@ -113,31 +72,46 @@ func I2PPrimarySession(name, samaddr, keyspath string) (*sam3.PrimarySession, er
if err != nil {
log.Fatalf("error connecting to SAM to %s: %s", samaddr, err)
}
var keys *i2pkeys.I2PKeys
if keyspath != "" {
if _, err := os.Stat(keyspath + ".i2p.private"); os.IsNotExist(err) {
f, err := os.Create(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to open I2P keyfile for writing: %s", err)
}
defer f.Close()
tkeys, err := sam.NewKeys()
if err != nil {
log.Fatalf("unable to generate I2P Keys, %s", err)
}
keys = &tkeys
err = i2pkeys.StoreKeysIncompat(*keys, f)
if err != nil {
log.Fatalf("unable to save newly generated I2P Keys, %s", err)
}
} else {
tkeys, err := i2pkeys.LoadKeys(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to load I2P Keys: %e", err)
}
keys = &tkeys
}
keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil {
return nil, err
}
gram, err := sam.NewPrimarySession(name, *keys, sam3.Options_Medium)
return gram, err
}
func GenerateOrLoadKeys(keyspath string, sam *sam3.SAM) (keys *i2pkeys.I2PKeys, err error) {
if sam == nil {
sam, err = sam3.NewSAM("127.0.0.1:7657")
if err != nil {
return nil, err
}
}
if _, err := os.Stat(keyspath + ".i2p.private"); os.IsNotExist(err) {
f, err := os.Create(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to open I2P keyfile for writing: %s", err)
}
defer f.Close()
tkeys, err := sam.NewKeys()
if err != nil {
log.Fatalf("unable to generate I2P Keys, %s", err)
}
keys = &tkeys
err = i2pkeys.StoreKeysIncompat(*keys, f)
if err != nil {
log.Fatalf("unable to save newly generated I2P Keys, %s", err)
}
} else {
tkeys, err := i2pkeys.LoadKeys(keyspath + ".i2p.private")
if err != nil {
log.Fatalf("unable to load I2P Keys: %e", err)
}
keys = &tkeys
}
return keys, nil
}
func GenerateKeys(keyspath string) (keys *i2pkeys.I2PKeys, err error) {
return GenerateOrLoadKeys(keyspath, nil)
}

View File

@@ -7,6 +7,7 @@ import (
"log"
"strings"
"testing"
"time"
"github.com/eyedeekay/sam3/i2pkeys"
)
@@ -98,11 +99,12 @@ func Test_PrimaryStreamingServerClient(t *testing.T) {
}
defer sam.Close()
fmt.Println("\tServer: Creating tunnel")
ss, err := sam.NewStreamSubSession("primaryExampleServerTun")
ss, err := sam.NewUniqueStreamSubSession("primaryExampleServerTun")
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) {

121
stream.go
View File

@@ -6,9 +6,7 @@ import (
"context"
"errors"
"io"
"log"
"net"
"strconv"
"strings"
"time"
@@ -28,6 +26,18 @@ type StreamSession struct {
to string
}
func (s *StreamSession) SetDeadline(t time.Time) error {
return s.conn.SetDeadline(t)
}
func (s *StreamSession) SetReadDeadline(t time.Time) error {
return s.conn.SetReadDeadline(t)
}
func (s *StreamSession) SetWriteDeadline(t time.Time) error {
return s.conn.SetWriteDeadline(t)
}
func (ss *StreamSession) From() string {
return ss.from
}
@@ -54,6 +64,10 @@ func (ss *StreamSession) Addr() i2pkeys.I2PAddr {
return ss.keys.Addr()
}
func (ss *StreamSession) LocalAddr() net.Addr {
return ss.keys.Addr()
}
// Returns the keys associated with the stream session
func (ss *StreamSession) Keys() i2pkeys.I2PKeys {
return ss.keys
@@ -239,106 +253,3 @@ func (s *StreamSession) Listen() (*StreamListener, error) {
laddr: s.keys.Addr(),
}, nil
}
type StreamListener struct {
// parent stream session
session *StreamSession
// our session id
id string
// our local address for this sam socket
laddr i2pkeys.I2PAddr
}
func (l *StreamListener) From() string {
return l.session.from
}
func (l *StreamListener) To() string {
return l.session.to
}
// get our address
// implements net.Listener
func (l *StreamListener) Addr() net.Addr {
return l.laddr
}
// implements net.Listener
func (l *StreamListener) Close() error {
return l.session.Close()
}
// implements net.Listener
func (l *StreamListener) Accept() (net.Conn, error) {
return l.AcceptI2P()
}
func ExtractPairString(input, value string) string {
parts := strings.Split(input, " ")
for _, part := range parts {
if strings.HasPrefix(part, value) {
kv := strings.SplitN(input, "=", 2)
if len(kv) == 2 {
return kv[1]
}
}
}
return ""
}
func ExtractPairInt(input, value string) int {
rv, err := strconv.Atoi(ExtractPairString(input, value))
if err != nil {
return 0
}
return rv
}
func ExtractDest(input string) string {
return strings.Split(input, " ")[0]
}
// accept a new inbound connection
func (l *StreamListener) AcceptI2P() (*SAMConn, error) {
s, err := NewSAM(l.session.samAddr)
if err == nil {
// we connected to sam
// send accept() command
_, err = io.WriteString(s.conn, "STREAM ACCEPT ID="+l.id+" SILENT=false\n")
// read reply
rd := bufio.NewReader(s.conn)
// read first line
line, err := rd.ReadString(10)
log.Println(line)
if err == nil {
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")
l.session.to = ExtractPairString(destline, "TO_PORT")
// return wrapped connection
dest = strings.Trim(dest, "\n")
return &SAMConn{
laddr: l.laddr,
raddr: i2pkeys.I2PAddr(dest),
conn: s.conn,
}, nil
} else {
s.Close()
return nil, err
}
} else {
s.Close()
return nil, errors.New("invalid sam line: " + line)
}
} else {
s.Close()
return nil, err
}
}
s.Close()
return nil, err
}

116
streamListener.go Normal file
View File

@@ -0,0 +1,116 @@
package sam3
import (
"bufio"
"errors"
"io"
"log"
"net"
"strconv"
"strings"
"github.com/eyedeekay/sam3/i2pkeys"
)
type StreamListener struct {
// parent stream session
session *StreamSession
// our session id
id string
// our local address for this sam socket
laddr i2pkeys.I2PAddr
}
func (l *StreamListener) From() string {
return l.session.from
}
func (l *StreamListener) To() string {
return l.session.to
}
// get our address
// implements net.Listener
func (l *StreamListener) Addr() net.Addr {
return l.laddr
}
// implements net.Listener
func (l *StreamListener) Close() error {
return l.session.Close()
}
// implements net.Listener
func (l *StreamListener) Accept() (net.Conn, error) {
return l.AcceptI2P()
}
func ExtractPairString(input, value string) string {
parts := strings.Split(input, " ")
for _, part := range parts {
if strings.HasPrefix(part, value) {
kv := strings.SplitN(input, "=", 2)
if len(kv) == 2 {
return kv[1]
}
}
}
return ""
}
func ExtractPairInt(input, value string) int {
rv, err := strconv.Atoi(ExtractPairString(input, value))
if err != nil {
return 0
}
return rv
}
func ExtractDest(input string) string {
return strings.Split(input, " ")[0]
}
// accept a new inbound connection
func (l *StreamListener) AcceptI2P() (*SAMConn, error) {
s, err := NewSAM(l.session.samAddr)
if err == nil {
// we connected to sam
// send accept() command
_, err = io.WriteString(s.conn, "STREAM ACCEPT ID="+l.id+" SILENT=false\n")
// read reply
rd := bufio.NewReader(s.conn)
// read first line
line, err := rd.ReadString(10)
log.Println(line)
if err == nil {
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")
l.session.to = ExtractPairString(destline, "TO_PORT")
// return wrapped connection
dest = strings.Trim(dest, "\n")
return &SAMConn{
laddr: l.laddr,
raddr: i2pkeys.I2PAddr(dest),
conn: s.conn,
}, nil
} else {
s.Close()
return nil, err
}
} else {
s.Close()
return nil, errors.New("invalid sam line: " + line)
}
} else {
s.Close()
return nil, err
}
}
s.Close()
return nil, err
}