diff --git a/config/quantity.go b/config/quantity.go index 47a62f2..a5d744d 100644 --- a/config/quantity.go +++ b/config/quantity.go @@ -39,7 +39,7 @@ func (c *Conf) SetInQuantity(label ...string) { if v, ok := c.GetInt("inbound.quantity", label...); ok { c.InQuantity = v } else { - c.InQuantity = 5 + c.InQuantity = 1 } } @@ -48,6 +48,6 @@ func (c *Conf) SetOutQuantity(label ...string) { if v, ok := c.GetInt("outbound.quantity", label...); ok { c.OutQuantity = v } else { - c.OutQuantity = 5 + c.OutQuantity = 1 } } diff --git a/etc/samcatd/tunnels.ini b/etc/samcatd/tunnels.ini index 5ca2580..173c26a 100644 --- a/etc/samcatd/tunnels.ini +++ b/etc/samcatd/tunnels.ini @@ -6,12 +6,12 @@ inbound.length = 3 outbound.length = 3 -inbound.lengthVariance = 0 -outbound.lengthVariance = 0 -inbound.backupQuantity = 3 -outbound.backupQuantity = 3 -inbound.quantity = 5 -outbound.quantity = 5 +inbound.lengthVariance = 1 +outbound.lengthVariance = 1 +inbound.backupQuantity = 1 +outbound.backupQuantity = 1 +inbound.quantity = 2 +outbound.quantity = 2 inbound.allowZeroHop = false outbound.allowZeroHop = false i2cp.encryptLeaseSet = false @@ -27,15 +27,15 @@ i2cp.enableBlackList = false type = server host = 127.0.0.1 port = 8081 -inbound.length = 3 -outbound.length = 3 +inbound.length = 2 +outbound.length = 2 keys = tcpserver [sam-forwarder-tcp-client] type = client host = 127.0.0.1 port = 8082 -inbound.length = 3 +inbound.length = 2 outbound.length = 3 destination = i2p-projekt.i2p keys = tcpclient diff --git a/forwarder-client.go b/forwarder-client.go index 4b6ccfc..aed319c 100644 --- a/forwarder-client.go +++ b/forwarder-client.go @@ -12,6 +12,7 @@ import ( import ( "github.com/eyedeekay/sam-forwarder/i2pkeys" + "github.com/eyedeekay/sam-forwarder/interface" "github.com/eyedeekay/sam3" "github.com/eyedeekay/sam3/i2pkeys" ) @@ -36,6 +37,7 @@ type SAMClientForwarder struct { FilePath string file io.ReadWriter save bool + up bool // samcatd options passfile string @@ -250,15 +252,45 @@ func (f *SAMClientForwarder) Serve() error { } } +func (f *SAMClientForwarder) Up() bool { + return f.up +} + //Close shuts the whole thing down. func (f *SAMClientForwarder) Close() error { var err error err = f.samConn.Close() + f.up = false err = f.connectStream.Close() err = f.publishConnection.Close() return err } +func (s *SAMClientForwarder) Load() (samtunnel.SAMTunnel, error) { + if s.publishConnection, err = net.Listen("tcp", s.TargetHost+":"+s.TargetPort); err != nil { + return nil, err + } + if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { + return nil, err + } + log.Println("SAM Bridge connection established.") + if s.save { + log.Println("Saving i2p keys") + } + if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { + return nil, err + } + log.Println("Destination keys generated, tunnel name:", s.TunName) + if s.save { + if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { + return nil, err + } + log.Println("Saved tunnel keys for", s.TunName) + } + s.up = true + return s, nil +} + //NewSAMClientForwarder makes a new SAM forwarder with default options, accepts host:port arguments func NewSAMClientForwarder(host, port string) (*SAMClientForwarder, error) { return NewSAMClientForwarderFromOptions(SetClientHost(host), SetClientPort(port)) @@ -305,25 +337,9 @@ func NewSAMClientForwarderFromOptions(opts ...func(*SAMClientForwarder) error) ( return nil, err } } - if s.publishConnection, err = net.Listen("tcp", s.TargetHost+":"+s.TargetPort); err != nil { - return nil, err + l, e := s.Load() + if e != nil { + return nil, e } - if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { - return nil, err - } - log.Println("SAM Bridge connection established.") - if s.save { - log.Println("Saving i2p keys") - } - if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { - return nil, err - } - log.Println("Destination keys generated, tunnel name:", s.TunName) - if s.save { - if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { - return nil, err - } - log.Println("Saved tunnel keys for", s.TunName) - } - return &s, nil + return l.(*SAMClientForwarder), nil } diff --git a/forwarder.go b/forwarder.go index 05284a2..2632eec 100644 --- a/forwarder.go +++ b/forwarder.go @@ -15,6 +15,7 @@ import ( import ( "github.com/eyedeekay/sam-forwarder/i2pkeys" + "github.com/eyedeekay/sam-forwarder/interface" "github.com/eyedeekay/sam3" "github.com/eyedeekay/sam3/i2pkeys" ) @@ -38,6 +39,7 @@ type SAMForwarder struct { FilePath string file io.ReadWriter save bool + up bool Type string @@ -358,16 +360,43 @@ func (f *SAMForwarder) Serve() error { } } +func (f *SAMForwarder) Up() bool { + return f.up +} + //Close shuts the whole thing down. func (f *SAMForwarder) Close() error { var err error err = f.samConn.Close() + f.up = false err = f.publishStream.Close() err = f.publishListen.Close() err = f.publishConnection.Close() return err } +func (s *SAMForwarder) Load() (samtunnel.SAMTunnel, error) { + if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { + return nil, err + } + log.Println("SAM Bridge connection established.") + if s.save { + log.Println("Saving i2p keys") + } + if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { + return nil, err + } + log.Println("Destination keys generated, tunnel name:", s.TunName) + if s.save { + if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { + return nil, err + } + log.Println("Saved tunnel keys for", s.TunName) + } + s.up = true + return s, nil +} + //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)) @@ -414,22 +443,9 @@ func NewSAMForwarderFromOptions(opts ...func(*SAMForwarder) error) (*SAMForwarde return nil, err } } - if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { - return nil, err + l, e := s.Load() + if e != nil { + return nil, e } - log.Println("SAM Bridge connection established.") - if s.save { - log.Println("Saving i2p keys") - } - if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { - return nil, err - } - log.Println("Destination keys generated, tunnel name:", s.TunName) - if s.save { - if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { - return nil, err - } - log.Println("Saved tunnel keys for", s.TunName) - } - return &s, nil + return l.(*SAMForwarder), nil } diff --git a/handler/tunnelhandler.go b/handler/tunnelhandler.go index 7bb97f7..240c45b 100644 --- a/handler/tunnelhandler.go +++ b/handler/tunnelhandler.go @@ -37,16 +37,51 @@ func (t *TunnelHandler) Printdivf(id, key, value string, rw http.ResponseWriter, } func (t *TunnelHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - if strings.HasSuffix(req.URL.Path, "color") { - fmt.Fprintf(rw, "
", t.SAMTunnel.ID(), t.SAMTunnel.GetType()) - } if err := req.ParseForm(); err == nil { if action := req.PostFormValue("action"); action != "" { - fmt.Fprintf(rw, "%s", action) - return + var err error + switch action { + case "start": + if !t.SAMTunnel.Up() { + fmt.Println("Starting tunnel", t.ID()) + if t.SAMTunnel, err = t.Load(); err == nil { + t.Serve() + } + //return + } else { + fmt.Println(t.ID(), "already started") + req.URL.Path = req.URL.Path + "/color" + } + case "stop": + if t.SAMTunnel.Up() { + fmt.Println("Stopping tunnel", t.ID()) + t.Close() + } else { + fmt.Println(t.ID(), "already stopped") + req.URL.Path = req.URL.Path + "/color" + } + case "restart": + if t.SAMTunnel.Up() { + fmt.Println("Stopping tunnel", t.ID()) + t.Close() + fmt.Println("Starting tunnel", t.ID()) + if t.SAMTunnel, err = t.Load(); err == nil { + t.Serve() + } + return + } else { + fmt.Println(t.ID(), "stopped.") + req.URL.Path = req.URL.Path + "/color" + } + default: + } } } + if strings.HasSuffix(req.URL.Path, "color") { + fmt.Fprintf(rw, "
", t.SAMTunnel.ID(), t.SAMTunnel.GetType()) + } + t.Printdivf(t.SAMTunnel.ID(), "TunName", t.SAMTunnel.ID(), rw, req) fmt.Fprintf(rw, " \n", t.SAMTunnel.ID()) fmt.Fprintf(rw, " Show/Hide %s
\n", t.SAMTunnel.ID(), t.SAMTunnel.ID()) diff --git a/interface/interface.go b/interface/interface.go index 0b5b63a..e725294 100644 --- a/interface/interface.go +++ b/interface/interface.go @@ -13,4 +13,6 @@ type SAMTunnel interface { Base64() string Serve() error Close() error + Up() bool + Load() (SAMTunnel, error) } diff --git a/tcp/forwarder-client.go b/tcp/forwarder-client.go index 4f87bda..09449a5 100644 --- a/tcp/forwarder-client.go +++ b/tcp/forwarder-client.go @@ -11,6 +11,7 @@ import ( import ( "github.com/eyedeekay/sam-forwarder/i2pkeys" + "github.com/eyedeekay/sam-forwarder/interface" "github.com/eyedeekay/sam3" "github.com/eyedeekay/sam3/i2pkeys" ) @@ -35,6 +36,7 @@ type SAMClientForwarder struct { FilePath string file io.ReadWriter save bool + up bool // samcatd options passfile string @@ -249,15 +251,45 @@ func (f *SAMClientForwarder) Serve() error { } } +func (f *SAMClientForwarder) Up() bool { + return f.up +} + //Close shuts the whole thing down. func (f *SAMClientForwarder) Close() error { var err error err = f.samConn.Close() + f.up = false err = f.connectStream.Close() err = f.publishConnection.Close() return err } +func (s *SAMClientForwarder) Load() (samtunnel.SAMTunnel, error) { + if s.publishConnection, err = net.Listen("tcp", s.TargetHost+":"+s.TargetPort); err != nil { + return nil, err + } + if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { + return nil, err + } + log.Println("SAM Bridge connection established.") + if s.save { + log.Println("Saving i2p keys") + } + if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { + return nil, err + } + log.Println("Destination keys generated, tunnel name:", s.TunName) + if s.save { + if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { + return nil, err + } + log.Println("Saved tunnel keys for", s.TunName) + } + s.up = true + return s, nil +} + //NewSAMClientForwarder makes a new SAM forwarder with default options, accepts host:port arguments func NewSAMClientForwarder(host, port string) (*SAMClientForwarder, error) { return NewSAMClientForwarderFromOptions(SetClientHost(host), SetClientPort(port)) @@ -304,25 +336,9 @@ func NewSAMClientForwarderFromOptions(opts ...func(*SAMClientForwarder) error) ( return nil, err } } - if s.publishConnection, err = net.Listen("tcp", s.TargetHost+":"+s.TargetPort); err != nil { - return nil, err + l, e := s.Load() + if e != nil { + return nil, e } - if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { - return nil, err - } - log.Println("SAM Bridge connection established.") - if s.save { - log.Println("Saving i2p keys") - } - if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { - return nil, err - } - log.Println("Destination keys generated, tunnel name:", s.TunName) - if s.save { - if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { - return nil, err - } - log.Println("Saved tunnel keys for", s.TunName) - } - return &s, nil + return l.(*SAMClientForwarder), nil } diff --git a/tcp/forwarder.go b/tcp/forwarder.go index 0e0caf6..b5993f2 100644 --- a/tcp/forwarder.go +++ b/tcp/forwarder.go @@ -14,6 +14,7 @@ import ( import ( "github.com/eyedeekay/sam-forwarder/i2pkeys" + "github.com/eyedeekay/sam-forwarder/interface" "github.com/eyedeekay/sam3" "github.com/eyedeekay/sam3/i2pkeys" ) @@ -28,15 +29,15 @@ type SAMForwarder struct { TargetHost string TargetPort string - samConn *sam3.SAM - SamKeys i2pkeys.I2PKeys - publishStream *sam3.StreamSession - publishListen *sam3.StreamListener - publishConnection net.Conn + samConn *sam3.SAM + SamKeys i2pkeys.I2PKeys + publishStream *sam3.StreamSession + publishListen *sam3.StreamListener FilePath string file io.ReadWriter save bool + up bool Type string @@ -89,7 +90,6 @@ func (f *SAMForwarder) ID() string { func (f *SAMForwarder) Cleanup() { f.publishStream.Close() f.publishListen.Close() - f.publishConnection.Close() f.samConn.Close() } @@ -280,6 +280,9 @@ func (f *SAMForwarder) connUnlockAndClose(cli, conn bool, connection *sam3.SAMCo } func (f *SAMForwarder) forward(conn *sam3.SAMConn) { //(conn net.Conn) { + if !f.Up() { + return + } var request *http.Request var requestbytes []byte var responsebytes []byte @@ -335,38 +338,70 @@ func (f *SAMForwarder) Base64() string { //Serve starts the SAM connection and and forwards the local host:port to i2p func (f *SAMForwarder) Serve() error { //lsk, lspk, lspsk := f.leasesetsettings() - if f.publishStream, err = f.samConn.NewStreamSession(f.TunName, f.SamKeys, f.print()); 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) - - for { - conn, err := f.publishListen.AcceptI2P() - if err != nil { - log.Fatalf("ERROR: failed to accept listener: %v", err) + if f.Up() { + if f.publishStream, err = f.samConn.NewStreamSession(f.TunName, f.SamKeys, f.print()); 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) + + for { + conn, err := f.publishListen.AcceptI2P() + if err != nil { + log.Printf("ERROR: failed to accept listener: %v", err) + return nil + } + defer conn.Close() + log.Printf("Accepted connection %v\n", conn) + go f.forward(conn) } - log.Printf("Accepted connection %v\n", conn) - go f.forward(conn) } + return nil +} + +func (f *SAMForwarder) Up() bool { + return f.up } //Close shuts the whole thing down. func (f *SAMForwarder) Close() error { var err error - err = f.samConn.Close() + //err = f.samConn.Close() + f.up = false err = f.publishStream.Close() - err = f.publishListen.Close() - err = f.publishConnection.Close() + //err = f.samConn.Close() + //err = f.publishListen.Close() return err } +func (s *SAMForwarder) Load() (samtunnel.SAMTunnel, error) { + if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { + return nil, err + } + log.Println("SAM Bridge connection established.") + if s.save { + log.Println("Saving i2p keys") + } + if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { + return nil, err + } + log.Println("Destination keys generated, tunnel name:", s.TunName) + if s.save { + if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { + return nil, err + } + log.Println("Saved tunnel keys for", s.TunName) + } + s.up = true + return s, nil +} + //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)) @@ -413,22 +448,9 @@ func NewSAMForwarderFromOptions(opts ...func(*SAMForwarder) error) (*SAMForwarde return nil, err } } - if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { - return nil, err + l, e := s.Load() + if e != nil { + return nil, e } - log.Println("SAM Bridge connection established.") - if s.save { - log.Println("Saving i2p keys") - } - if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { - return nil, err - } - log.Println("Destination keys generated, tunnel name:", s.TunName) - if s.save { - if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { - return nil, err - } - log.Println("Saved tunnel keys for", s.TunName) - } - return &s, nil + return l.(*SAMForwarder), nil } diff --git a/udp/forwarder-client-udp.go b/udp/forwarder-client-udp.go index 889bbdf..e053d65 100644 --- a/udp/forwarder-client-udp.go +++ b/udp/forwarder-client-udp.go @@ -13,6 +13,7 @@ import ( import ( "github.com/eyedeekay/sam-forwarder/i2pkeys" + "github.com/eyedeekay/sam-forwarder/interface" "github.com/eyedeekay/sam3" "github.com/eyedeekay/sam3/i2pkeys" ) @@ -38,6 +39,7 @@ type SAMSSUClientForwarder struct { FilePath string file io.ReadWriter save bool + up bool // samcatd options passfile string @@ -87,6 +89,8 @@ func (f *SAMSSUClientForwarder) Cleanup() { } func (f *SAMSSUClientForwarder) Close() error { + f.Cleanup() + f.up = false return nil } @@ -249,6 +253,10 @@ func (f *SAMSSUClientForwarder) forward(conn net.PacketConn) { }() } +func (f *SAMSSUClientForwarder) Up() bool { + return f.up +} + //Serve starts the SAM connection and and forwards the local host:port to i2p func (f *SAMSSUClientForwarder) Serve() error { if f.addr, err = f.samConn.Lookup(f.dest); err != nil { @@ -272,6 +280,31 @@ func (f *SAMSSUClientForwarder) Serve() error { return nil } +func (s *SAMSSUClientForwarder) Load() (samtunnel.SAMTunnel, error) { + if s.publishConnection, err = net.ListenPacket("udp", s.TargetHost+":"+s.TargetPort); err != nil { + return nil, err + } + if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { + return nil, err + } + log.Println("SAM Bridge connection established.") + if s.save { + log.Println("Saving i2p keys") + } + if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { + return nil, err + } + log.Println("Destination keys generated, tunnel name:", s.TunName) + if s.save { + if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { + return nil, err + } + log.Println("Saved tunnel keys for", s.TunName) + } + s.up = true + return s, nil +} + //NewSAMSSUClientForwarderFromOptions makes a new SAM forwarder with default options, accepts host:port arguments func NewSAMSSUClientForwarderFromOptions(opts ...func(*SAMSSUClientForwarder) error) (*SAMSSUClientForwarder, error) { var s SAMSSUClientForwarder @@ -313,25 +346,9 @@ func NewSAMSSUClientForwarderFromOptions(opts ...func(*SAMSSUClientForwarder) er return nil, err } } - if s.publishConnection, err = net.ListenPacket("udp", s.TargetHost+":"+s.TargetPort); err != nil { - return nil, err + l, e := s.Load() + if e != nil { + return nil, e } - if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { - return nil, err - } - log.Println("SAM Bridge connection established.") - if s.save { - log.Println("Saving i2p keys") - } - if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { - return nil, err - } - log.Println("Destination keys generated, tunnel name:", s.TunName) - if s.save { - if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { - return nil, err - } - log.Println("Saved tunnel keys for", s.TunName) - } - return &s, nil + return l.(*SAMSSUClientForwarder), nil } diff --git a/udp/forwarder-udp.go b/udp/forwarder-udp.go index 287a43e..ffb7b80 100644 --- a/udp/forwarder-udp.go +++ b/udp/forwarder-udp.go @@ -13,6 +13,7 @@ import ( import ( "github.com/eyedeekay/sam-forwarder/i2pkeys" + "github.com/eyedeekay/sam-forwarder/interface" "github.com/eyedeekay/sam3" "github.com/eyedeekay/sam3/i2pkeys" ) @@ -36,6 +37,7 @@ type SAMSSUForwarder struct { FilePath string file io.ReadWriter save bool + up bool // samcatd options passfile string @@ -269,6 +271,31 @@ func (f *SAMSSUForwarder) Serve() error { } } +func (s *SAMSSUForwarder) Load() (samtunnel.SAMTunnel, error) { + if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { + return nil, err + } + log.Println("SAM Bridge connection established.") + if s.save { + log.Println("Saving i2p keys") + } + if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { + return nil, err + } + log.Println("Destination keys generated, tunnel name:", s.TunName) + if s.save { + if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { + return nil, err + } + log.Println("Saved tunnel keys for", s.TunName) + } + s.up = true + return s, nil +} +func (f *SAMSSUForwarder) Up() bool { + return f.up +} + //NewSAMSSUForwarder makes a new SAM forwarder with default options, accepts host:port arguments func NewSAMSSUForwarder(host, port string) (*SAMSSUForwarder, error) { return NewSAMSSUForwarderFromOptions(SetHost(host), SetPort(port)) @@ -313,22 +340,9 @@ func NewSAMSSUForwarderFromOptions(opts ...func(*SAMSSUForwarder) error) (*SAMSS return nil, err } } - if s.samConn, err = sam3.NewSAM(s.sam()); err != nil { - return nil, err + l, e := s.Load() + if e != nil { + return nil, e } - log.Println("SAM Bridge connection established.") - if s.save { - log.Println("Saving i2p keys") - } - if s.SamKeys, err = sfi2pkeys.Load(s.FilePath, s.TunName, s.passfile, s.samConn, s.save); err != nil { - return nil, err - } - log.Println("Destination keys generated, tunnel name:", s.TunName) - if s.save { - if err := sfi2pkeys.Save(s.FilePath, s.TunName, s.passfile, s.SamKeys); err != nil { - return nil, err - } - log.Println("Saved tunnel keys for", s.TunName) - } - return &s, nil + return l.(*SAMSSUForwarder), nil }