[tor-commits] [fog/master] Added a loading configuration file on the server side. The format is identical to the client configuration file except ClientTransportationPlugin is ServerTransportationPlugin. Uses go-shellwords to parse the config files.

infinity0 at torproject.org infinity0 at torproject.org
Fri Aug 1 16:50:37 UTC 2014


commit 58858475e5ba737ca0e7e271b7604fe1ac06bf75
Author: Quinn Jarrell <qjarrell at gosynapsify.com>
Date:   Mon Jun 23 16:15:18 2014 -0400

    Added a loading configuration file on the server side. The format is identical to the client configuration file except ClientTransportationPlugin is ServerTransportationPlugin. Uses go-shellwords to parse the config files.
---
 fog-server/Makefile      |    2 +-
 fog-server/config.go     |  145 ++++++++++++++++++++++++++++++++++++++++++++++
 fog-server/fog-server.go |   80 ++++---------------------
 fog-server/fogrc         |   13 +++++
 fog-server/torrc         |    2 +-
 5 files changed, 171 insertions(+), 71 deletions(-)

diff --git a/fog-server/Makefile b/fog-server/Makefile
index c7d474b..1a153a6 100644
--- a/fog-server/Makefile
+++ b/fog-server/Makefile
@@ -1,6 +1,6 @@
 GOBUILDFLAGS =
 
-./fog-server: ./fog-server.go ./stack.go
+./fog-server: ./fog-server.go ./stack.go ./config.go
 	go build $(GOBUILDFLAGS) -o "$@" $^
 
 test:
