Просмотр исходного кода

Merge pull request #62 from rod-hynes/master

Fix: upstream HTTP proxy bugs
Rod Hynes 11 лет назад
Родитель
Сommit
f8d0e09ca1
5 измененных файлов с 37 добавлено и 17 удалено
  1. 5 5
      psiphon/TCPConn_windows.go
  2. 11 7
      psiphon/conn.go
  3. 1 1
      psiphon/httpProxy.go
  4. 1 1
      psiphon/socksProxy.go
  5. 19 3
      psiphon/utils.go

+ 5 - 5
psiphon/TCPConn_windows.go

@@ -73,11 +73,11 @@ func interruptibleTCPDial(addr string, config *DialConfig) (conn *TCPConn, err e
 
 		netConn, err := net.DialTimeout("tcp", dialAddr, config.ConnectTimeout)
 
-		if config.UpstreamHttpProxyAddress != "" {
-			err := HttpProxyConnect(netConn, addr)
-			if err != nil {
-				netConn = nil
-			}
+		if err == nil && config.UpstreamHttpProxyAddress != "" {
+			err = HttpProxyConnect(netConn, addr)
+		}
+		if err != nil {
+			netConn = nil
 		}
 
 		results <- &interruptibleDialResult{netConn, err}

+ 11 - 7
psiphon/conn.go

@@ -20,10 +20,13 @@
 package psiphon
 
 import (
-	"bytes"
+	"bufio"
+	"errors"
 	"fmt"
 	"io"
 	"net"
+	"net/http"
+	"strings"
 	"sync"
 	"time"
 )
@@ -168,15 +171,16 @@ func HttpProxyConnect(rawConn net.Conn, addr string) (err error) {
 		return ContextError(err)
 	}
 
-	expectedResponse := []byte("HTTP/1.1 200 OK\r\n\r\n")
-	readBuffer := make([]byte, len(expectedResponse))
-	_, err = io.ReadFull(rawConn, readBuffer)
+	// Adapted from dialConn in net/http/transport.go:
+	// Read response.
+	// Okay to use and discard buffered reader here, because
+	// TLS server will not speak until spoken to.
+	response, err := http.ReadResponse(bufio.NewReader(rawConn), nil)
 	if err != nil {
 		return ContextError(err)
 	}
-
-	if !bytes.Equal(readBuffer, expectedResponse) {
-		return fmt.Errorf("unexpected HTTP proxy response: %s", string(readBuffer))
+	if response.StatusCode != 200 {
+		return ContextError(errors.New(strings.SplitN(response.Status, " ", 2)[1]))
 	}
 
 	return nil

+ 1 - 1
psiphon/httpProxy.go

@@ -44,7 +44,7 @@ func NewHttpProxy(config *Config, tunneler Tunneler) (proxy *HttpProxy, err erro
 	listener, err := net.Listen(
 		"tcp", fmt.Sprintf("127.0.0.1:%d", config.LocalHttpProxyPort))
 	if err != nil {
-		if IsNetworkBindError(err) {
+		if IsAddressInUseError(err) {
 			NoticeHttpProxyPortInUse(config.LocalSocksProxyPort)
 		}
 		return nil, ContextError(err)

+ 1 - 1
psiphon/socksProxy.go

@@ -46,7 +46,7 @@ func NewSocksProxy(config *Config, tunneler Tunneler) (proxy *SocksProxy, err er
 	listener, err := socks.ListenSocks(
 		"tcp", fmt.Sprintf("127.0.0.1:%d", config.LocalSocksProxyPort))
 	if err != nil {
-		if IsNetworkBindError(err) {
+		if IsAddressInUseError(err) {
 			NoticeSocksProxyPortInUse(config.LocalSocksProxyPort)
 		}
 		return nil, ContextError(err)

+ 19 - 3
psiphon/utils.go

@@ -26,8 +26,11 @@ import (
 	"errors"
 	"fmt"
 	"math/big"
+	"net"
+	"os"
 	"runtime"
 	"strings"
+	"syscall"
 	"time"
 )
 
@@ -141,7 +144,20 @@ func ContextError(err error) error {
 	return fmt.Errorf("%s#%d: %s", funcName, line, err)
 }
 
-// IsNetworkBindError returns true when the err is due to EADDRINUSE.
-func IsNetworkBindError(err error) bool {
-	return strings.Contains(err.Error(), "bind: address already in use")
+// IsAddressInUseError returns true when the err is due to EADDRINUSE/WSAEADDRINUSE.
+func IsAddressInUseError(err error) bool {
+	if err, ok := err.(*net.OpError); ok {
+		if err, ok := err.Err.(*os.SyscallError); ok {
+			if err.Err == syscall.EADDRINUSE {
+				return true
+			}
+			// Special case for Windows (WSAEADDRINUSE = 10048)
+			if errno, ok := err.Err.(syscall.Errno); ok {
+				if 10048 == int(errno) {
+					return true
+				}
+			}
+		}
+	}
+	return false
 }