[tor-commits] [meek/master] Doc comments.

dcf at torproject.org dcf at torproject.org
Thu May 8 03:28:50 UTC 2014


commit 0ef39a5661475d3d414079284b2bbe3f24176f46
Author: David Fifield <david at bamsoftware.com>
Date:   Wed May 7 19:47:15 2014 -0700

    Doc comments.
---
 meek-client-torbrowser/meek-client-torbrowser.go   |   33 ++++++++--
 meek-client/helper.go                              |    3 +-
 meek-client/meek-client.go                         |   68 +++++++++++++++++---
 meek-server/meek-server.go                         |   49 +++++++++++---
 terminateprocess-buffer/terminateprocess-buffer.go |    3 +-
 5 files changed, 130 insertions(+), 26 deletions(-)

diff --git a/meek-client-torbrowser/meek-client-torbrowser.go b/meek-client-torbrowser/meek-client-torbrowser.go
index 6ddcf2f..21ef4d9 100644
--- a/meek-client-torbrowser/meek-client-torbrowser.go
+++ b/meek-client-torbrowser/meek-client-torbrowser.go
@@ -1,12 +1,31 @@
-// Usage:
-//   meek-client-torbrowser --log meek-client-torbrowser.log -- meek-client --url=https://meek-reflect.appspot.com/ --front=www.google.com --log meek-client.log
+// meek-client-torbrowser is an auxiliary program that helps with connecting
+// meek-client to meek-http-helper running in Tor Browser.
 //
-// The meek-client-torbrowser program starts a copy of Tor Browser running
-// meek-http-helper in a special profile, and then starts meek-client set up to
-// use the browser helper.
+// Sample usage in torrc (exact paths depend on platform):
+// 	ClientTransportPlugin meek exec ./meek-client-torbrowser --log meek-client-torbrowser.log -- ./meek-client --url=https://meek-reflect.appspot.com/ --front=www.google.com --log meek-client.log
+// Everything up to "--" is options for this program. Everything following it is
+// a meek-client command line. The command line for running firefox is implicit
+// and hardcoded in this program.
 //