diff --git a/fog-server/config.go b/fog-server/config.go
new file mode 100644
index 0000000..615ea47
--- /dev/null
+++ b/fog-server/config.go
@@ -0,0 +1,145 @@
+package main
+
+import (
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"strings"
+)
+
+import "git.torproject.org/pluggable-transports/goptlib.git"
+import "github.com/mattn/go-shellwords"
+
+// Represents a server transport plugin configuration like:
+// 	ServerTransportPlugin MethodName exec Command
+type ServerTransportPlugin struct {
+	MethodName string
+	Command    []string
+	Options    pt.Args
+}
+
+type Configuration struct {
+	// Map from method names to command strings.
+	Transports map[string][]string
+	// Map from method names to ServerTransportOptions.
+	Options map[string]pt.Args
+	// Map from tor-friendly names like "obfs3_websocket" to systematic
+	// names like "obfs3|websocket".
+	Aliases map[string]string
+}
+
+func (conf *Configuration) MethodNames() []string {
+	result := make([]string, 0)
+	// We understand all the single transports
+	for k, _ := range conf.Transports {
+		result = append(result, k)
+	}
+	// and aliases.
+	for k, _ := range conf.Aliases {
+		result = append(result, k)
+	}
+	return result
+}
+
+// Parse a (possibly composed) method name into a slice of single method names.
+func (conf *Configuration) ParseMethodName(methodName string) []string {
+	if name, ok := conf.Aliases[methodName]; ok {
+		methodName = name
+	}
+	return strings.Split(methodName, "|")
+}
+
+func (conf *Configuration) PluginList(methodName string) ([]ServerTransportPlugin, error) {
+	names := conf.ParseMethodName(methodName)
+	stp := make([]ServerTransportPlugin, 0)
+	for _, name := range names {
+		command, ok := conf.Transports[name]
+		if !ok {
+			return nil, errors.New(fmt.Sprintf("no transport named %q", name))
+		}
+		options := conf.Options[name]
+		stp = append(stp, ServerTransportPlugin{name, command, options})
+	}
+	return stp, nil
+}
+
+// Initialize a configuration object
+func getConfiguration() (conf *Configuration) {
+	conf = new(Configuration)
+	conf.Transports = make(map[string][]string)
+	conf.Aliases = make(map[string]string)
+	conf.Options = make(map[string]pt.Args)
+	return conf
+}
+
+// Reads a configuration file and returns the contents
+func ReadConfigFile(fileName string) (*Configuration, error) {
+	var contents []byte
+	contents, err := ioutil.ReadFile(fileName)
+	if err != nil {
+		return nil, errors.New(fmt.Sprintf("Error reading configuration file %s contents.", fileName))
+	}
+	return ParseConfiguration(string(contents), getConfiguration())
+}
+
+// Parses a configuration string and fills the config object's fields with the requested Aliases and ServerTransportPlugins
+func ParseConfiguration(configString string, config *Configuration) (*Configuration, error) {
+	lines := strings.Split(configString, "\n")
+	for lineCounter, line := range lines {
+		if len(line) > 0 && line[0] != '#' { // Check for empty lines and comment tags on the first
+			line = strings.TrimSpace(line)
+			delimitedTokens, err := shellwords.Parse(line)
+			if err != nil {
+				return nil, errors.New(fmt.Sprintf("Line %v: \"%v\" was split incorrectly by shellwords. Error: %v", lineCounter, line, err))
+			}
+			if len(delimitedTokens) > 1 {
+				configLineType := delimitedTokens[0] // This can be either Alias or ServerTransportPlugin
+				if configLineType == "ServerTransportPlugin" {
+					err = parseTransportLine(config, delimitedTokens, lineCounter)
+					if err != nil {
+						return nil, err
+					}
+				} else if configLineType == "Alias" {
+					err = parseAliasLine(config, delimitedTokens, lineCounter)
+					if err != nil {
+						return nil, err
+					}
+				} else {
+					log("Configuration file has unknown line %s: %s", lineCounter, line)
+				}
+			}
+		}
+	}
+	return config, nil
+}
+
+// Parses a ServerTransportPlugin line.
+// Ex: ServerTransportPlugin dummy obfsproxy --client T managed
+func parseTransportLine(config *Configuration, tokens []string, lineCounter int) error {
+	transportName := tokens[1]
+	transportCmdLine := tokens[2:]
+	if _, ok := config.Transports[transportName]; ok {
+		return errors.New(fmt.Sprintf("Configuration file has duplicate ServerTransportPlugin lines. Duplicate line is at line number %s", lineCounter))
+	}
+	config.Transports[transportName] = transportCmdLine
+	return nil
+}
+
+// Parses an alias line
+// Ex: Alias b64_b64 b64|b64
+func parseAliasLine(config *Configuration, tokens []string, lineCounter int) error {
+	var aliasName string
+	var aliasPath []string
+	aliasName = tokens[1]
+	aliasPath = strings.Split(tokens[2], "|")
+	if _, hashed := config.Aliases[aliasName]; hashed {
+		return errors.New(fmt.Sprintf("Configuration file has duplicate Alias lines. Duplicate line is at line number %s", lineCounter))
+	}
+	for _, ptName := range aliasPath {
+		if _, hashed := config.Transports[ptName]; !hashed {
+			log("Transport map is missing pluggable transport %s needed for chain %s. Check your configuration file for a ServerTransportPlugin line can launch %s", ptName, aliasName, ptName)
+		}
+	}
+	config.Aliases[aliasName] = tokens[2]
+	return nil
+}
\ No newline at end of file
diff --git a/fog-server/fog-server.go b/fog-server/fog-server.go
index cf77a6a..9ee2703 100644
--- a/fog-server/fog-server.go
+++ b/fog-server/fog-server.go
@@ -39,6 +39,7 @@ func usage() {
 	fmt.Printf("  -h, --help   show this help.\n")
 	fmt.Printf("  --log FILE   log messages to FILE (default stderr).\n")
 	fmt.Printf("  --port PORT  listen on PORT (overrides Tor's requested port).\n")
+	fmt.Printf("  -f, --file FILE   Loads and runs configuration FILE.\n")
 }
 
 var logMutex sync.Mutex
@@ -174,14 +175,6 @@ func encodeServerTransportOptions(methodName string, opts pt.Args) string {
 	return strings.Join(parts, ";")
 }
 
