summaryrefslogtreecommitdiff
path: root/obfs4-server
diff options
context:
space:
mode:
authorYawning Angel <yawning@schwanenlied.me>2014-05-09 10:23:58 +0000
committerYawning Angel <yawning@schwanenlied.me>2014-05-09 10:23:58 +0000
commitef38b844f9989dff25f553b583aeafc411dd100e (patch)
tree4162a60fd98f25c8f378523acd13e9adc319df52 /obfs4-server
Initial import.
Diffstat (limited to 'obfs4-server')
-rw-r--r--obfs4-server/obfs4-server.go225
1 files changed, 225 insertions, 0 deletions
diff --git a/obfs4-server/obfs4-server.go b/obfs4-server/obfs4-server.go
new file mode 100644
index 0000000..aac2351
--- /dev/null
+++ b/obfs4-server/obfs4-server.go
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2014, Yawning Angel <yawning at torproject dot org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is based off goptlib's dummy-server.go file.
+ */
+
+// obfs4 pluggable transport server. Works only as a managed proxy.
+//
+// Usage (in torrc):
+// BridgeRelay 1
+// ORPort 9001
+// ExtORPort 6669
+// ServerTransportPlugin obfs4 exec obfs4-server
+// ServerTransportOptions obfs4 private-key=<Base64 Bridge private key> node-id=<Base64 Node ID>
+//
+// Becuase the pluggable transport requires arguments, using obfs4-server
+// requires tor 0.2.5.x.
+package main
+
+import (
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+
+ "github.com/yawning/obfs4"
+ "github.com/yawning/obfs4/ntor"
+)
+
+import "git.torproject.org/pluggable-transports/goptlib.git"
+
+var ptInfo pt.ServerInfo
+
+// When a connection handler starts, +1 is written to this channel; when it
+// ends, -1 is written.
+var handlerChan = make(chan int)
+
+func copyLoop(a, b net.Conn) {
+ var wg sync.WaitGroup
+ wg.Add(2)
+
+ go func() {
+ io.Copy(b, a)
+ wg.Done()
+ }()
+ go func() {
+ io.Copy(a, b)
+ wg.Done()
+ }()
+
+ wg.Wait()
+}
+
+func handler(conn net.Conn) error {
+ defer conn.Close()
+
+ handlerChan <- 1
+ defer func() {
+ handlerChan <- -1
+ }()
+
+ or, err := pt.DialOr(&ptInfo, conn.RemoteAddr().String(), "obfs4")
+ if err != nil {
+ return err
+ }
+ defer or.Close()
+
+ copyLoop(conn, or)
+
+ return nil
+}
+
+func acceptLoop(ln net.Listener) error {
+ defer ln.Close()
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ if e, ok := err.(net.Error); ok && !e.Temporary() {
+ return err
+ }
+ continue
+ }
+ go handler(conn)
+ }
+}
+
+func generateParams(id string) {
+ rawID, err := hex.DecodeString(id)
+ if err != nil {
+ fmt.Println("Failed to hex decode id:", err)
+ return
+ }
+
+ parsedID, err := ntor.NewNodeID(rawID)
+ if err != nil {
+ fmt.Println("Failed to parse id:", err)
+ return
+ }
+
+ fmt.Println("Generated node_id:", parsedID.Base64())
+
+ keypair, err := ntor.NewKeypair(false)
+ if err != nil {
+ fmt.Println("Failed to generate keypair:", err)
+ return
+ }
+
+ fmt.Println("Generated private-key:", keypair.Private().Base64())
+ fmt.Println("Generated public-key:", keypair.Public().Base64())
+}
+
+func main() {
+ var err error
+
+ // Some command line args.
+ genParams := flag.String("gen", "", "Generate params given a Node ID.")
+ flag.Parse()
+ if *genParams != "" {
+ generateParams(*genParams)
+ os.Exit(0)
+ }
+
+ // Ok, guess we're in PT land.
+ ptInfo, err = pt.ServerSetup([]string{"obfs4"})
+ if err != nil {
+ os.Exit(1)
+ }
+
+ listeners := make([]net.Listener, 0)
+ for _, bindaddr := range ptInfo.Bindaddrs {
+ switch bindaddr.MethodName {
+ case "obfs4":
+ // Handle the mandetory arguments.
+ privateKey, ok := bindaddr.Options.Get("private-key")
+ if !ok {
+ pt.SmethodError(bindaddr.MethodName, "need a private-key option")
+ break
+ }
+ nodeID, ok := bindaddr.Options.Get("node-id")
+ if !ok {
+ pt.SmethodError(bindaddr.MethodName, "need a node-id option")
+ break
+ }
+
+ ln, err := obfs4.Listen("tcp", bindaddr.Addr.String(), nodeID,
+ privateKey)
+ if err != nil {
+ pt.SmethodError(bindaddr.MethodName, err.Error())
+ break
+ }
+
+ oLn, _ := ln.(*obfs4.Obfs4Listener)
+ args := pt.Args{}
+ args.Add("node-id", nodeID)
+ args.Add("public-key", oLn.PublicKey())
+ go acceptLoop(ln)
+ pt.SmethodArgs(bindaddr.MethodName, ln.Addr(), args)
+ // TODO: Maybe log the args?
+ listeners = append(listeners, ln)
+ default:
+ pt.SmethodError(bindaddr.MethodName, "no such method")
+ }
+ }
+ pt.SmethodsDone()
+
+ var numHandlers int = 0
+ var sig os.Signal
+ sigChan := make(chan os.Signal, 1)
+ signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
+
+ // wait for first signal
+ sig = nil
+ for sig == nil {
+ select {
+ case n := <-handlerChan:
+ numHandlers += n
+ case sig = <-sigChan:
+ }
+ }
+ for _, ln := range listeners {
+ ln.Close()
+ }
+
+ if sig == syscall.SIGTERM {
+ return
+ }
+
+ // wait for second signal or no more handlers
+ sig = nil
+ for sig == nil && numHandlers != 0 {
+ select {
+ case n := <-handlerChan:
+ numHandlers += n
+ case sig = <-sigChan:
+ }
+ }
+}