30 Commits

Author SHA1 Message Date
eyedeekay
cd2a4f072e update i2pkeys library to new version 2024-09-17 19:40:10 -04:00
eyedeekay
818b5249bc Add credit for contribution to release info 2024-09-17 19:35:15 -04:00
idk
83f9866de4 Merge pull request #10 from hkh4n/refactor
Refactored error handling in sam3.go
2024-09-12 12:26:56 -04:00
Haris Khan
b4293f755e refactored error handling in NewKeys() and newGenericSessionWithSignatureAndPorts() 2024-09-10 19:55:28 -04:00
Haris Khan
2bde2687b3 refactored error handling in NewSAM(), included "fmt" 2024-09-10 19:21:06 -04:00
eyedeekay
19d8d8e4a8 Update module to i2pkeys@v0.33.7 2024-01-09 14:45:40 -05:00
eyedeekay
1cec982a61 bump version 0.33.7 2024-01-09 14:22:29 -05:00
eyedeekay
b2df466212 Don't leave errors unchecked. gofmt again. 2024-01-09 14:20:35 -05:00
eyedeekay
bf2a12d78d fix misspellings 2024-01-09 13:40:42 -05:00
eyedeekay
760e0b44b2 gofmt -s 2024-01-09 13:37:49 -05:00
eyedeekay
9b7a798782 Add a space when specifying the port to a datagram session 2024-01-09 13:34:49 -05:00
eyedeekay
3dc49e391d force an enctype if one is not present 2024-01-07 12:09:13 -05:00
eyedeekay
b08d519a17 bump version 2023-07-21 15:10:09 -04:00
idk
256aaa7430 update go modules 2023-03-07 02:19:24 +00:00
idk
197aca0ece Never pass Sig_NONE again, if sig is unset, use the correct default sig 2023-01-16 04:18:11 +00:00
idk
fff37dbffa Never pass Sig_NONE again, if sig is unset, use the correct default sig 2023-01-16 04:17:51 +00:00
idk
dfd7cd886f update index.html 2022-08-28 13:40:47 -04:00
idk
c998e57a89 update index.html 2022-08-28 13:38:27 -04:00
idk
41317685c5 update index.html 2022-08-28 13:36:46 -04:00
idk
56cca2e537 bump version 2022-08-08 18:09:36 -04:00
idk
9ca67baa32 don't let the primary session thing be a guess, detect first, then attempt one and cache the result 2022-08-08 17:43:43 -04:00
idk
9083650fd0 switch to github-release 2022-08-05 11:57:22 -04:00
idk
34eafde2e2 bump version 2022-08-05 11:56:51 -04:00
idk
1780908fb8 add logging detail 2022-08-05 01:48:06 -04:00
idk
615604699a update index.html 2022-08-04 18:07:18 -04:00
idk
fb14beb87f update index.html 2022-07-31 18:03:00 -04:00
idk
6fb498e01e update index.html 2022-07-31 17:40:28 -04:00
idk
c80e6e7d95 update index.html 2022-07-31 17:39:38 -04:00
idk
ee9930813d fixes primary tunnel test 2022-06-01 18:25:24 -04:00
idk
3d289d99c6 fix some primary sessions, grab some defaults from environment 2022-05-31 23:59:37 -04:00
22 changed files with 821 additions and 293 deletions

0
.nojekyll Normal file
View File

View File

@@ -1,16 +1,17 @@
USER_GH=eyedeekay USER_GH=eyedeekay
VERSION=0.33.2 VERSION=0.33.8
CREDIT='contributors to this release: @hkh4n, @eyedeekay'
packagename=sam3 packagename=sam3
echo: echo:
@echo "type make version to do release $(VERSION)" @echo "type make version to do release $(VERSION)"
version: version:
gothub release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION)" github-release release -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) -d "version $(VERSION) $(CREDIT)"
del: del:
gothub delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION) github-release delete -s $(GITHUB_TOKEN) -u $(USER_GH) -r $(packagename) -t v$(VERSION)
tar: tar:
tar --exclude .git \ tar --exclude .git \
@@ -26,4 +27,4 @@ fmt:
find . -name '*.go' -exec gofmt -w -s {} \; find . -name '*.go' -exec gofmt -w -s {} \;
upload-linux: upload-linux:
gothub upload -R -u $(USER_GH) -r "$(packagename)" -t $(VERSION) -l `sha256sum ` -n "$(packagename)" -f "$(packagename)" github-release upload -R -u $(USER_GH) -r "$(packagename)" -t $(VERSION) -l `sha256sum ` -n "$(packagename)" -f "$(packagename)"

View File