-// Arguments to this program are passed unmodified to meek-client, with the
-// addition of a --helper option pointing to the browser helper.
+// This program, meek-client-torbrowser, starts a copy of firefox under the
+// meek-http-helper profile, which must have configured the meek-http-helper
+// extension. This program reads the stdout of firefox, looking for a special
+// line with the listening port number of the extension, one that looks like
+// "meek-http-helper: listen <address>". The meek-client command is then
+// executed as given, except that a --helper option is added that points to the
+// port number read from firefox.
+//
+// This program proxies stdin and stdout to and from meek-client, so it is
+// actually meek-client that drives the pluggable transport negotiation with
+// tor.
+//
+// The special --exit-on-stdin-eof is a special workaround for Windows. On
+// Windows we don't get a detectable shutdown signal that allows us to kill the
+// subprocesses we've started. Instead, use the --exit-on-stdin-eof option and
+// run this program inside of terminateprocess-buffer. When
+// terminateprocess-buffer is killed, it will close our stdin, and we can exit
+// gracefully. --exit-on-stdin-eof and terminateprocess-buffer need to be used
+// together.
 package main
 
 import (
diff --git a/meek-client/helper.go b/meek-client/helper.go
index 98fd771..49423fb 100644
--- a/meek-client/helper.go
+++ b/meek-client/helper.go
@@ -29,7 +29,8 @@ type JSONResponse struct {
 	Body   []byte `json:"body"`
 }
 
-// Ask a locally running browser extension to make the request for us.
+// Do an HTTP roundtrip through the configured browser extension, using the
+// payload data in buf and the request metadata in info.
 func roundTripWithHelper(buf []byte, info *RequestInfo) (*http.Response, error) {
 	s, err := net.DialTCP("tcp", nil, options.HelperAddr)
 	if err != nil {
diff --git a/meek-client/meek-client.go b/meek-client/meek-client.go
index 229bfd2..b3cce7a 100644
--- a/meek-client/meek-client.go
+++ b/meek-client/meek-client.go
@@ -1,3 +1,31 @@
+// meek-client is the client transport plugin for the meek pluggable transport.
+//
+// Sample usage in torrc:
+// 	Bridge meek 0.0.2.0:1
+// 	ClientTransportPlugin meek exec ./meek-client --url=https://meek-reflect.appspot.com/ --front=www.google.com --log meek-client.log
+// The transport ignores the bridge address 0.0.2.0:1 and instead connects to
+// the URL given by --url. When --front is given, the domain in the URL is
+// replaced by the front domain for the purpose of the DNS lookup, TCP
+// connection, and TLS SNI, but the HTTP Host header in the request will be the
+// one in --url. (For example, in the configuration above, the connection will
+// appear on the outside to be going to www.google.com, but it will actually be
+// dispatched to meek-reflect.appspot.com by the Google frontend server.)
+//
+// Most user configuration can happen either through SOCKS args (i.e., args on a
+// Bridge line) or through command line options. SOCKS args take precedence
+// per-connection over command line options. For example, this configuration
+// using SOCKS args:
+// 	Bridge meek 0.0.2.0:1 url=https://meek-reflect.appspot.com/ front=www.google.com
+// 	ClientTransportPlugin meek exec ./meek-client
+// is the same as this one using command line options.
+// 	Bridge meek 0.0.2.0:1
+// 	ClientTransportPlugin meek exec ./meek-client --url=https://meek-reflect.appspot.com/ --front=www.google.com
+// The advantage of SOCKS args is that multiple Bridge lines can have different
+// configurations, but it requires a newer tor.
+//
+// The --helper option prevents this program from doing any network operations
+// itself. Rather, it will send all requests through a browser extension that
+// makes HTTP requests.
 package main
 
 import (
@@ -22,12 +50,27 @@ import (
 import "git.torproject.org/pluggable-transports/goptlib.git"
 
 const (
-	ptMethodName            = "meek"
-	sessionIdLength         = 32
-	maxPayloadLength        = 0x10000
-	initPollInterval        = 100 * time.Millisecond
-	maxPollInterval         = 5 * time.Second
-	pollIntervalMultiplier  = 1.5
+	ptMethodName = "meek"
+	// A session ID is a randomly generated string that identifies a
+	// long-lived session. We split a TCP stream across multiple HTTP
+	// requests, and those with the same session ID belong to the same
+	// stream.
+	sessionIdLength = 32
+	// The size of the largest chunk of data we will read from the SOCKS
+	// port before forwarding it in a request, and the maximum size of a
+	// body we are willing to handle in a reply.
+	maxPayloadLength = 0x10000
+	// We must poll the server to see if it has anything to send; there is
+	// no way for the server to push data back to us until we send an HTTP
+	// request. When a timer expires, we send a request even if it has an
+	// empty body. The interval starts at this value and then grows.
+	initPollInterval = 100 * time.Millisecond
+	// Maximum polling interval.
+	maxPollInterval = 5 * time.Second
+	// Geometric increase in the polling interval each time we fail to read
+	// data.
+	pollIntervalMultiplier = 1.5
+	// Safety limits on interaction with the HTTP helper.
 	maxHelperResponseLength = 10000000
 	helperReadTimeout       = 60 * time.Second
 	helperWriteTimeout      = 2 * time.Second
@@ -35,6 +78,7 @@ const (
 
 var ptInfo pt.ClientInfo
 
+// Store for command line options.
 var options struct {
 	URL          string
 	Front        string
@@ -63,6 +107,8 @@ type RequestInfo struct {
 	HTTPProxyURL *url.URL
 }
 
+// Do an HTTP roundtrip using the payload data in buf and the request metadata
+// in info.
 func roundTripWithHTTP(buf []byte, info *RequestInfo) (*http.Response, error) {
 	tr := http.DefaultTransport
 	if info.HTTPProxyURL != nil {
@@ -82,6 +128,8 @@ func roundTripWithHTTP(buf []byte, info *RequestInfo) (*http.Response, error) {
 	return tr.RoundTrip(req)
 }
 
+// Send the data in buf to the remote URL, wait for a reply, and feed the reply
+// body back into conn.
 func sendRecv(buf []byte, conn net.Conn, info *RequestInfo) (int64, error) {
 	roundTrip := roundTripWithHTTP
 	if options.HelperAddr != nil {
@@ -100,6 +148,8 @@ func sendRecv(buf []byte, conn net.Conn, info *RequestInfo) (int64, error) {
 	return io.Copy(conn, io.LimitReader(resp.Body, maxPayloadLength))
 }
 
+// Repeatedly read from conn, issue HTTP requests, and write the responses back
+// to conn.
 func copyLoop(conn net.Conn, info *RequestInfo) error {
 	var interval time.Duration
 
@@ -183,6 +233,7 @@ func genSessionId() string {
 	return base64.StdEncoding.EncodeToString(buf)
 }
 
+// Callback for new SOCKS requests.
 func handler(conn *pt.SocksConn) error {
 	handlerChan <- 1
 	defer func() {
@@ -190,7 +241,6 @@ func handler(conn *pt.SocksConn) error {
 	}()
 
 	defer conn.Close()
-	// Ignore the IP address in the SOCKS request.
 	err := conn.Grant(&net.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: 0})
 	if err != nil {
 		return err
@@ -333,7 +383,7 @@ func main() {
 	sigChan := make(chan os.Signal, 1)
 	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
 
-	// wait for first signal
+	// Wait for first signal.
 	sig = nil
 	for sig == nil {
 		select {
@@ -352,7 +402,7 @@ func main() {
 		return
 	}
 
-	// wait for second signal or no more handlers
+	// Wait for second signal or no more handlers.
 	sig = nil
 	for sig == nil && numHandlers != 0 {
 		select {
diff --git a/meek-server/meek-server.go b/meek-server/meek-server.go
index 30964b8..cdbf448 100644
--- a/meek-server/meek-server.go
+++ b/meek-server/meek-server.go
@@ -1,3 +1,11 @@
+// meek-server is the server transport plugin for the meek pluggable transport.
+// It acts as an HTTP server, keeps track of session ids, and forwards received
+// data to a local OR port.
+//
+// Sample usage in torrc:
+// 	ServerTransportPlugin meek exec ./meek-server --port 8443 --cert cert.pem --key key.pem --log meek-server.log
+// Plain HTTP usage:
+// 	ServerTransportPlugin meek exec ./meek-server --port 8080 --disable-tls --log meek-server.log
 package main
 
 import (
@@ -20,14 +28,22 @@ import (
 import "git.torproject.org/pluggable-transports/goptlib.git"
 
 const (
-	ptMethodName       = "meek"
+	ptMethodName = "meek"
+	// Reject session ids shorter than this, as a weak defense against
+	// client bugs that send an empty session id or something similarly
+	// likely to collide.
 	minSessionIdLength = 32
-	maxPayloadLength   = 0x10000
-	// How long we try to read something back from the ORPort before returning the
-	// response.
+	// The largest request body we are willing to process, and the largest
+	// chunk of data we'll send back in a response.
+	maxPayloadLength = 0x10000
+	// How long we try to read something back from the OR port before
+	// returning the response.
 	turnaroundTimeout = 10 * time.Millisecond
-	// Passed as ReadTimeout and WriteTimeout when constructing the http.Server.
-	readWriteTimeout    = 20 * time.Second
+	// Passed as ReadTimeout and WriteTimeout when constructing the
+	// http.Server.
+	readWriteTimeout = 20 * time.Second
+	// Cull unused session ids (with their corresponding OR port connection)
+	// if we haven't seen any activity for this long.
 	maxSessionStaleness = 120 * time.Second
 )
 
@@ -45,19 +61,27 @@ func httpInternalServerError(w http.ResponseWriter) {
 	http.Error(w, "Internal server error.\n", http.StatusInternalServerError)
 }
 
+// Every session id maps to an existing OR port connection, which we keep open
+// between received requests. The first time we see a new session id, we create
+// a new OR port connection.
 type Session struct {
 	Or       *net.TCPConn
 	LastSeen time.Time
 }
 
+// Mark a session as having been seen just now.
 func (session *Session) Touch() {
 	session.LastSeen = time.Now()
 }
 
+// Is this session old enough to be culled?
 func (session *Session) IsExpired() bool {
 	return time.Since(session.LastSeen) > maxSessionStaleness
 }
 
+// There is one state per HTTP listener. In the usual case there is just one
+// listener, so there is just one global state. State also serves as the http
+// Handler.
 type State struct {
 	sessionMap map[string]*Session
 	lock       sync.Mutex
@@ -85,6 +109,7 @@ func (state *State) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	}
 }
 
+// Handle a GET request. This doesn't have any purpose apart from diagnostics.
 func (state *State) Get(w http.ResponseWriter, req *http.Request) {
 	if path.Clean(req.URL.Path) != "/" {
 		http.NotFound(w, req)
@@ -95,6 +120,8 @@ func (state *State) Get(w http.ResponseWriter, req *http.Request) {
 	w.Write([]byte("I’m just a happy little web server.\n"))
 }
 
+// Look up a session by id, or create a new one (with its OR port connection) if
+// it doesn't already exist.
 func (state *State) GetSession(sessionId string, req *http.Request) (*Session, error) {
 	state.lock.Lock()
 	defer state.lock.Unlock()
@@ -115,6 +142,8 @@ func (state *State) GetSession(sessionId string, req *http.Request) (*Session, e
 	return session, nil
 }
 
+// Feed the body of req into the OR port, and write any data read from the OR
+// port back to w.
 func transact(session *Session, w http.ResponseWriter, req *http.Request) error {
 	body := http.MaxBytesReader(w, req.Body, maxPayloadLength+1)
 	_, err := io.Copy(session.Or, body)
@@ -140,6 +169,7 @@ func transact(session *Session, w http.ResponseWriter, req *http.Request) error
 	return nil
 }
 
+// Handle a POST request. Look up the session id and then do a transaction.
 func (state *State) Post(w http.ResponseWriter, req *http.Request) {
 	sessionId := req.Header.Get("X-Session-Id")
 	if len(sessionId) < minSessionIdLength {
@@ -162,6 +192,8 @@ func (state *State) Post(w http.ResponseWriter, req *http.Request) {
 	}
 }
 
+// Remove a session from the map and closes its corresponding OR port
+// connection. Does nothing if the session id is not known.
 func (state *State) CloseSession(sessionId string) {
 	state.lock.Lock()
 	defer state.lock.Unlock()
@@ -173,6 +205,7 @@ func (state *State) CloseSession(sessionId string) {
 	}
 }
 
+// Loop forever, checking for expired sessions and removing them.
 func (state *State) ExpireSessions() {
 	for {
 		time.Sleep(maxSessionStaleness / 2)
@@ -319,7 +352,7 @@ func main() {
 	sigChan := make(chan os.Signal, 1)
 	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
 
-	// wait for first signal
+	// Wait for first signal.
 	sig = nil
 	for sig == nil {
 		select {
@@ -338,7 +371,7 @@ func main() {
 		return
 	}
 
-	// wait for second signal or no more handlers
+	// Wait for second signal or no more handlers.
 	sig = nil
 	for sig == nil && numHandlers != 0 {
 		select {
diff --git a/terminateprocess-buffer/terminateprocess-buffer.go b/terminateprocess-buffer/terminateprocess-buffer.go
index 16a7297..f826159 100644
--- a/terminateprocess-buffer/terminateprocess-buffer.go
+++ b/terminateprocess-buffer/terminateprocess-buffer.go
@@ -1,4 +1,5 @@
-// This program is designed to sit between tor and a transport plugin on
+// The terminateprocess-buffer program is designed to act as a
+// TerminateProcess-absorbing buffer between tor and a transport plugin on
 // Windows. On Windows, transport plugins are killed with a TerminateProcess,
 // which doesn't give them a chance to clean up before exiting.
 // https://trac.torproject.org/projects/tor/ticket/9330



More information about the tor-commits mailing list