Files
sam-forwarder/forwarder.go
2018-07-26 23:46:48 -04:00

123 lines
3.1 KiB
Go

package samforwarder
import (
"io"
"log"
"net"
)
import (
"github.com/kpetku/sam3"
)
//SAMForwarder is a structure which automatically configured the forwarding of
//a local service to i2p over the SAM API.
type SAMForwarder struct {
SamHost string
SamPort string
TunName string
TargetHost string
TargetPort string
samConn *sam3.SAM
samKeys sam3.I2PKeys
publishStream *sam3.StreamSession
publishListen *sam3.StreamListener
publishConnection net.Conn
//
savePath string
save bool
}
var err error
func (f *SAMForwarder) target() string {
return f.TargetHost+":"+f.TargetPort
}
func (f *SAMForwarder) sam() string {
return f.SamHost+":"+f.SamPort
}
func (f *SAMForwarder) forward(conn net.Conn) {
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)
}()
}
//Base32 returns the base32 address where the local service is being forwarded
func (f *SAMForwarder) Base32() string {
return f.samKeys.Addr().Base32()
}
//Serve starts the SAM connection and and forwards the local host:port to i2p
func (f *SAMForwarder) Serve() error {
if f.samConn, err = sam3.NewSAM(f.sam()); err != nil {
return err
}
log.Println("SAM Bridge connection established.")
if f.samKeys, err = f.samConn.NewKeys(); err != nil {
return err
}
log.Println("Destination keys generated, tunnel name:", f.TunName, ".")
if f.publishStream, err = f.samConn.NewStreamSession(f.TunName, f.samKeys,
[]string{"inbound.length=3", "outbound.length=3",
"inbound.lengthVariance=1", "outbound.lengthVariance=1",
"inbound.backupQuantity=3", "outbound.backupQuantity=3",
"inbound.quantity=8", "outbound.quantity=8"}); err != nil {
log.Println("Stream Creation error:", err.Error())
return err
}
log.Println("SAM stream session established.")
if f.publishListen, err = f.publishStream.Listen(); err != nil {
return err
}
log.Println("Starting Listener.")
b := string(f.samKeys.Addr().Base32())
log.Println("SAM Listener created,", b+".b32.i2p")
for {
conn, err := f.publishListen.Accept()
if err != nil {
log.Fatalf("ERROR: failed to accept listener: %v", err)
}
log.Printf("Accepted connection %v\n", conn)
go f.forward(conn)
}
}
//NewSAMForwarder makes a new SAM forwarder with default options, accepts host:port arguments
func NewSAMForwarder(host, port string) (*SAMForwarder, error) {
return NewSAMForwarderFromOptions(SetHost(host), SetPort(port))
}
//NewSAMForwarderFromOptions makes a new SAM forwarder with default options, accepts host:port arguments
func NewSAMForwarderFromOptions(opts ...func(*SAMForwarder) error) (*SAMForwarder, error) {
var s SAMForwarder
s.SamHost = "127.0.0.1"
s.SamPort = "7656"
s.TargetHost = "127.0.0.1"
s.TargetPort = "8081"
s.TunName = "samForwarder"
for _, o := range opts {
if err := o(&s); err != nil {
return nil, err
}
}
return &s, nil
}