-// Represents a server transport plugin configuration like:
-// 	ServerTransportPlugin MethodName exec Command
-type ServerTransportPlugin struct {
-	MethodName string
-	Command    []string
-	Options    pt.Args
-}
-
 func startProcesses(connectBackAddr net.Addr, plugins []ServerTransportPlugin) (bindAddr *net.TCPAddr, procs ProcList, err error) {
 	var stdout io.ReadCloser
 
@@ -393,72 +386,17 @@ func startChain(methodName string, bindaddr *net.TCPAddr, plugins []ServerTransp
 	return chain, nil
 }
 
-type Configuration struct {
-	// Map from method names to command strings.
-	Transports map[string][]string
-	// Map from method names to ServerTransportOptions.
-	Options map[string]pt.Args
-	// Map from tor-friendly names like "obfs3_websocket" to systematic
-	// names like "obfs3|websocket".
-	Aliases map[string]string
-}
-
-func (conf *Configuration) MethodNames() []string {
-	result := make([]string, 0)
-	// We understand all the single transports
-	for k, _ := range conf.Transports {
-		result = append(result, k)
-	}
-	// and aliases.
-	for k, _ := range conf.Aliases {
-		result = append(result, k)
-	}
-	return result
-}
-
-// Parse a (possibly composed) method name into a slice of single method names.
-func (conf *Configuration) ParseMethodName(methodName string) []string {
-	if name, ok := conf.Aliases[methodName]; ok {
-		methodName = name
-	}
-	return strings.Split(methodName, "|")
-}
-
-func (conf *Configuration) PluginList(methodName string) ([]ServerTransportPlugin, error) {
-	names := conf.ParseMethodName(methodName)
-	stp := make([]ServerTransportPlugin, 0)
-	for _, name := range names {
-		command, ok := conf.Transports[name]
-		if !ok {
-			return nil, errors.New(fmt.Sprintf("no transport named %q", name))
-		}
-		options := conf.Options[name]
-		stp = append(stp, ServerTransportPlugin{name, command, options})
-	}
-	return stp, nil
-}
-
-// Simulate loading a configuration file.
-func getConfiguration() (conf *Configuration) {
-	conf = new(Configuration)
-	conf.Transports = make(map[string][]string)
-	conf.Aliases = make(map[string]string)
-	conf.Options = make(map[string]pt.Args)
-	conf.Transports["obfs3"] = []string{"obfsproxy", "managed"}
-	conf.Transports["websocket"] = []string{"pt-websocket-server"}
-	// conf.Options["obfs3"] = make(pt.Args)
-	// conf.Options["obfs3"]["secret"] = []string{"foo"}
-	conf.Aliases["obfs3_websocket"] = "obfs3|websocket"
-	return conf
-}
-
 func main() {
 	var logFilename string
 	var port int
+	var configFilename string
+	var conf *Configuration
 
 	flag.Usage = usage
 	flag.StringVar(&logFilename, "log", "", "log file to write to")
 	flag.IntVar(&port, "port", 0, "port to listen on if unspecified by Tor")
+	flag.StringVar(&configFilename, "file", "fogrc", "The fog file to read the configuration from.")
+	flag.StringVar(&configFilename, "f", "fogrc", "The fog file to read the configuration from.")
 	flag.Parse()
 
 	if logFilename != "" {
@@ -469,11 +407,15 @@ func main() {
 		}
 		logFile = f
 	}
+	var err error
 
+	conf, err = ReadConfigFile(configFilename)
+	if err != nil {
+		log("Error in reading configuration file: %s", err)
+		os.Exit(1)
+	}
 	log("Starting.")
 
-	var err error
-	conf := getConfiguration()
 	ptInfo, err = pt.ServerSetup(conf.MethodNames())
 	if err != nil {
 		log("Error in ServerSetup: %s", err)
diff --git a/fog-server/fogrc b/fog-server/fogrc
new file mode 100644
index 0000000..870d8b6
--- /dev/null
+++ b/fog-server/fogrc
@@ -0,0 +1,13 @@
+#Based off of ticket #9744
+#Server transports are setup like so:
+#ServerTransportPlugin name commandline
+#For instance to launch obfs3, the server transport line should be this
+#ServerTransportPlugin obfs3 obfsproxy managed
+#
+#For chaining transports together, an alias line is used.
+#Alias chainname firsttransportname|secondtransportname
+#tor expects alias to use underscores instead of pipes. So an alias links the tor version of a plugin chain to the actual plugins. See ticket #9580
+
+ServerTransportPlugin obfs3 obfsproxy managed
+ServerTransportPlugin websocket pt-websocket-server
+Alias obfs3_websocket obfs3|websocket
\ No newline at end of file
diff --git a/fog-server/torrc b/fog-server/torrc
index f103ddc..88258fa 100644
--- a/fog-server/torrc
+++ b/fog-server/torrc
@@ -2,4 +2,4 @@ ORPort 9999
 ExtORPort 5555
 BridgeRelay 1
 SocksPort 0
-ServerTransportPlugin obfs3_websocket exec ./bin/fog-server
+ServerTransportPlugin obfs3_websocket exec ./fog-server



More information about the tor-commits mailing list