summaryrefslogtreecommitdiff
path: root/shapeshifter.go
diff options
context:
space:
mode:
Diffstat (limited to 'shapeshifter.go')
-rw-r--r--shapeshifter.go71
1 files changed, 45 insertions, 26 deletions
diff --git a/shapeshifter.go b/shapeshifter.go
index 25a6400..c717cd2 100644
--- a/shapeshifter.go
+++ b/shapeshifter.go
@@ -6,13 +6,33 @@ import (
"io"
"log"
"net"
+ "strconv"
"sync"
- "github.com/OperatorFoundation/obfs4/common/ntor"
- "github.com/OperatorFoundation/shapeshifter-transports/transports/obfs4/v2"
+ pt "git.torproject.org/pluggable-transports/goptlib.git"
+ "gitlab.com/yawning/obfs4.git/common/ntor"
+ "gitlab.com/yawning/obfs4.git/transports/obfs4"
"golang.org/x/net/proxy"
)
+const (
+ certLength = ntor.NodeIDLength + ntor.PublicKeyLength
+)
+
+func unpackCert(cert string) (*ntor.NodeID, *ntor.PublicKey, error) {
+ if l := base64.RawStdEncoding.DecodedLen(len(cert)); l != certLength {
+ return nil, nil, fmt.Errorf("cert length %d is invalid", l)
+ }
+ decoded, err := base64.RawStdEncoding.DecodeString(cert)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ nodeID, _ := ntor.NewNodeID(decoded[:ntor.NodeIDLength])
+ pubKey, _ := ntor.NewPublicKey(decoded[ntor.NodeIDLength:])
+ return nodeID, pubKey, nil
+}
+
type Logger interface {
Log(msg string)
}
@@ -78,12 +98,31 @@ func (ss ShapeShifter) clientHandler(conn net.Conn) {
defer conn.Close()
dialer := proxy.Direct
- transport, err := obfs4.NewObfs4Client(ss.Cert, ss.IatMode, dialer)
+ // The empty string is the StateDir argument which appears unused on the
+ // client side. I am unsure why the clientfactory requires it; possibly to
+ // satisfy an interface somewhere, but this is not documented.
+ //transport, err := obfs4.NewObfs4Client(ss.Cert, ss.IatMode, dialer)
+
+ transport, err := (&obfs4.Transport{}).ClientFactory("")
if err != nil {
ss.sendError("Can not create an obfs4 client (cert: %s, iat-mode: %d): %v", ss.Cert, ss.IatMode, err)
return
}
- remote, err := transport.Dial(ss.Target)
+ ptArgs := make(pt.Args)
+ nodeID, pubKey, err := unpackCert(ss.Cert)
+ if err != nil {
+ ss.sendError("Error unpacking cert: %v", err)
+ return
+ }
+ ptArgs.Add("node-id", nodeID.Hex())
+ ptArgs.Add("public-key", pubKey.Hex())
+ ptArgs.Add("iat-mode", strconv.Itoa(ss.IatMode))
+ args, err := transport.ParseArgs(&ptArgs)
+ if err != nil {
+ ss.sendError("Cannot parse arguments: %v", err)
+ return
+ }
+ remote, err := transport.Dial("tcp", ss.Target, dialer.Dial, args)
if err != nil {
ss.sendError("outgoing connection failed %s: %v", ss.Target, err)
return
@@ -142,7 +181,8 @@ func (ss *ShapeShifter) checkOptions() error {
if ss.SocksAddr == "" {
ss.SocksAddr = "127.0.0.1:0"
}
- return isCertValid(ss.Cert)
+ _, _, err := unpackCert(ss.Cert)
+ return err
}
func (ss *ShapeShifter) sendError(format string, a ...interface{}) {
@@ -160,24 +200,3 @@ func (ss *ShapeShifter) sendError(format string, a ...interface{}) {
log.Printf(format, a...)
}
}
-
-func isCertValid(cert string) error {
- // copied from github.com/OperatorFoundation/shapeshifter-transports/transports/obfs4/statefile.go
- const certSuffix = "=="
- const certLength = ntor.NodeIDLength + ntor.PublicKeyLength
-
- if cert == "" {
- return fmt.Errorf("obfs4 transport missing cert argument")
- }
-
- decoded, err := base64.StdEncoding.DecodeString(cert + certSuffix)
- if err != nil {
- return fmt.Errorf("failed to decode cert: %s", err)
- }
-
- if len(decoded) != certLength {
- return fmt.Errorf("cert length %d is invalid", len(decoded))
- }
-
- return nil
-}