Parcourir la source

bug fixes; make ServerEntry and RemoteServerList struct members public

Rod Hynes il y a 11 ans
Parent
commit
f888440334

+ 4 - 4
psiphon/interruptibleConn.go

@@ -61,11 +61,11 @@ func NewInterruptibleConn(readTimeout, writeTimeout time.Duration, deviceName st
 	if deviceName != "" {
 		// TODO: requires root, which we won't have on Android in VpnService mode
 		//       an alternative may be to use http://golang.org/pkg/syscall/#UnixRights to
-		//       send the fd to the main Android process which received the fd with
+		//       send the fd to the main Android process which receives the fd with
 		//       http://developer.android.com/reference/android/net/LocalSocket.html#getAncillaryFileDescriptors%28%29
-		//       and then call
+		//       and then calls
 		//       http://developer.android.com/reference/android/net/VpnService.html#protect%28int%29.
-		//       See for example:
+		//       See, for example:
 		//       https://code.google.com/p/ics-openvpn/source/browse/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java#164
 		const SO_BINDTODEVICE = 0x19 // only defined for Linux
 		err = syscall.SetsockoptString(socketFd, syscall.SOL_SOCKET, SO_BINDTODEVICE, deviceName)
@@ -83,7 +83,7 @@ func NewInterruptibleConn(readTimeout, writeTimeout time.Duration, deviceName st
 func (interruptibleConn *InterruptibleConn) Connect(ipAddress string, port int) (err error) {
 	// TODO: domain name resolution (for meek)
 	var addr [4]byte
-	copy(addr[:], net.ParseIP(ipAddress)[:4])
+	copy(addr[:], net.ParseIP(ipAddress).To4())
 	sockAddr := syscall.SockaddrInet4{Addr: addr, Port: port}
 	err = syscall.Connect(interruptibleConn.socketFd, &sockAddr)
 	if err != nil {

+ 8 - 5
psiphon/obfuscator.go

@@ -58,23 +58,26 @@ func NewObfuscator(keyword string) (obfuscator *Obfuscator, err error) {
 	if err != nil {
 		return nil, err
 	}
-	obfuscator.clientToServerCipher, err = rc4.NewCipher(clientToServerKey)
+	serverToClientKey, err := deriveKey(seed, []byte(keyword), []byte(OBFUSCATE_SERVER_TO_CLIENT_IV))
 	if err != nil {
 		return nil, err
 	}
-	serverToClientKey, err := deriveKey(seed, []byte(keyword), []byte(OBFUSCATE_SERVER_TO_CLIENT_IV))
+	clientToServerCipher, err := rc4.NewCipher(clientToServerKey)
 	if err != nil {
 		return nil, err
 	}
-	obfuscator.serverToClientCipher, err = rc4.NewCipher(serverToClientKey)
+	serverToClientCipher, err := rc4.NewCipher(serverToClientKey)
 	if err != nil {
 		return nil, err
 	}
-	obfuscator.seedMessage, err = makeSeedMessage(seed, obfuscator.clientToServerCipher)
+	seedMessage, err := makeSeedMessage(seed, clientToServerCipher)
 	if err != nil {
 		return nil, err
 	}
-	return
+	return &Obfuscator{
+		seedMessage:          seedMessage,
+		clientToServerCipher: clientToServerCipher,
+		serverToClientCipher: serverToClientCipher}, nil
 }
 
 // ConsumeSeedMessage returns the seed message created in NewObfuscator,

+ 9 - 10
psiphon/remoteServerList.go

@@ -37,17 +37,16 @@ import (
 // entries. As it may be downloaded from various sources, it is digitally
 // signed so that the data may be authenticated.
 type RemoteServerList struct {
-	data                   string `json:"data"`
-	signingPublicKeyDigest string `json:"signingPublicKeyDigest"`
-	signature              string `json:"signature"`
+	Data                   string `json:"data"`
+	SigningPublicKeyDigest string `json:"signingPublicKeyDigest"`
+	Signature              string `json:"signature"`
 }
 
 // FetchRemoteServerList downloads a remote server list JSON record from
 // config.RemoteServerListUrl; validates its digital signature using the
 // public key config.RemoteServerListSignaturePublicKey; and parses the
 // data field into ServerEntry records.
-func FetchRemoteServerList(config *Config) (serverList []ServerEntry, err error) {
-	serverList = make([]ServerEntry, 0)
+func FetchRemoteServerList(config *Config) (serverList []*ServerEntry, err error) {
 	httpClient := http.Client{
 		Timeout: FETCH_REMOTE_SERVER_LIST_TIMEOUT,
 	}
@@ -69,7 +68,8 @@ func FetchRemoteServerList(config *Config) (serverList []ServerEntry, err error)
 	if err != nil {
 		return nil, err
 	}
-	for _, hexEncodedServerListItem := range strings.Split(remoteServerList.data, "\n") {
+	serverList = make([]*ServerEntry, 0)
+	for _, hexEncodedServerListItem := range strings.Split(remoteServerList.Data, "\n") {
 		decodedServerListItem, err := hex.DecodeString(hexEncodedServerListItem)
 		if err != nil {
 			return nil, err
@@ -84,7 +84,7 @@ func FetchRemoteServerList(config *Config) (serverList []ServerEntry, err error)
 		if err != nil {
 			return nil, err
 		}
-		serverList = append(serverList, serverEntry)
+		serverList = append(serverList, &serverEntry)
 	}
 	return serverList, nil
 }
@@ -102,19 +102,18 @@ func validateRemoteServerList(config *Config, remoteServerList *RemoteServerList
 	if !ok {
 		return errors.New("unexpected RemoteServerListSignaturePublicKey key type")
 	}
-	signature, err := base64.StdEncoding.DecodeString(remoteServerList.signature)
+	signature, err := base64.StdEncoding.DecodeString(remoteServerList.Signature)
 	if err != nil {
 		return err
 	}
 	// TODO: can detect if signed with different key --
 	// match digest(publicKey) against remoteServerList.signingPublicKeyDigest
 	hash := sha256.New()
-	hash.Write([]byte(remoteServerList.data))
+	hash.Write([]byte(remoteServerList.Data))
 	digest := hash.Sum(nil)
 	err = rsa.VerifyPKCS1v15(rsaPublicKey, crypto.SHA256, digest, signature)
 	if err != nil {
 		return err
 	}
-
 	return nil
 }

+ 5 - 5
psiphon/runTunnel.go

@@ -40,12 +40,12 @@ func establishTunnelWorker(
 	waitGroup *sync.WaitGroup, candidateQueue chan *Tunnel, firstEstablishedTunnel chan *Tunnel) {
 	defer waitGroup.Done()
 	for tunnel := range candidateQueue {
-		log.Printf("Connecting to %s...", tunnel.serverEntry.ipAddress)
+		log.Printf("Connecting to %s...", tunnel.serverEntry.IpAddress)
 		err := EstablishTunnel(tunnel)
 		if err != nil {
-			log.Printf("failed to connect to %s: %s", tunnel.serverEntry.ipAddress, err)
+			log.Printf("failed to connect to %s: %s", tunnel.serverEntry.IpAddress, err)
 		} else {
-			log.Printf("success connecting to %s", tunnel.serverEntry.ipAddress)
+			log.Printf("success connecting to %s", tunnel.serverEntry.IpAddress)
 			select {
 			case firstEstablishedTunnel <- tunnel:
 			default:
@@ -70,9 +70,9 @@ func runTunnel(config *Config) error {
 		return fmt.Errorf("failed to fetch remote server list: %s", err)
 	}
 	log.Printf("establishing tunnel")
-	candidateList := make([]*Tunnel, len(serverList))
+	candidateList := make([]*Tunnel, 0)
 	for _, serverEntry := range serverList {
-		candidateList = append(candidateList, &Tunnel{serverEntry: &serverEntry})
+		candidateList = append(candidateList, &Tunnel{serverEntry: serverEntry})
 	}
 	waitGroup := new(sync.WaitGroup)
 	candidateQueue := make(chan *Tunnel)

+ 17 - 17
psiphon/serverEntry.go

@@ -24,21 +24,21 @@ package psiphon
 // several protocols. ServerEntry are JSON records downloaded from
 // various sources.
 type ServerEntry struct {
-	ipAddress                     string   `json:"ipAddress"`
-	webServerPort                 string   `json:"webServerPort"` // not an int
-	webServerSecret               string   `json:"webServerSecret"`
-	webServerCertificate          string   `json:"webServerCertificate"`
-	sshPort                       int      `json:"sshPort"`
-	sshUsername                   string   `json:"sshUsername"`
-	sshPassword                   string   `json:"sshPassword"`
-	sshHostKey                    string   `json:"sshHostKey"`
-	sshObfuscatedPort             int      `json:"sshObfuscatedPort"`
-	sshObfuscatedKey              string   `json:"sshObfuscatedKey"`
-	capabilities                  []string `json:"capabilities"`
-	region                        string   `json:"region"`
-	meekServerPort                int      `json:"meekServerPort"`
-	meekCookieEncryptionPublicKey string   `json:"meekCookieEncryptionPublicKey"`
-	meekObfuscatedKey             string   `json:"meekObfuscatedKey"`
-	meekFrontingDomain            string   `json:"meekFrontingDomain"`
-	meekFrontingHost              string   `json:"meekFrontingHost"`
+	IpAddress                     string   `json:"ipAddress"`
+	WebServerPort                 string   `json:"webServerPort"` // not an int
+	WebServerSecret               string   `json:"webServerSecret"`
+	WebServerCertificate          string   `json:"webServerCertificate"`
+	SshPort                       int      `json:"sshPort"`
+	SshUsername                   string   `json:"sshUsername"`
+	SshPassword                   string   `json:"sshPassword"`
+	SshHostKey                    string   `json:"sshHostKey"`
+	SshObfuscatedPort             int      `json:"sshObfuscatedPort"`
+	SshObfuscatedKey              string   `json:"sshObfuscatedKey"`
+	Capabilities                  []string `json:"capabilities"`
+	Region                        string   `json:"region"`
+	MeekServerPort                int      `json:"meekServerPort"`
+	MeekCookieEncryptionPublicKey string   `json:"meekCookieEncryptionPublicKey"`
+	MeekObfuscatedKey             string   `json:"meekObfuscatedKey"`
+	MeekFrontingDomain            string   `json:"meekFrontingDomain"`
+	MeekFrontingHost              string   `json:"meekFrontingHost"`
 }

+ 12 - 11
psiphon/tunnel.go

@@ -24,6 +24,7 @@ import (
 	"code.google.com/p/go.crypto/ssh"
 	"encoding/base64"
 	"errors"
+	"fmt"
 	"net"
 	"strconv"
 	"strings"
@@ -67,12 +68,12 @@ func EstablishTunnel(tunnel *Tunnel) (err error) {
 	}
 	// First connect the transport
 	// TODO: meek
-	sshCapable := Contains(tunnel.serverEntry.capabilities, "SSH")
-	obfuscatedSshCapable := Contains(tunnel.serverEntry.capabilities, "OSSH")
+	sshCapable := Contains(tunnel.serverEntry.Capabilities, "SSH")
+	obfuscatedSshCapable := false //Contains(tunnel.serverEntry.Capabilities, "OSSH")
 	if !sshCapable && !obfuscatedSshCapable {
-		return errors.New("server does not have sufficient capabilities")
+		return fmt.Errorf("server does not have sufficient capabilities")
 	}
-	port := tunnel.serverEntry.sshPort
+	port := tunnel.serverEntry.SshPort
 	interruptibleConn, err := NewInterruptibleConn(0, CONNECTION_CANDIDATE_TIMEOUT, "")
 	if err != nil {
 		return err
@@ -80,18 +81,18 @@ func EstablishTunnel(tunnel *Tunnel) (err error) {
 	var conn net.Conn
 	conn = interruptibleConn
 	if obfuscatedSshCapable {
-		port = tunnel.serverEntry.sshObfuscatedPort
-		conn, err = NewObfuscatedSshConn(interruptibleConn, tunnel.serverEntry.sshObfuscatedKey)
+		port = tunnel.serverEntry.SshObfuscatedPort
+		conn, err = NewObfuscatedSshConn(interruptibleConn, tunnel.serverEntry.SshObfuscatedKey)
 		if err != nil {
 			return err
 		}
 	}
-	err = interruptibleConn.Connect(tunnel.serverEntry.ipAddress, port)
+	err = interruptibleConn.Connect(tunnel.serverEntry.IpAddress, port)
 	if err != nil {
 		return err
 	}
 	// Now establish the SSH session
-	expectedPublicKey, err := base64.StdEncoding.DecodeString(tunnel.serverEntry.sshHostKey)
+	expectedPublicKey, err := base64.StdEncoding.DecodeString(tunnel.serverEntry.SshHostKey)
 	if err != nil {
 		return err
 	}
@@ -104,14 +105,14 @@ func EstablishTunnel(tunnel *Tunnel) (err error) {
 		},
 	}
 	sshClientConfig := &ssh.ClientConfig{
-		User: tunnel.serverEntry.sshUsername,
+		User: tunnel.serverEntry.SshUsername,
 		Auth: []ssh.AuthMethod{
-			ssh.Password(tunnel.serverEntry.sshPassword),
+			ssh.Password(tunnel.serverEntry.SshPassword),
 		},
 		HostKeyCallback: sshCertChecker.CheckHostKey,
 	}
 	// The folowing is adapted from ssh.Dial(), here using a custom conn
-	sshAddress := strings.Join([]string{tunnel.serverEntry.ipAddress, ":", strconv.Itoa(tunnel.serverEntry.sshPort)}, "")
+	sshAddress := strings.Join([]string{tunnel.serverEntry.IpAddress, ":", strconv.Itoa(tunnel.serverEntry.SshPort)}, "")
 	sshConn, sshChans, sshReqs, err := ssh.NewClientConn(conn, sshAddress, sshClientConfig)
 	if err != nil {
 		return err