@@ -10,6 +10,8 @@ before upgrading your sam3 dependencies. You can probably do this by running:
find . -name '*.go' -exec sed -i 's|github.com/eyedeekay/sam3/i2pkeys|github.com/eyedeekay/i2pkeys|g' {} \; find . -name '*.go' -exec sed -i 's|github.com/eyedeekay/sam3/i2pkeys|github.com/eyedeekay/i2pkeys|g' {} \;
``` ```
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days.
# README # # README #
go library for the I2P [SAMv3.0](https://geti2p.net/en/docs/api/samv3) bridge, used to build anonymous/pseudonymous end-to-end encrypted sockets. go library for the I2P [SAMv3.0](https://geti2p.net/en/docs/api/samv3) bridge, used to build anonymous/pseudonymous end-to-end encrypted sockets.

View File

@@ -51,6 +51,8 @@ type I2PConfig struct {
ReduceIdle string ReduceIdle string
ReduceIdleTime string ReduceIdleTime string
ReduceIdleQuantity string ReduceIdleQuantity string
LeaseSetEncryption string
//Streaming Library options //Streaming Library options
AccessListType string AccessListType string
AccessList []string AccessList []string
@@ -234,6 +236,7 @@ func (f *I2PConfig) Print() []string {
lsk, lspk, lspsk, lsk, lspk, lspsk,
f.Accesslisttype(), f.Accesslisttype(),
f.Accesslist(), f.Accesslist(),
f.LeaseSetEncryptionType(),
} }
} }
@@ -259,6 +262,18 @@ func (f *I2PConfig) Accesslist() string {
return "" return ""
} }
func (f *I2PConfig) LeaseSetEncryptionType() string {
if f.LeaseSetEncryption == "" {
return "i2cp.leaseSetEncType=4,0"
}
for _, s := range strings.Split(f.LeaseSetEncryption, ",") {
if _, err := strconv.Atoi(s); err != nil {
panic("Invalid encrypted leaseSet type: " + s)
}
}
return "i2cp.leaseSetEncType=" + f.LeaseSetEncryption
}
func NewConfig(opts ...func(*I2PConfig) error) (*I2PConfig, error) { func NewConfig(opts ...func(*I2PConfig) error) (*I2PConfig, error) {
var config I2PConfig var config I2PConfig
config.SamHost = "127.0.0.1" config.SamHost = "127.0.0.1"

View File

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

View File

@@ -6,10 +6,10 @@ import (
"strings" "strings"
) )
//Option is a SAMEmit Option // Option is a SAMEmit Option
type Option func(*SAMEmit) error type Option func(*SAMEmit) error
//SetType sets the type of the forwarder server // SetType sets the type of the forwarder server
func SetType(s string) func(*SAMEmit) error { func SetType(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if s == "STREAM" { if s == "STREAM" {
@@ -41,7 +41,7 @@ func SetSAMAddress(s string) func(*SAMEmit) error {
} }
} }
//SetSAMHost sets the host of the SAMEmit's SAM bridge // SetSAMHost sets the host of the SAMEmit's SAM bridge
func SetSAMHost(s string) func(*SAMEmit) error { func SetSAMHost(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.SamHost = s c.I2PConfig.SamHost = s
@@ -49,7 +49,7 @@ func SetSAMHost(s string) func(*SAMEmit) error {
} }
} }
//SetSAMPort sets the port of the SAMEmit's SAM bridge using a string // SetSAMPort sets the port of the SAMEmit's SAM bridge using a string
func SetSAMPort(s string) func(*SAMEmit) error { func SetSAMPort(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
port, err := strconv.Atoi(s) port, err := strconv.Atoi(s)
@@ -64,7 +64,7 @@ func SetSAMPort(s string) func(*SAMEmit) error {
} }
} }
//SetName sets the host of the SAMEmit's SAM bridge // SetName sets the host of the SAMEmit's SAM bridge
func SetName(s string) func(*SAMEmit) error { func SetName(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.TunName = s c.I2PConfig.TunName = s
@@ -72,7 +72,7 @@ func SetName(s string) func(*SAMEmit) error {
} }
} }
//SetInLength sets the number of hops inbound // SetInLength sets the number of hops inbound
func SetInLength(u int) func(*SAMEmit) error { func SetInLength(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if u < 7 && u >= 0 { if u < 7 && u >= 0 {
@@ -83,7 +83,7 @@ func SetInLength(u int) func(*SAMEmit) error {
} }
} }
//SetOutLength sets the number of hops outbound // SetOutLength sets the number of hops outbound
func SetOutLength(u int) func(*SAMEmit) error { func SetOutLength(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if u < 7 && u >= 0 { if u < 7 && u >= 0 {
@@ -94,7 +94,7 @@ func SetOutLength(u int) func(*SAMEmit) error {
} }
} }
//SetInVariance sets the variance of a number of hops inbound // SetInVariance sets the variance of a number of hops inbound
func SetInVariance(i int) func(*SAMEmit) error { func SetInVariance(i int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if i < 7 && i > -7 { if i < 7 && i > -7 {
@@ -105,7 +105,7 @@ func SetInVariance(i int) func(*SAMEmit) error {
} }
} }
//SetOutVariance sets the variance of a number of hops outbound // SetOutVariance sets the variance of a number of hops outbound
func SetOutVariance(i int) func(*SAMEmit) error { func SetOutVariance(i int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if i < 7 && i > -7 { if i < 7 && i > -7 {
@@ -116,7 +116,7 @@ func SetOutVariance(i int) func(*SAMEmit) error {
} }
} }
//SetInQuantity sets the inbound tunnel quantity // SetInQuantity sets the inbound tunnel quantity
func SetInQuantity(u int) func(*SAMEmit) error { func SetInQuantity(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if u <= 16 && u > 0 { if u <= 16 && u > 0 {
@@ -127,7 +127,7 @@ func SetInQuantity(u int) func(*SAMEmit) error {
} }
} }
//SetOutQuantity sets the outbound tunnel quantity // SetOutQuantity sets the outbound tunnel quantity
func SetOutQuantity(u int) func(*SAMEmit) error { func SetOutQuantity(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if u <= 16 && u > 0 { if u <= 16 && u > 0 {
@@ -138,7 +138,7 @@ func SetOutQuantity(u int) func(*SAMEmit) error {
} }
} }
//SetInBackups sets the inbound tunnel backups // SetInBackups sets the inbound tunnel backups
func SetInBackups(u int) func(*SAMEmit) error { func SetInBackups(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if u < 6 && u >= 0 { if u < 6 && u >= 0 {
@@ -149,7 +149,7 @@ func SetInBackups(u int) func(*SAMEmit) error {
} }
} }
//SetOutBackups sets the inbound tunnel backups // SetOutBackups sets the inbound tunnel backups
func SetOutBackups(u int) func(*SAMEmit) error { func SetOutBackups(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if u < 6 && u >= 0 { if u < 6 && u >= 0 {
@@ -160,7 +160,7 @@ func SetOutBackups(u int) func(*SAMEmit) error {
} }
} }
//SetEncrypt tells the router to use an encrypted leaseset // SetEncrypt tells the router to use an encrypted leaseset
func SetEncrypt(b bool) func(*SAMEmit) error { func SetEncrypt(b bool) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if b { if b {
@@ -172,7 +172,7 @@ func SetEncrypt(b bool) func(*SAMEmit) error {
} }
} }
//SetLeaseSetKey sets the host of the SAMEmit's SAM bridge // SetLeaseSetKey sets the host of the SAMEmit's SAM bridge
func SetLeaseSetKey(s string) func(*SAMEmit) error { func SetLeaseSetKey(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.LeaseSetKey = s c.I2PConfig.LeaseSetKey = s
@@ -180,7 +180,7 @@ func SetLeaseSetKey(s string) func(*SAMEmit) error {
} }
} }
//SetLeaseSetPrivateKey sets the host of the SAMEmit's SAM bridge // SetLeaseSetPrivateKey sets the host of the SAMEmit's SAM bridge
func SetLeaseSetPrivateKey(s string) func(*SAMEmit) error { func SetLeaseSetPrivateKey(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.LeaseSetPrivateKey = s c.I2PConfig.LeaseSetPrivateKey = s
@@ -188,7 +188,7 @@ func SetLeaseSetPrivateKey(s string) func(*SAMEmit) error {
} }
} }
//SetLeaseSetPrivateSigningKey sets the host of the SAMEmit's SAM bridge // SetLeaseSetPrivateSigningKey sets the host of the SAMEmit's SAM bridge
func SetLeaseSetPrivateSigningKey(s string) func(*SAMEmit) error { func SetLeaseSetPrivateSigningKey(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.LeaseSetPrivateSigningKey = s c.I2PConfig.LeaseSetPrivateSigningKey = s
@@ -196,7 +196,7 @@ func SetLeaseSetPrivateSigningKey(s string) func(*SAMEmit) error {
} }
} }
//SetMessageReliability sets the host of the SAMEmit's SAM bridge // SetMessageReliability sets the host of the SAMEmit's SAM bridge
func SetMessageReliability(s string) func(*SAMEmit) error { func SetMessageReliability(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.MessageReliability = s c.I2PConfig.MessageReliability = s
@@ -204,7 +204,7 @@ func SetMessageReliability(s string) func(*SAMEmit) error {
} }
} }
//SetAllowZeroIn tells the tunnel to accept zero-hop peers // SetAllowZeroIn tells the tunnel to accept zero-hop peers
func SetAllowZeroIn(b bool) func(*SAMEmit) error { func SetAllowZeroIn(b bool) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if b { if b {
@@ -216,7 +216,7 @@ func SetAllowZeroIn(b bool) func(*SAMEmit) error {
} }
} }
//SetAllowZeroOut tells the tunnel to accept zero-hop peers // SetAllowZeroOut tells the tunnel to accept zero-hop peers
func SetAllowZeroOut(b bool) func(*SAMEmit) error { func SetAllowZeroOut(b bool) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if b { if b {
@@ -228,7 +228,7 @@ func SetAllowZeroOut(b bool) func(*SAMEmit) error {
} }
} }
//SetCompress tells clients to use compression // SetCompress tells clients to use compression
func SetCompress(b bool) func(*SAMEmit) error { func SetCompress(b bool) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if b { if b {
@@ -240,7 +240,7 @@ func SetCompress(b bool) func(*SAMEmit) error {
} }
} }
//SetFastRecieve tells clients to use compression // SetFastRecieve tells clients to use compression
func SetFastRecieve(b bool) func(*SAMEmit) error { func SetFastRecieve(b bool) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if b { if b {
@@ -252,7 +252,7 @@ func SetFastRecieve(b bool) func(*SAMEmit) error {
} }
} }
//SetReduceIdle tells the connection to reduce it's tunnels during extended idle time. // SetReduceIdle tells the connection to reduce it's tunnels during extended idle time.
func SetReduceIdle(b bool) func(*SAMEmit) error { func SetReduceIdle(b bool) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if b { if b {
@@ -264,7 +264,7 @@ func SetReduceIdle(b bool) func(*SAMEmit) error {
} }
} }
//SetReduceIdleTime sets the time to wait before reducing tunnels to idle levels // SetReduceIdleTime sets the time to wait before reducing tunnels to idle levels
func SetReduceIdleTime(u int) func(*SAMEmit) error { func SetReduceIdleTime(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.ReduceIdleTime = "300000" c.I2PConfig.ReduceIdleTime = "300000"
@@ -276,7 +276,7 @@ func SetReduceIdleTime(u int) func(*SAMEmit) error {
} }
} }
//SetReduceIdleTimeMs sets the time to wait before reducing tunnels to idle levels in milliseconds // SetReduceIdleTimeMs sets the time to wait before reducing tunnels to idle levels in milliseconds
func SetReduceIdleTimeMs(u int) func(*SAMEmit) error { func SetReduceIdleTimeMs(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.ReduceIdleTime = "300000" c.I2PConfig.ReduceIdleTime = "300000"
@@ -288,7 +288,7 @@ func SetReduceIdleTimeMs(u int) func(*SAMEmit) error {
} }
} }
//SetReduceIdleQuantity sets minimum number of tunnels to reduce to during idle time // SetReduceIdleQuantity sets minimum number of tunnels to reduce to during idle time
func SetReduceIdleQuantity(u int) func(*SAMEmit) error { func SetReduceIdleQuantity(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if u < 5 { if u < 5 {
@@ -299,7 +299,7 @@ func SetReduceIdleQuantity(u int) func(*SAMEmit) error {
} }
} }
//SetCloseIdle tells the connection to close it's tunnels during extended idle time. // SetCloseIdle tells the connection to close it's tunnels during extended idle time.
func SetCloseIdle(b bool) func(*SAMEmit) error { func SetCloseIdle(b bool) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if b { if b {
@@ -311,7 +311,7 @@ func SetCloseIdle(b bool) func(*SAMEmit) error {
} }
} }
//SetCloseIdleTime sets the time to wait before closing tunnels to idle levels // SetCloseIdleTime sets the time to wait before closing tunnels to idle levels
func SetCloseIdleTime(u int) func(*SAMEmit) error { func SetCloseIdleTime(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.CloseIdleTime = "300000" c.I2PConfig.CloseIdleTime = "300000"
@@ -323,7 +323,7 @@ func SetCloseIdleTime(u int) func(*SAMEmit) error {
} }
} }
//SetCloseIdleTimeMs sets the time to wait before closing tunnels to idle levels in milliseconds // SetCloseIdleTimeMs sets the time to wait before closing tunnels to idle levels in milliseconds
func SetCloseIdleTimeMs(u int) func(*SAMEmit) error { func SetCloseIdleTimeMs(u int) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
c.I2PConfig.CloseIdleTime = "300000" c.I2PConfig.CloseIdleTime = "300000"
@@ -335,7 +335,7 @@ func SetCloseIdleTimeMs(u int) func(*SAMEmit) error {
} }
} }
//SetAccessListType tells the system to treat the AccessList as a whitelist // SetAccessListType tells the system to treat the AccessList as a whitelist
func SetAccessListType(s string) func(*SAMEmit) error { func SetAccessListType(s string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if s == "whitelist" { if s == "whitelist" {
@@ -355,7 +355,7 @@ func SetAccessListType(s string) func(*SAMEmit) error {
} }
} }
//SetAccessList tells the system to treat the AccessList as a whitelist // SetAccessList tells the system to treat the AccessList as a whitelist
func SetAccessList(s []string) func(*SAMEmit) error { func SetAccessList(s []string) func(*SAMEmit) error {
return func(c *SAMEmit) error { return func(c *SAMEmit) error {
if len(s) > 0 { if len(s) > 0 {

18
emit.go
View File

@@ -3,6 +3,7 @@ package sam3
import ( import (
"fmt" "fmt"
"log" "log"
"net"
"strings" "strings"
) )
@@ -11,10 +12,7 @@ type SAMEmit struct {
} }
func (e *SAMEmit) OptStr() string { func (e *SAMEmit) OptStr() string {
optStr := "" optStr := strings.Join(e.I2PConfig.Print(), " ")
for _, opt := range e.I2PConfig.Print() {
optStr += opt + " "
}
return optStr return optStr
} }
@@ -107,3 +105,15 @@ func IgnorePortError(err error) error {
} }
return err 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
}

10
go.mod
View File

@@ -2,12 +2,4 @@ module github.com/eyedeekay/sam3
go 1.12 go 1.12
require ( require github.com/eyedeekay/i2pkeys v0.33.8
github.com/eyedeekay/goSam v0.32.31-0.20210122211817-f97683379f23
github.com/eyedeekay/i2pkeys v0.0.0-20220310052025-204d4ae6dcae // indirect
github.com/google/renameio v1.0.0 // indirect
github.com/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33
github.com/rogpeppe/go-internal v1.6.2 // indirect
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b // indirect
honnef.co/go/tools v0.0.1-2020.1.6 // indirect
)

94
go.sum
View File

@@ -1,90 +1,4 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/eyedeekay/i2pkeys v0.33.7 h1:cxqHSkl6b2lHyPJUtIQZBiipYf7NQVYqM1d3ub0MI4k=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/eyedeekay/i2pkeys v0.33.7/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
github.com/agl/ed25519 v0.0.0-20200225211852-fd4d107ace12 h1:iPf1jQ8yKTms6k6L5vYSE7RZJpjEe5vLTOmzRZdpnKc= github.com/eyedeekay/i2pkeys v0.33.8 h1:f3llyruchFqs1QwCacBYbShArKPpMSSOqo/DVZXcfVs=
github.com/cryptix/go v1.3.1 h1:I9opbROgEpldI0PwkMku0UY2DLFYgelZd9u0uaxmMgY= github.com/eyedeekay/i2pkeys v0.33.8/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
github.com/cryptix/go v1.3.1/go.mod h1:mFQotm9rTzptzvNjJM+1vSIDa/rVOVqMu0889GIXg70=
github.com/cryptix/goSam v0.1.0 h1:lKXtrTv3Kd6+eIuNtcq3zPShJEVRqw+lQwmh49HmC7k=
github.com/cryptix/goSam v0.1.0/go.mod h1:7ewkjhXT8V5RG07pvWUOHHtMahvGbeKlEv8ukUyRiTA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eyedeekay/goSam v0.32.30 h1:mMlZNE2oISdjjjpgfN17W56tn9F8rD/Jc2tsjTDDFYg=
github.com/eyedeekay/goSam v0.32.30/go.mod h1:UgJnih/LpotwKriwVPOEa6yPDM2NDdVrKfLtS5DOLPE=
github.com/eyedeekay/goSam v0.32.31-0.20210122211024-dddd8ea916d6 h1:seMFdfTWvmAsyj9jYPZATBJiJu5gHPsvJJk4Ruo2npQ=
github.com/eyedeekay/goSam v0.32.31-0.20210122211024-dddd8ea916d6/go.mod h1:UgJnih/LpotwKriwVPOEa6yPDM2NDdVrKfLtS5DOLPE=
github.com/eyedeekay/goSam v0.32.31-0.20210122211817-f97683379f23 h1:AHm/EzBilSQH+RFgEuslnlCpVQd88MQWx7KHW/VIQlc=
github.com/eyedeekay/goSam v0.32.31-0.20210122211817-f97683379f23/go.mod h1:UgJnih/LpotwKriwVPOEa6yPDM2NDdVrKfLtS5DOLPE=
github.com/eyedeekay/i2pkeys v0.0.0-20220310052025-204d4ae6dcae h1:SwegHeaf4pkDMB24UltIvJlj2+nd06QUZAbs8BDyfjM=
github.com/eyedeekay/i2pkeys v0.0.0-20220310052025-204d4ae6dcae/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
github.com/eyedeekay/sam3 v0.32.32/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5/go.mod h1:kGHRXch95rnGLHjER/GhhFiHvfnqNz7KqWD9kGfATHY=
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd/go.mod h1:wKdY0ikOgzrWSeB9UyBVKPRhjXQ+vTb+BPeJuypUuNE=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-stack/stack v1.7.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio v1.0.0 h1:xhp2CnJmgQmpJU4RY8chagahUq5mbPPAbiSQstKpVMA=
github.com/google/renameio v1.0.0/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/miolini/datacounter v0.0.0-20171104152933-fd4e42a1d5e0 h1:clkDYGefEWUCwyCrwYn900sOaVGDpinPJgD0W6ebEjs=
github.com/miolini/datacounter v0.0.0-20171104152933-fd4e42a1d5e0/go.mod h1:P6fDJzlxN+cWYR09KbE9/ta+Y6JofX9tAUhJpWkWPaM=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33 h1:dyyWDK0yzlZ8ay89Oe5ZIRtscacUjFyPUFGChrgMXRg=
github.com/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33/go.mod h1:BjmVxzAnkLeoEbqHEerI4eSw6ua+RaIB0S4jMV21RAs=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef h1:RHORRhs540cYZYrzgU2CPUyykkwZM78hGdzocOo9P8A=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b h1:Lq5JUTFhiybGVf28jB6QRpqd13/JPOaCnET17PVzYJE=
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc=
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=

View File

@@ -10,8 +10,11 @@ import (
"github.com/eyedeekay/sam3" "github.com/eyedeekay/sam3"
) )
// HEY! If you're looking at this, there's a good chance that `github.com/eyedeekay/onramp`
// is a better fit! Check it out.
func NetListener(name, samaddr, keyspath string) (net.Listener, error) { 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. // I2PListener is a convenience function which takes a SAM tunnel name, a SAM address and a filename.
@@ -19,8 +22,10 @@ func NetListener(name, samaddr, keyspath string) (net.Listener, error) {
// exist, keys will be generated and stored in that file. // exist, keys will be generated and stored in that file.
func I2PListener(name, samaddr, keyspath string) (*sam3.StreamListener, error) { func I2PListener(name, samaddr, keyspath string) (*sam3.StreamListener, error) {
log.Printf("Starting and registering I2P service, please wait a couple of minutes...") 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 err != nil {
return nil, err
}
if keyspath != "" { if keyspath != "" {
err = ioutil.WriteFile(keyspath+".i2p.public.txt", []byte(listener.Keys().Addr().Base32()), 0644) err = ioutil.WriteFile(keyspath+".i2p.public.txt", []byte(listener.Keys().Addr().Base32()), 0644)
if err != nil { if err != nil {
@@ -36,9 +41,9 @@ func I2PListener(name, samaddr, keyspath string) (*sam3.StreamListener, error) {
// of the user. // of the user.
func I2PStreamSession(name, samaddr, keyspath string) (*sam3.StreamSession, error) { func I2PStreamSession(name, samaddr, keyspath string) (*sam3.StreamSession, error) {
log.Printf("Starting and registering I2P session...") log.Printf("Starting and registering I2P session...")
sam, err := sam3.NewSAM(samaddr) sam, err := sam3.NewSAM(sam3.SAMDefaultAddr(samaddr))
if err != nil { 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) keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil { if err != nil {
@@ -52,9 +57,9 @@ func I2PStreamSession(name, samaddr, keyspath string) (*sam3.StreamSession, erro
// It also takes care of setting a persisitent key on behalf of the user. // It also takes care of setting a persisitent key on behalf of the user.
func I2PDatagramSession(name, samaddr, keyspath string) (*sam3.DatagramSession, error) { func I2PDatagramSession(name, samaddr, keyspath string) (*sam3.DatagramSession, error) {
log.Printf("Starting and registering I2P session...") log.Printf("Starting and registering I2P session...")
sam, err := sam3.NewSAM(samaddr) sam, err := sam3.NewSAM(sam3.SAMDefaultAddr(samaddr))
if err != nil { 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) keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil { if err != nil {
@@ -68,9 +73,9 @@ func I2PDatagramSession(name, samaddr, keyspath string) (*sam3.DatagramSession,
// It also takes care of setting a persisitent key on behalf of the user. // It also takes care of setting a persisitent key on behalf of the user.
func I2PPrimarySession(name, samaddr, keyspath string) (*sam3.PrimarySession, error) { func I2PPrimarySession(name, samaddr, keyspath string) (*sam3.PrimarySession, error) {
log.Printf("Starting and registering I2P session...") log.Printf("Starting and registering I2P session...")
sam, err := sam3.NewSAM(samaddr) sam, err := sam3.NewSAM(sam3.SAMDefaultAddr(samaddr))
if err != nil { 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) keys, err := GenerateOrLoadKeys(keyspath, sam)
if err != nil { if err != nil {
@@ -80,9 +85,15 @@ func I2PPrimarySession(name, samaddr, keyspath string) (*sam3.PrimarySession, er
return gram, err 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) { func GenerateOrLoadKeys(keyspath string, sam *sam3.SAM) (keys *i2pkeys.I2PKeys, err error) {
if sam == nil { 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 { if err != nil {
return nil, err return nil, err
} }
@@ -112,6 +123,8 @@ func GenerateOrLoadKeys(keyspath string, sam *sam3.SAM) (keys *i2pkeys.I2PKeys,
return keys, nil 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) { func GenerateKeys(keyspath string) (keys *i2pkeys.I2PKeys, err error) {
return GenerateOrLoadKeys(keyspath, nil) return GenerateOrLoadKeys(keyspath, nil)
} }

BIN
i2plogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

331
index.html Normal file
View File

@@ -0,0 +1,331 @@
<html>
<head>
<title>
README
</title>
<meta name="author" content="eyedeekay" />
<meta name="description" content="sam3" />
<meta name="keywords" content="master" />
<link rel="stylesheet" type="text/css" href="style.css" />
<link rel="stylesheet" type="text/css" href="showhider.css" />
</head>
<body>
<div id="navbar">
<a href="#shownav">
Show navigation
</a>
<div id="shownav">
<div id="hidenav">
<ul>
<li>
<a href="index.html">
index
</a>
</li>
</ul>
<br>
<a href="#hidenav">
Hide Navigation
</a>
</div>
</div>
</div>
<h1>
<a href="#readme" rel="nofollow">
<span></span>
</a>
README
</h1>
<h2>
<a href="#important" rel="nofollow">
<span></span>
</a>
!!IMPORTANT!!
</h2>
<p>
In the next version, I&#39;ll be moving the
<code>
i2pkeys
</code>
directory to it&#39;s own repository
so I can avoid import cycle headaches. Please migrate to the new
<code>
i2pkeys
</code>
repository
before upgrading your sam3 dependencies. You can probably do this by running:
</p>
<div>
<pre>find . -name &#39;*.go&#39; -exec sed -i &#39;s|github.com/eyedeekay/sam3/i2pkeys|github.com/eyedeekay/i2pkeys|g&#39; {} \;
</pre>
</div>
<p>
STATUS: This project is maintained. I will respond to issues, pull requests, and feature requests within a few days.
</p>
<h1>
<a href="#readme" rel="nofollow">
<span></span>
</a>
README
</h1>
<p>
go library for the I2P
<a href="https://geti2p.net/en/docs/api/samv3" rel="nofollow">
SAMv3.0
</a>
bridge, used to build anonymous/pseudonymous end-to-end encrypted sockets.
</p>
<p>
This library is much better than ccondom (that use BOB), much more stable and much easier to maintain.
</p>
<h2>
<a href="#support-todo" rel="nofollow">
<span></span>
</a>
Support/TODO
</h2>
<p>
<strong>
What works:
</strong>
</p>
<ul>
<li>
Utils
<ul>
<li>
Resolving domain names to I2P destinations
</li>
<li>
.b32.i2p hashes
</li>
<li>
Generating keys/i2p destinations
</li>
</ul>
</li>
<li>
Streaming
<ul>
<li>
DialI2P() - Connecting to stuff in I2P
</li>
<li>
Listen()/Accept() - Handling incomming connections
</li>
<li>
Implements net.Conn and net.Listener
</li>
</ul>
</li>
<li>
Datagrams
<ul>
<li>
Implements net.PacketConn
</li>
</ul>
</li>
<li>
Raw datagrams
<ul>
<li>
Like datagrams, but without addresses
</li>
</ul>
</li>
</ul>
<p>
<strong>
Does not work:
</strong>
</p>
<ul>
<li>
Stream Forwarding
</li>
<li>
Probably needs some real-world testing
</li>
</ul>
<h2>
<a href="#documentation" rel="nofollow">
<span></span>
</a>
Documentation
</h2>
<ul>
<li>
Latest version-documentation:
<ul>
<li>
set your GOPATH
</li>
<li>
Enter
<code>
godoc -http=:8081
</code>
into your terminal and hit enter.
</li>
<li>
Goto
<a href="http://localhost:8081" rel="nofollow">
http://localhost:8081
</a>
, click packages, and navigate to sam3
</li>
</ul>
</li>
</ul>
<h2>
<a href="#examples" rel="nofollow">
<span></span>
</a>
Examples
</h2>
<div>
<pre>package main
import (
&#34;github.com/eyedeekay/sam3&#34;
&#34;github.com/eyedeekay/sam3/i2pkeys&#34;
&#34;fmt&#34;
)
const yoursam = &#34;127.0.0.1:7656&#34; // sam bridge
func client(server i2pkeys.I2PAddr) {
sam, _ := sam3.NewSAM(yoursam)
keys, _ := sam.NewKeys()
stream, _ := sam.NewStreamSession(&#34;clientTun&#34;, keys, sam3.Options_Small)
fmt.Println(&#34;Client: Connecting to &#34; + server.Base32())
conn, _ := stream.DialI2P(server)
conn.Write([]byte(&#34;Hello world!&#34;))
return
}
func main() {
sam, _ := NewSAM(yoursam)
keys, _ := sam.NewKeys()
stream, _ := sam.NewStreamSession(&#34;serverTun&#34;, keys, sam3.Options_Medium)
listener, _ := stream.Listen()
go client(keys.Addr())
conn, _ := listener.Accept()
buf := make([]byte, 4096)
n, _ := conn.Read(buf)
fmt.Println(&#34;Server received: &#34; + string(buf[:n]))
}
</pre>
</div>
<p>
The above will write to the terminal:
</p>
<div>
<pre>Client: Connecting to zjnvfh4hs3et5vtz35ogwzrws26zvwkcad5uo5esecvg4qpk5b4a.b32.i2p
Server received: Hello world!
</pre>
</div>
<p>
Error handling was omitted in the above code for readability.
</p>
<h2>
<a href="#testing" rel="nofollow">
<span></span>
</a>
Testing
</h2>
<ul>
<li>
<code>
go test -tags=nettest
</code>
runs the whole suite (takes 90+ sec to perform!)
</li>
<li>
<code>
go test -short
</code>
runs the shorter variant, does not connect to anything
</li>
</ul>
<h2>
<a href="#license" rel="nofollow">
<span></span>
</a>
License
</h2>
<p>
Public domain.
</p>
<h2>
<a href="#author" rel="nofollow">
<span></span>
</a>
Author
</h2>
<ul>
<li>
Kalle Vedin
<code>
kalle.vedin@fripost.org
</code>
</li>
<li>
Unknown Name (majestrate)
</li>
<li>
idk
</li>
<li>
qiwenmin
</li>
</ul>
<div>
<a href="#show">
Show license
</a>
<div id="show">
<div id="hide">
<pre><code>This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
</code></pre>
<a href="#hide">
Hide license
</a>
</div>
</div>
</div>
<div>
<iframe src="https://snowflake.torproject.org/embed.html" width="320" height="240" frameborder="0" scrolling="no"></iframe>
</div>
<div>
<a href="https://geti2p.net/">
<img src="i2plogo.png"></img>
I2P
</a>
</div>
</body>
</html>

View File

@@ -77,9 +77,11 @@ func (ss *PrimarySession) Keys() i2pkeys.I2PKeys {
func (sam *PrimarySession) Dial(network, addr string) (net.Conn, error) { func (sam *PrimarySession) Dial(network, addr string) (net.Conn, error) {
if network == "udp" || network == "udp4" || network == "udp6" { 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) return sam.DialUDPI2P(network, network+addr[0:4], addr)
} }
if network == "tcp" || network == "tcp4" || network == "tcp6" { 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 sam.DialTCPI2P(network, network+addr[0:4], addr)
} }
return nil, fmt.Errorf("Error: Must specify a valid network type") return nil, fmt.Errorf("Error: Must specify a valid network type")
@@ -87,52 +89,60 @@ func (sam *PrimarySession) Dial(network, addr string) (net.Conn, error) {
// DialTCP implements x/dialer // DialTCP implements x/dialer
func (sam *PrimarySession) DialTCP(network string, laddr, raddr net.Addr) (net.Conn, error) { 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 { if !ok {
stsess, err := sam.NewUniqueStreamSubSession(network + raddr.String()[0:4]) ts, err = sam.NewUniqueStreamSubSession(network + raddr.String()[0:4])
if err != nil { if err != nil {
return nil, err return nil, err
} }
sam.stsess[network+raddr.String()[0:4]] = stsess sam.stsess[network+raddr.String()[0:4]] = ts
ts, _ = sam.stsess[network+raddr.String()[0:4]]
} }
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) { 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 { if !ok {
stsess, err := sam.NewUniqueStreamSubSession(network + laddr) ts, err = sam.NewUniqueStreamSubSession(network + laddr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
sam.stsess[network+raddr[0:4]] = stsess sam.stsess[network+raddr[0:4]] = ts
ts, _ = sam.stsess[network+raddr[0:4]]
} }
return sam.stsess[network+raddr[0:4]].Dial(network, raddr) return ts.Dial(network, raddr)
} }
// DialUDP implements x/dialer // DialUDP implements x/dialer
func (sam *PrimarySession) DialUDP(network string, laddr, raddr net.Addr) (net.PacketConn, error) { 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 { 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 { if err != nil {
return nil, err return nil, err
} }
sam.dgsess[network+raddr.String()[0:4]] = dgsess sam.dgsess[network+raddr.String()[0:4]] = ds
ds, _ = sam.dgsess[network+raddr.String()[0:4]]
} }
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) { 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 { if !ok {
dgsess, err := sam.NewDatagramSubSession(network+laddr, 0) ds, err = sam.NewDatagramSubSession(network+laddr, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
sam.dgsess[network+raddr[0:4]] = dgsess sam.dgsess[network+raddr[0:4]] = ds
ds, _ = sam.dgsess[network+raddr[0:4]]
} }
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) { func (s *PrimarySession) Lookup(name string) (a net.Addr, err error) {
@@ -161,7 +171,11 @@ func (sam *PrimarySession) ResolveUDPAddr(network, dest string) (net.Addr, error
// Creates a new PrimarySession with the I2CP- and streaminglib options as // Creates a new PrimarySession with the I2CP- and streaminglib options as
// specified. See the I2P documentation for a full list of options. // specified. See the I2P documentation for a full list of options.
func (sam *SAM) NewPrimarySession(id string, keys i2pkeys.I2PKeys, options []string) (*PrimarySession, error) { func (sam *SAM) NewPrimarySession(id string, keys i2pkeys.I2PKeys, options []string) (*PrimarySession, error) {
conn, err := sam.newGenericSession(PrimarySessionSwitch, id, keys, options, []string{}) return sam.newPrimarySession(PrimarySessionSwitch, id, keys, options)
}
func (sam *SAM) newPrimarySession(primarySessionSwitch string, id string, keys i2pkeys.I2PKeys, options []string) (*PrimarySession, error) {
conn, err := sam.newGenericSession(primarySessionSwitch, id, keys, options, []string{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -205,13 +219,13 @@ func (sam *PrimarySession) newGenericSubSessionWithSignatureAndPorts(style, id,
conn := sam.conn conn := sam.conn
fp := "" fp := ""
tp := "" tp := ""
if from != "0" { if from != "0" && from != "" {
fp = " FROM_PORT=" + from fp = " FROM_PORT=" + from
} }
if to != "0" { if to != "0" && to != "" {
tp = " TO_PORT=" + 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++ { for m, i := 0, 0; m != len(scmsg); i++ {
if i == 15 { if i == 15 {
conn.Close() conn.Close()
@@ -231,6 +245,7 @@ func (sam *PrimarySession) newGenericSubSessionWithSignatureAndPorts(style, id,
return nil, err return nil, err
} }
text := string(buf[:n]) text := string(buf[:n])
//log.Println("SAM:", text)
if strings.HasPrefix(text, session_ADDOK) { if strings.HasPrefix(text, session_ADDOK) {
//if sam.keys.String() != text[len(session_ADDOK):len(text)-1] { //if sam.keys.String() != text[len(session_ADDOK):len(text)-1] {
//conn.Close() //conn.Close()
@@ -245,7 +260,7 @@ func (sam *PrimarySession) newGenericSubSessionWithSignatureAndPorts(style, id,
return nil, errors.New("Duplicate destination") return nil, errors.New("Duplicate destination")
} else if text == session_INVALID_KEY { } else if text == session_INVALID_KEY {
conn.Close() conn.Close()
return nil, errors.New("Invalid key") return nil, errors.New("Invalid key - Primary Session")
} else if strings.HasPrefix(text, session_I2P_ERROR) { } else if strings.HasPrefix(text, session_I2P_ERROR) {
conn.Close() conn.Close()
return nil, errors.New("I2P error " + text[len(session_I2P_ERROR):]) return nil, errors.New("I2P error " + text[len(session_I2P_ERROR):])
@@ -272,7 +287,7 @@ func (sam *PrimarySession) NewUniqueStreamSubSession(id string) (*StreamSession,
if err != nil { if err != nil {
return nil, err 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 // Creates a new StreamSession with the I2CP- and streaminglib options as
@@ -304,7 +319,7 @@ func (s *PrimarySession) NewDatagramSubSession(id string, udpPort int) (*Datagra
if udpPort == 0 { if udpPort == 0 {
udpPort = 7655 udpPort = 7655
} }
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String()) lhost, _, err := SplitHostPort(s.conn.LocalAddr().String())
if err != nil { if err != nil {
s.Close() s.Close()
return nil, err return nil, err
@@ -317,7 +332,7 @@ func (s *PrimarySession) NewDatagramSubSession(id string, udpPort int) (*Datagra
if err != nil { if err != nil {
return nil, err return nil, err
} }
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String()) rhost, _, err := SplitHostPort(s.conn.RemoteAddr().String())
if err != nil { if err != nil {
s.Close() s.Close()
return nil, err return nil, err
@@ -347,7 +362,7 @@ func (s *PrimarySession) NewRawSubSession(id string, udpPort int) (*RawSession,
if udpPort == 0 { if udpPort == 0 {
udpPort = 7655 udpPort = 7655
} }
lhost, _, err := net.SplitHostPort(s.conn.LocalAddr().String()) lhost, _, err := SplitHostPort(s.conn.LocalAddr().String())
if err != nil { if err != nil {
s.Close() s.Close()
return nil, err return nil, err
@@ -360,7 +375,7 @@ func (s *PrimarySession) NewRawSubSession(id string, udpPort int) (*RawSession,
if err != nil { if err != nil {
return nil, err return nil, err
} }
rhost, _, err := net.SplitHostPort(s.conn.RemoteAddr().String()) rhost, _, err := SplitHostPort(s.conn.RemoteAddr().String())
if err != nil { if err != nil {
s.Close() s.Close()
return nil, err return nil, err

View File

@@ -2,12 +2,12 @@ package sam3
import ( import (
"fmt" "fmt"
"io/ioutil"
"log" "log"
"net/http"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/eyedeekay/i2pkeys"
) )
func Test_PrimaryStreamingDial(t *testing.T) { func Test_PrimaryStreamingDial(t *testing.T) {
@@ -108,17 +108,20 @@ func Test_PrimaryStreamingServerClient(t *testing.T) {
if !(<-w) { if !(<-w) {
return return
} }
/*sam2, err := NewSAM(yoursam) /*
if err != nil { sam2, err := NewSAM(yoursam)
c <- false if err != nil {
return c <- false
} return
defer sam2.Close() }
keys, err := sam2.NewKeys() defer sam2.Close()
if err != nil { keys, err := sam2.NewKeys()
c <- false if err != nil {
return c <- false
}*/ return
}
*/
fmt.Println("\tClient: Creating tunnel") fmt.Println("\tClient: Creating tunnel")
ss2, err := sam.NewStreamSubSession("primaryExampleClientTun") ss2, err := sam.NewStreamSubSession("primaryExampleClientTun")
if err != nil { if err != nil {
@@ -220,73 +223,86 @@ func ExamplePrimaryStreamListener() {
const samBridge = "127.0.0.1:7656" 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.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 { if err != nil {
log.Fatal(err.Error()) log.Fatal(err.Error())
return return
} }
defer earlysam.Close() defer latesam.Close()
keys, err := earlysam.NewKeys() keys2, err := latesam.NewKeys()
if err != nil { if err != nil {
log.Fatal(err.Error()) log.Fatal(err.Error())
return 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"})
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")
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
return return
} }
defer ss.Close() defer sc.Close()
l, err := ss.Listen() 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 { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
return return
} }
conn, err := l.Accept() defer resp.Body.Close()
r, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
return return
} }
conn.Write([]byte("Hello world!")) fmt.Println("Got response: " + string(r))
<-quit // waits for client to die, for example only
// Output: // Output:
//Hello world! // Got response: Hello world!
}
type exitHandler struct {
}
func (e *exitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello world!"))
} }

7
raw.go
View File

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

View File

@@ -55,7 +55,7 @@ func (sam *SAMResolver) Resolve(name string) (i2pkeys.I2PAddr, error) {
if text == "RESULT=OK" { if text == "RESULT=OK" {
continue continue
} else if text == "RESULT=INVALID_KEY" { } else if text == "RESULT=INVALID_KEY" {
errStr += "Invalid key." errStr += "Invalid key - resolver."
} else if text == "RESULT=KEY_NOT_FOUND" { } else if text == "RESULT=KEY_NOT_FOUND" {
errStr += "Unable to resolve " + name errStr += "Unable to resolve " + name
} else if text == "NAME="+name { } else if text == "NAME="+name {

31
sam3.go
View File

@@ -5,6 +5,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"errors" "errors"
"fmt"
"io" "io"
"math/rand" "math/rand"
"net" "net"
@@ -12,9 +13,7 @@ import (
"strings" "strings"
"github.com/eyedeekay/i2pkeys" "github.com/eyedeekay/i2pkeys"
)
import (
. "github.com/eyedeekay/i2pkeys" . "github.com/eyedeekay/i2pkeys"
) )
@@ -37,7 +36,7 @@ const (
) )
const ( const (
Sig_NONE = "" Sig_NONE = "SIGNATURE_TYPE=EdDSA_SHA512_Ed25519"
Sig_DSA_SHA1 = "SIGNATURE_TYPE=DSA_SHA1" Sig_DSA_SHA1 = "SIGNATURE_TYPE=DSA_SHA1"
Sig_ECDSA_SHA256_P256 = "SIGNATURE_TYPE=ECDSA_SHA256_P256" Sig_ECDSA_SHA256_P256 = "SIGNATURE_TYPE=ECDSA_SHA256_P256"
Sig_ECDSA_SHA384_P384 = "SIGNATURE_TYPE=ECDSA_SHA384_P384" Sig_ECDSA_SHA384_P384 = "SIGNATURE_TYPE=ECDSA_SHA384_P384"
@@ -62,17 +61,17 @@ func NewSAM(address string) (*SAM, error) {
// TODO: clean this up // TODO: clean this up
conn, err := net.Dial("tcp", address) conn, err := net.Dial("tcp", address)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("error dialing to address '%s': %w", address, err)
} }
if _, err := conn.Write(s.Config.HelloBytes()); err != nil { if _, err := conn.Write(s.Config.HelloBytes()); err != nil {
conn.Close() conn.Close()
return nil, err return nil, fmt.Errorf("error writing to address '%s': %w", address, err)
} }
buf := make([]byte, 256) buf := make([]byte, 256)
n, err := conn.Read(buf) n, err := conn.Read(buf)
if err != nil { if err != nil {
conn.Close() conn.Close()
return nil, err return nil, fmt.Errorf("error reading onto buffer: %w", err)
} }
if strings.Contains(string(buf[:n]), "HELLO REPLY RESULT=OK") { if strings.Contains(string(buf[:n]), "HELLO REPLY RESULT=OK") {
s.Config.I2PConfig.SetSAMAddress(address) s.Config.I2PConfig.SetSAMAddress(address)
@@ -80,10 +79,9 @@ func NewSAM(address string) (*SAM, error) {
//s.Config.I2PConfig.DestinationKeys = nil //s.Config.I2PConfig.DestinationKeys = nil
s.resolver, err = NewSAMResolver(&s) s.resolver, err = NewSAMResolver(&s)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("error creating resolver: %w", err)
} }
return &s, nil return &s, nil
//return &SAM{address, conn, nil, nil}, nil
} else if string(buf[:n]) == "HELLO REPLY RESULT=NOVERSION\n" { } else if string(buf[:n]) == "HELLO REPLY RESULT=NOVERSION\n" {
conn.Close() conn.Close()
return nil, errors.New("That SAM bridge does not support SAMv3.") return nil, errors.New("That SAM bridge does not support SAMv3.")
@@ -118,7 +116,7 @@ func (sam *SAM) EnsureKeyfile(fname string) (keys i2pkeys.I2PKeys, err error) {
sam.Config.I2PConfig.DestinationKeys = keys sam.Config.I2PConfig.DestinationKeys = keys
} }
} else { } else {
// persistant // persistent
_, err = os.Stat(fname) _, err = os.Stat(fname)
if os.IsNotExist(err) { if os.IsNotExist(err) {
// make the keys // make the keys
@@ -157,12 +155,12 @@ func (sam *SAM) NewKeys(sigType ...string) (i2pkeys.I2PKeys, error) {
sigtmp = sigType[0] sigtmp = sigType[0]
} }
if _, err := sam.conn.Write([]byte("DEST GENERATE " + sigtmp + "\n")); err != nil { if _, err := sam.conn.Write([]byte("DEST GENERATE " + sigtmp + "\n")); err != nil {
return i2pkeys.I2PKeys{}, err return i2pkeys.I2PKeys{}, fmt.Errorf("error with writing in SAM: %w", err)
} }
buf := make([]byte, 8192) buf := make([]byte, 8192)
n, err := sam.conn.Read(buf) n, err := sam.conn.Read(buf)
if err != nil { if err != nil {
return i2pkeys.I2PKeys{}, err return i2pkeys.I2PKeys{}, fmt.Errorf("error with reading in SAM: %w", err)
} }
s := bufio.NewScanner(bytes.NewReader(buf[:n])) s := bufio.NewScanner(bytes.NewReader(buf[:n]))
s.Split(bufio.ScanWords) s.Split(bufio.ScanWords)
@@ -211,10 +209,7 @@ func (sam *SAM) newGenericSessionWithSignature(style, id string, keys i2pkeys.I2
// This sam3 instance is now a session // This sam3 instance is now a session
func (sam *SAM) newGenericSessionWithSignatureAndPorts(style, id, from, to string, keys i2pkeys.I2PKeys, sigType string, options []string, extras []string) (net.Conn, error) { func (sam *SAM) newGenericSessionWithSignatureAndPorts(style, id, from, to string, keys i2pkeys.I2PKeys, sigType string, options []string, extras []string) (net.Conn, error) {
optStr := "" optStr := GenerateOptionString(options)
for _, opt := range options {
optStr += opt + " "
}
conn := sam.conn conn := sam.conn
fp := "" fp := ""
@@ -234,7 +229,7 @@ func (sam *SAM) newGenericSessionWithSignatureAndPorts(style, id, from, to strin
n, err := conn.Write(scmsg[m:]) n, err := conn.Write(scmsg[m:])
if err != nil { if err != nil {
conn.Close() conn.Close()
return nil, err return nil, fmt.Errorf("writing to connection failed: %w", err)
} }
m += n m += n
} }
@@ -242,7 +237,7 @@ func (sam *SAM) newGenericSessionWithSignatureAndPorts(style, id, from, to strin
n, err := conn.Read(buf) n, err := conn.Read(buf)
if err != nil { if err != nil {
conn.Close() conn.Close()
return nil, err return nil, fmt.Errorf("reading from connection failed: %w", err)
} }
text := string(buf[:n]) text := string(buf[:n])
if strings.HasPrefix(text, session_OK) { if strings.HasPrefix(text, session_OK) {
@@ -259,7 +254,7 @@ func (sam *SAM) newGenericSessionWithSignatureAndPorts(style, id, from, to strin
return nil, errors.New("Duplicate destination") return nil, errors.New("Duplicate destination")
} else if text == session_INVALID_KEY { } else if text == session_INVALID_KEY {
conn.Close() conn.Close()
return nil, errors.New("Invalid key") return nil, errors.New("Invalid key - SAM session")
} else if strings.HasPrefix(text, session_I2P_ERROR) { } else if strings.HasPrefix(text, session_I2P_ERROR) {
conn.Close() conn.Close()
return nil, errors.New("I2P error " + text[len(session_I2P_ERROR):]) return nil, errors.New("I2P error " + text[len(session_I2P_ERROR):])

10
showhider.css Normal file
View File

@@ -0,0 +1,10 @@
/* edgar showhider CSS file */
#show {display:none; }
#hide {display:block; }
#show:target {display: block; }
#hide:target {display: none; }
#shownav {display:none; }
#hidenav {display:block; }
#shownav:target {display: block; }
#hidenav:target {display: none; }

View File

@@ -103,12 +103,12 @@ func (sam *SAM) NewStreamSessionWithSignatureAndPorts(id, from, to string, keys
return &StreamSession{sam.Config.I2PConfig.Sam(), id, conn, keys, time.Duration(600 * time.Second), time.Now(), sigType, from, to}, nil return &StreamSession{sam.Config.I2PConfig.Sam(), id, conn, keys, time.Duration(600 * time.Second), time.Now(), sigType, from, to}, nil
} }
// lookup name, convienence function // lookup name, convenience function
func (s *StreamSession) Lookup(name string) (i2pkeys.I2PAddr, error) { func (s *StreamSession) Lookup(name string) (i2pkeys.I2PAddr, error) {
sam, err := NewSAM(s.samAddr) sam, err := NewSAM(s.samAddr)
if err == nil { if err == nil {
addr, err := sam.Lookup(name) addr, err := sam.Lookup(name)
sam.Close() defer sam.Close()
return addr, err return addr, err
} }
return i2pkeys.I2PAddr(""), err return i2pkeys.I2PAddr(""), err
@@ -161,6 +161,7 @@ func minNonzeroTime(a, b time.Time) time.Time {
// - now+Timeout // - now+Timeout
// - d.Deadline // - d.Deadline
// - the context's deadline // - the context's deadline
//
// Or zero, if none of Timeout, Deadline, or context's deadline is set. // Or zero, if none of Timeout, Deadline, or context's deadline is set.
func (s *StreamSession) deadline(ctx context.Context, now time.Time) (earliest time.Time) { func (s *StreamSession) deadline(ctx context.Context, now time.Time) (earliest time.Time) {
if s.Timeout != 0 { // including negative, for historical reasons if s.Timeout != 0 { // including negative, for historical reasons
@@ -177,15 +178,19 @@ func (s *StreamSession) Dial(n, addr string) (c net.Conn, err error) {
var i2paddr i2pkeys.I2PAddr var i2paddr i2pkeys.I2PAddr
var host string var host string
host, _, err = net.SplitHostPort(addr) host, _, err = SplitHostPort(addr)
//log.Println("Dialing:", host)
if err = IgnorePortError(err); err == nil { if err = IgnorePortError(err); err == nil {
// check for name // check for name
if strings.HasSuffix(host, ".b32.i2p") || strings.HasSuffix(host, ".i2p") { if strings.HasSuffix(host, ".b32.i2p") || strings.HasSuffix(host, ".i2p") {
// name lookup // name lookup
i2paddr, err = s.Lookup(host) i2paddr, err = s.Lookup(host)
//log.Println("Lookup:", i2paddr, err)
} else { } else {
// probably a destination // 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 { if err == nil {
return s.DialI2P(i2paddr) return s.DialI2P(i2paddr)
@@ -230,7 +235,7 @@ func (s *StreamSession) DialI2P(addr i2pkeys.I2PAddr) (*SAMConn, error) {
return nil, errors.New("I2P internal error") return nil, errors.New("I2P internal error")
case "RESULT=INVALID_KEY": case "RESULT=INVALID_KEY":
conn.Close() conn.Close()
return nil, errors.New("Invalid key") return nil, errors.New("Invalid key - Stream Session")
case "RESULT=INVALID_ID": case "RESULT=INVALID_ID":
conn.Close() conn.Close()
return nil, errors.New("Invalid tunnel ID") return nil, errors.New("Invalid tunnel ID")

View File

@@ -77,40 +77,43 @@ func (l *StreamListener) AcceptI2P() (*SAMConn, error) {
// we connected to sam // we connected to sam
// send accept() command // send accept() command
_, err = io.WriteString(s.conn, "STREAM ACCEPT ID="+l.id+" SILENT=false\n") _, err = io.WriteString(s.conn, "STREAM ACCEPT ID="+l.id+" SILENT=false\n")
if err != nil {
s.Close()
return nil, err
}
// read reply // read reply
rd := bufio.NewReader(s.conn) rd := bufio.NewReader(s.conn)
// read first line // read first line
line, err := rd.ReadString(10) line, err := rd.ReadString(10)
log.Println(line) if err != nil {
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() s.Close()
return nil, err return nil, err
} }
log.Println(line)
if strings.HasPrefix(line, "STREAM STATUS RESULT=OK") {
// we gud read destination line
destline, err := rd.ReadString(10)
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
} }

157
style.css Normal file
View File

@@ -0,0 +1,157 @@
/* edgar default CSS file */
body {
font-family: "Roboto";
font-family: monospace;
text-align: justify;
background-color: #373636;
color: whitesmoke;
font-size: 1.15em;
}
ul {
width: 55%;
display: block;
}
ol {
width: 55%;
display: block;
}
li {
margin-top: 1%;
}
p {
max-width: 90%;
margin-top: 1%;
margin-left: 3%;
margin-right: 3%;
}
img {
float: left;
top: 5%;
left: 5%;
max-width: 60%;
display: inline;
}
.inline {
display: inline;
}
.link-button:focus {
outline: none;
}
.link-button:active {
color: red;
}
code {
font-family: monospace;
border-radius: 5%;
padding: 1%;
border-color: darkgray;
font-size: .9em;
}
a {
color: #C6D9FE;
padding: 1%;
}
ul li {
color: #C6D9FE;
}
iframe {
background: aliceblue;
border-radius: 15%;
margin: 2%;
}
.container {
width: 36vw;
height: 64vh;
display: inline-block;
margin: 0;
padding: 0;
}
.editor-toolbar a {
display: inline-block;
text-align: center;
text-decoration: none !important;
color: whitesmoke !important;
}
#feed {
width: 60vw;
height: unset !important;
margin: 0;
padding: 0;
float: right;
background-color: #373636;
color: whitesmoke;
border: #C6D9FE solid 1px;
}
.thread-post,
.thread {
color: whitesmoke !important;
background-color: #373636;
border: 1px solid darkgray;
font-size: inherit;
padding-top: 1%;
padding-bottom: 1%;
}
.thread-post {
margin-left: 4%;
}
input {
text-align: center;
color: whitesmoke !important;
background-color: #373636;
border: 1px solid darkgray;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
padding-top: 1%;
padding-bottom: 1%;
}
.thread-hash {
text-align: right;
color: whitesmoke !important;
background-color: #373636;
border: 1px solid darkgray;
font-size: inherit;
padding-top: 1%;
padding-bottom: 1%;
}
.post-body {
text-align: left;
color: whitesmoke !important;
font-size: inherit;
padding-top: 1%;
padding-bottom: 1%;
}
#show {display:none; }
#hide {display:block; }
#show:target {display: block; }
#hide:target {display: none; }
#shownav {display:none; }
#hidenav {display:block; }
#shownav:target {display: block; }
#hidenav:target {display: none; }
#navbar {
float: right;
width: 10%;
}

View File

@@ -1,6 +1,11 @@
package sam3 package sam3
import "net/http" import (
"net"
"net/http"
"os"
"strings"
)
// Examples and suggestions for options when creating sessions. // Examples and suggestions for options when creating sessions.
var ( var (
@@ -61,10 +66,51 @@ func PrimarySessionString() string {
if err != nil { if err != nil {
return "MASTER" return "MASTER"
} }
// at this point we're probably running on Java I2P and thus probably
// have a PRIMARY session. Just to be sure, try to make one, check
// for errors, then immediately close it.
testSam, err := NewSAM(SAMDefaultAddr(""))
if err != nil {
return "MASTER"
}
newKeys, err := testSam.NewKeys()
if err != nil {
return "MASTER"
}
primarySession, err := testSam.newPrimarySession("PRIMARY", "primaryTestTunnel", newKeys, Options_Small)
if err != nil {
return "MASTER"
}
primarySession.Close()
return "PRIMARY" return "PRIMARY"
} }
return "MASTER" return "MASTER"
} }
var PrimarySessionSwitch string = PrimarySessionString() 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
}
func GenerateOptionString(opts []string) string {
optStr := strings.Join(opts, " ")
if strings.Contains(optStr, "i2cp.leaseSetEncType") {
return optStr
}
return optStr + " i2cp.leaseSetEncType=4,0"
}