Files
sam-forwarder/forwarder.go

223 lines
5.6 KiB
Go
Raw Normal View History

2018-07-26 17:50:46 -04:00
package samforwarder
import (
"io"
"log"
"net"
"os"
"path/filepath"
2018-07-27 12:37:11 -04:00
"strings"
)
import (
"github.com/kpetku/sam3"
)
2018-07-26 18:05:56 -04:00
//SAMForwarder is a structure which automatically configured the forwarding of
//a local service to i2p over the SAM API.
type SAMForwarder struct {
2018-07-27 12:37:11 -04:00
SamHost string
SamPort string
TunName string
TargetHost string
TargetPort string
samConn *sam3.SAM
SamKeys sam3.I2PKeys
2018-07-27 12:37:11 -04:00
publishStream *sam3.StreamSession
publishListen *sam3.StreamListener
publishConnection net.Conn
FilePath string
file io.ReadWriter
2018-07-27 12:37:11 -04:00
save bool
2018-07-28 03:41:33 -04:00
// I2CP options
2018-07-27 12:37:11 -04:00
encryptLeaseSet string
2018-08-01 22:25:13 -04:00
LeaseSetKeys *sam3.I2PKeys
2018-07-27 12:37:11 -04:00
inAllowZeroHop string
outAllowZeroHop string
inLength string
outLength string
inQuantity string
outQuantity string
inVariance string
outVariance string
inBackupQuantity string
outBackupQuantity string
useCompression string
reduceIdle string
reduceIdleTime string
reduceIdleQuantity string
2018-07-28 03:41:33 -04:00
2018-07-28 03:51:05 -04:00
//Streaming Library options
accessListType string
accessList []string
2018-07-26 18:05:56 -04:00
}
var err error
2018-07-27 12:37:11 -04:00
func (f *SAMForwarder) accesslisttype() string {
if f.accessListType == "whitelist" {
return "i2cp.enableAccessList=true"
} else if f.accessListType == "blacklist" {
return "i2cp.enableBlackList=true"
2018-07-28 03:41:33 -04:00
} else if f.accessListType == "none" {
return ""
}
2018-07-27 12:37:11 -04:00
return ""
}
func (f *SAMForwarder) accesslist() string {
if f.accessListType != "" && len(f.accessList) > 0 {
r := ""
for _, s := range f.accessList {
r += s + ","
}
return "i2cp.accessList=" + strings.TrimSuffix(r, ",")
}
2018-07-28 04:33:43 -04:00
return ""
2018-07-27 12:37:11 -04:00
}
2018-07-30 22:01:05 -04:00
// Target returns the host:port of the local service you want to forward to i2p
2018-07-30 00:43:31 -04:00
func (f *SAMForwarder) Target() string {
2018-07-27 12:37:11 -04:00
return f.TargetHost + ":" + f.TargetPort
2018-07-26 18:05:56 -04:00
}
func (f *SAMForwarder) sam() string {
2018-07-27 12:37:11 -04:00
return f.SamHost + ":" + f.SamPort
2018-07-26 18:05:56 -04:00
}
func (f *SAMForwarder) forward(conn net.Conn) {
2018-07-30 00:44:29 -04:00
client, err := net.Dial("tcp", f.Target())
if err != nil {
log.Fatalf("Dial failed: %v", err)
}
log.Printf("Connected to localhost %v\n", conn)
go func() {
defer client.Close()
defer conn.Close()
io.Copy(client, conn)
}()
go func() {
defer client.Close()
defer conn.Close()
io.Copy(conn, client)
}()
}
2018-07-26 18:05:56 -04:00
//Base32 returns the base32 address where the local service is being forwarded
func (f *SAMForwarder) Base32() string {
return f.SamKeys.Addr().Base32()
2018-07-26 18:05:56 -04:00
}
//Serve starts the SAM connection and and forwards the local host:port to i2p
func (f *SAMForwarder) Serve() error {
if f.publishStream, err = f.samConn.NewStreamSession(f.TunName, f.SamKeys,
2018-07-27 12:37:11 -04:00
[]string{
"inbound.length=" + f.inLength,
"outbound.length=" + f.outLength,
"inbound.lengthVariance=" + f.inVariance,
"outbound.lengthVariance=" + f.outVariance,
"inbound.backupQuantity=" + f.inBackupQuantity,
"outbound.backupQuantity=" + f.outBackupQuantity,
"inbound.quantity=" + f.inQuantity,
"outbound.quantity=" + f.outQuantity,
"inbound.allowZeroHop=" + f.inAllowZeroHop,
"outbound.allowZeroHop=" + f.outAllowZeroHop,
"i2cp.encryptLeaseSet=" + f.encryptLeaseSet,
"i2cp.gzip=" + f.useCompression,
"i2cp.reduceOnIdle=" + f.reduceIdle,
"i2cp.reduceIdleTime=" + f.reduceIdleTime,
"i2cp.reduceQuantity=" + f.reduceIdleQuantity,
f.accesslisttype(),
f.accesslist(),
}); err != nil {
log.Println("Stream Creation error:", err.Error())
return err
}
log.Println("SAM stream session established.")
2018-07-26 18:05:56 -04:00
if f.publishListen, err = f.publishStream.Listen(); err != nil {
return err
}
log.Println("Starting Listener.")
b := string(f.SamKeys.Addr().Base32())
2018-08-02 22:35:41 -04:00
log.Println("SAM Listener created,", b)
for {
2018-07-26 18:05:56 -04:00
conn, err := f.publishListen.Accept()
if err != nil {
log.Fatalf("ERROR: failed to accept listener: %v", err)
}
log.Printf("Accepted connection %v\n", conn)
2018-07-26 18:05:56 -04:00
go f.forward(conn)
}
}
//NewSAMForwarder makes a new SAM forwarder with default options, accepts host:port arguments
func NewSAMForwarder(host, port string) (*SAMForwarder, error) {
2018-07-27 12:37:11 -04:00
return NewSAMForwarderFromOptions(SetHost(host), SetPort(port))
2018-07-26 18:05:56 -04:00
}
//NewSAMForwarderFromOptions makes a new SAM forwarder with default options, accepts host:port arguments
func NewSAMForwarderFromOptions(opts ...func(*SAMForwarder) error) (*SAMForwarder, error) {
2018-07-27 12:37:11 -04:00
var s SAMForwarder
s.SamHost = "127.0.0.1"
s.SamPort = "7656"
s.FilePath = ""
s.save = false
2018-07-27 12:37:11 -04:00
s.TargetHost = "127.0.0.1"
s.TargetPort = "8081"
s.TunName = "samForwarder"
s.inLength = "3"
s.outLength = "3"
s.inQuantity = "8"
s.outQuantity = "8"
s.inVariance = "1"
s.outVariance = "1"
s.inBackupQuantity = "3"
s.outBackupQuantity = "3"
s.inAllowZeroHop = "false"
s.outAllowZeroHop = "false"
s.encryptLeaseSet = "false"
2018-07-27 12:37:11 -04:00
s.useCompression = "true"
s.reduceIdle = "false"
s.reduceIdleTime = "15"
s.reduceIdleQuantity = "4"
for _, o := range opts {
2018-07-26 18:05:56 -04:00
if err := o(&s); err != nil {
return nil, err
}
}
if s.samConn, err = sam3.NewSAM(s.sam()); err != nil {
2018-07-28 04:33:43 -04:00
return nil, err
}
log.Println("SAM Bridge connection established.")
if s.SamKeys, err = s.samConn.NewKeys(); err != nil {
2018-07-28 04:33:43 -04:00
return nil, err
}
2018-07-30 09:20:44 -04:00
log.Println("Destination keys generated, tunnel name:", s.TunName)
if s.save {
if _, err := os.Stat(filepath.Join(s.FilePath, s.TunName+".i2pkeys")); os.IsNotExist(err) {
s.file, err = os.Create(filepath.Join(s.FilePath, s.TunName+".i2pkeys"))
if err != nil {
return nil, err
}
err = sam3.StoreKeysIncompat(s.SamKeys, s.file)
if err != nil {
return nil, err
}
}
2018-07-29 00:52:36 -04:00
s.file, err = os.Open(filepath.Join(s.FilePath, s.TunName+".i2pkeys"))
if err != nil {
return nil, err
}
s.SamKeys, err = sam3.LoadKeysIncompat(s.file)
if err != nil {
return nil, err
}
}
2018-07-27 12:37:11 -04:00
return &s, nil
}