[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [meek/master] Doc comments.
commit 0ef39a5661475d3d414079284b2bbe3f24176f46
Author: David Fifield <david@xxxxxxxxxxxxxxx>
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
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits