Esempio n. 1
0
func TestTCP(t *testing.T) {
	// Lower maxAssertAttempts to keep this test from running too long
	maxAssertAttempts = 2

	l0, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := l0.Close(); err != nil {
			t.Fatalf("Unable to close listener: %v", err)
		}
	}()

	start, fdc, err := Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}
	assert.Equal(t, 1, start, "Starting count should have been 1")

	err = fdc.AssertDelta(0)
	if err != nil {
		t.Fatal(err)
	}
	assert.NoError(t, err, "Initial TCP count should be 0")

	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	_, middle, err := Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	err = fdc.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have 1")
		assert.True(t, len(err.Error()) > 100)
	}
	err = fdc.AssertDelta(1)
	assert.NoError(t, err, "Ending TCP count should be 1")

	err = fdc.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have 1")
		assert.Contains(t, err.Error(), "New")
		assert.True(t, len(err.Error()) > 100)
	}

	if err := l.Close(); err != nil {
		t.Fatalf("Unable to close listener: %v", err)
	}
	err = middle.AssertDelta(0)
	if assert.Error(t, err, "Asserting wrong count should fail") {
		assert.Contains(t, err.Error(), "Expected 0, have -1")
		assert.Contains(t, err.Error(), "Removed")
		assert.True(t, len(err.Error()) > 100)
	}
}
Esempio n. 2
0
func TestGET(t *testing.T) {
	log.Debugf("TestGET")
	reqTemplate := "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n"
	resp := "HTTP/1.1 200 OK\r\n"
	content := "holla!\n"
	defer stopMockServers()
	site, _ := newMockServer(content)
	u, _ := url.Parse(site)
	log.Debugf("Started target site at %s", u)

	addr, _ := startServer(t)
	log.Debugf("Started proxy server at %s", addr)

	con, err := net.Dial("tcp", addr.String())
	if !assert.NoError(t, err, "should dial proxy server") {
		return
	}
	defer func() {
		assert.NoError(t, con.Close(), "should close connection")
	}()

	req := fmt.Sprintf(reqTemplate, u, u.Host)
	_, err = con.Write([]byte(req))
	if !assert.NoError(t, err, "should write request") {
		return
	}

	var buf [400]byte
	_, err = con.Read(buf[:])
	if !assert.Contains(t, string(buf[:]), resp, "should get 200 OK for GET") {
		return
	}
	assert.Contains(t, string(buf[:]), content, "should read content")
}
Esempio n. 3
0
func TestIdleOriginDirect(t *testing.T) {
	okServer, err := impatientProxy(0, 30*time.Second)
	if err != nil {
		assert.Fail(t, "Error starting proxy server: %s", err)
	}

	impatientServer, err := impatientProxy(0, 50*time.Millisecond)
	if err != nil {
		assert.Fail(t, "Error starting proxy server: %s", err)
	}

	okForwardFn := func(conn net.Conn, proxy *server.Server, originURL *url.URL) {
		var buf [400]byte
		chunkedReq(t, &buf, conn, originURL)
		assert.Contains(t, string(buf[:]), "200 OK", "should succeed")
	}

	failForwardFn := func(conn net.Conn, proxy *server.Server, originURL *url.URL) {
		var buf [400]byte
		chunkedReq(t, &buf, conn, originURL)
		assert.Contains(t, string(buf[:]), "502 Bad Gateway", "should fail with 502")
	}

	testRoundTrip(t, okServer, httpOriginServer, okForwardFn)
	testRoundTrip(t, impatientServer, httpOriginServer, failForwardFn)
}
Esempio n. 4
0
func TestDumpWhiteList(t *testing.T) {
	AddToWl("a.com:80", true)
	AddToWl("b.com:80", false)
	dumped := DumpWhitelist()
	assert.Contains(t, dumped, "a.com:80", "dumped list should contain permanent items")
	assert.NotContains(t, dumped, "b.com:80", "dumped list should not contain temporary items")
}
Esempio n. 5
0
func TestTimeout(t *testing.T) {
	offer := Offer(1 * time.Millisecond)
	_, err := offer.FiveTuple()
	assert.Error(t, err, "There should be an error")
	if err != nil {
		assert.Contains(t, err.Error(), "Timed out", "Error should mention timing out")
	}
}
Esempio n. 6
0
func TestNotOKWithServerName(t *testing.T) {
	fdStart := countTCPFiles()
	conn, err := Dial("tcp", ADDR, true, nil)
	assert.Error(t, err, "There should have been a problem dialing")
	if err != nil {
		assert.Contains(t, err.Error(), CERTIFICATE_ERROR, "Wrong error on dial")
	}
	<-receivedServerNames
	closeAndCountFDs(t, conn, err, fdStart)
}
Esempio n. 7
0
// X-Lantern-Auth-Token + X-Lantern-Device-Id -> Forward
func TestDirectOK(t *testing.T) {
	reqTempl := "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n"
	failResp := "HTTP/1.1 500 Internal Server Error\r\n"

	testOk := func(conn net.Conn, proxy *server.Server, originURL *url.URL) {
		req := fmt.Sprintf(reqTempl, originURL.Path, originURL.Host)
		t.Log("\n" + req)
		_, err := conn.Write([]byte(req))
		if !assert.NoError(t, err, "should write GET request") {
			t.FailNow()
		}

		buf := [400]byte{}
		_, err = conn.Read(buf[:])
		assert.Contains(t, string(buf[:]), originResponse, "should read tunneled response")

	}

	testFail := func(conn net.Conn, proxy *server.Server, originURL *url.URL) {
		req := fmt.Sprintf(reqTempl, originURL.Path, originURL.Host)
		t.Log("\n" + req)
		_, err := conn.Write([]byte(req))
		if !assert.NoError(t, err, "should write GET request") {
			t.FailNow()
		}

		buf := [400]byte{}
		_, err = conn.Read(buf[:])
		t.Log("\n" + string(buf[:]))

		assert.Contains(t, string(buf[:]), failResp, "should respond with 500 Internal Server Error")

	}

	testRoundTrip(t, httpProxy, httpOriginServer, testOk)
	testRoundTrip(t, tlsProxy, httpOriginServer, testOk)

	// HTTPS can't be tunneled using Direct Proxying, as redirections
	// require a TLS handshake between the proxy and the origin
	testRoundTrip(t, httpProxy, tlsOriginServer, testFail)
	testRoundTrip(t, tlsProxy, tlsOriginServer, testFail)
}
Esempio n. 8
0
func TestCONNECT(t *testing.T) {
	connectReq := "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n"
	tunneledReq := "GET / HTTP/1.1\r\n\r\n"
	connectResp := "HTTP/1.1 200 OK\r\n"
	tunneledResp := "holla!\n"
	defer stopMockServers()
	site, _ := newMockServer("holla!")
	u, _ := url.Parse(site)
	log.Debugf("Started target site at %s", u)

	addr, _ := startServer(t)
	log.Debugf("Started proxy server at %s", addr)

	con, err := net.Dial("tcp", addr.String())
	if !assert.NoError(t, err, "should dial proxy server") {
		return
	}
	defer func() {
		assert.NoError(t, con.Close(), "should close connection")
	}()

	req := fmt.Sprintf(connectReq, u.Host, u.Host)
	_, err = con.Write([]byte(req))
	if !assert.NoError(t, err, "should write CONNECT request") {
		return
	}

	var buf [400]byte
	_, err = con.Read(buf[:])
	if !assert.Contains(t, string(buf[:]), connectResp, "should get 200 OK for CONNECT") {
		return
	}

	_, err = con.Write([]byte(tunneledReq))
	if !assert.NoError(t, err, "should write tunneled data") {
		return
	}

	_, err = con.Read(buf[:])
	assert.Contains(t, string(buf[:]), tunneledResp, "should read tunneled response")
}
Esempio n. 9
0
func TestNotOKWithoutServerName(t *testing.T) {
	fdStart := countTCPFiles()
	conn, err := Dial("tcp", ADDR, true, &tls.Config{
		ServerName: "localhost",
	})
	assert.Error(t, err, "There should have been a problem dialing")
	if err != nil {
		assert.Contains(t, err.Error(), CERTIFICATE_ERROR, "Wrong error on dial")
	}
	serverName := <-receivedServerNames
	assert.Empty(t, serverName, "Unexpected ServerName on server")
	closeAndCountFDs(t, conn, err, fdStart)
}
Esempio n. 10
0
func readResponse(conn net.Conn, req *http.Request, t *testing.T) {
	buffIn := bufio.NewReader(conn)
	resp, err := http.ReadResponse(buffIn, req)
	if err != nil {
		t.Fatalf("Unable to read response: %s", err)
	}

	buff := bytes.NewBuffer(nil)
	_, err = io.Copy(buff, resp.Body)
	if err != nil {
		t.Fatalf("Unable to read response body: %s", err)
	}
	text := string(buff.Bytes())
	assert.Contains(t, text, TEXT, "Wrong text returned from server")
}
Esempio n. 11
0
func TestNotOKWithServerName(t *testing.T) {
	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	conn, err := Dial("tcp", ADDR, true, nil)
	assert.Error(t, err, "There should have been a problem dialing")
	if err != nil {
		assert.Contains(t, err.Error(), CERTIFICATE_ERROR, "Wrong error on dial")
	}
	<-receivedServerNames

	closeAndCountFDs(t, conn, err, fdc)
}
Esempio n. 12
0
func TestInvalidRequest(t *testing.T) {
	connectResp := "HTTP/1.1 400 Bad Request\r\n"
	testFn := func(conn net.Conn, proxy *server.Server, originURL *url.URL) {
		_, err := conn.Write([]byte("GET HTTP/1.1\r\n\r\n"))
		if !assert.NoError(t, err, "should write GET request") {
			t.FailNow()
		}

		buf := [400]byte{}
		_, err = conn.Read(buf[:])
		assert.Contains(t, string(buf[:]), connectResp, "should 400")

	}
	for i := 0; i < 10; i++ {
		testRoundTrip(t, httpProxy, tlsOriginServer, testFn)
		testRoundTrip(t, tlsProxy, tlsOriginServer, testFn)
	}
}
Esempio n. 13
0
func TestNotOKWithBadRootCert(t *testing.T) {
	badCert, err := keyman.LoadCertificateFromPEMBytes([]byte(GoogleInternetAuthority))
	if err != nil {
		t.Fatalf("Unable to load GoogleInternetAuthority cert: %s", err)
	}

	_, fdc, err := fdcount.Matching("TCP")
	if err != nil {
		t.Fatal(err)
	}

	conn, err := Dial("tcp", ADDR, true, &tls.Config{
		RootCAs: badCert.PoolContainingCert(),
	})
	assert.Error(t, err, "There should have been a problem dialing")
	if err != nil {
		assert.Contains(t, err.Error(), CERTIFICATE_ERROR, "Wrong error on dial")
	}
	<-receivedServerNames

	closeAndCountFDs(t, conn, err, fdc)
}
Esempio n. 14
0
func TestAll(t *testing.T) {
	// Start an echo server
	l, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		log.Fatalf("Unable to listen: %s", err)
	}
	defer func() {
		if err := l.Close(); err != nil {
			log.Fatalf("Unable to close listener: %v", err)
		}
	}()
	go func() {
		for {
			c, err := l.Accept()
			if err == nil {
				go func() {
					_, err = io.Copy(c, c)
					if err != nil {
						log.Fatalf("Unable to echo: %s", err)
					}
				}()
			}
		}
	}()
	addr := l.Addr().String()

	dialedBy := int32(0)

	dialer1Closed := int32(0)
	dialer1 := &Dialer{
		Label:  "Dialer 1",
		Weight: 1,
		QOS:    10,
		Dial: func(network, addr string) (net.Conn, error) {
			atomic.StoreInt32(&dialedBy, 1)
			return net.Dial(network, addr)
		},
		OnClose: func() {
			atomic.StoreInt32(&dialer1Closed, 1)
		},
	}
	dialer2 := &Dialer{
		Label:  "Dialer 2",
		Weight: 10000000,
		QOS:    1,
		Dial: func(network, addr string) (net.Conn, error) {
			atomic.StoreInt32(&dialedBy, 2)
			return net.Dial(network, addr)
		},
	}
	d3Attempts := int32(0)
	dialer3 := newFailingDialer(3, &dialedBy, &d3Attempts)

	d4attempts := int32(0)
	dialer4 := &Dialer{
		Label:  "Dialer 4",
		Weight: 1,
		QOS:    15,
		Dial: func(network, addr string) (net.Conn, error) {
			atomic.StoreInt32(&dialedBy, 4)
			defer atomic.AddInt32(&d4attempts, 1)
			if atomic.LoadInt32(&d4attempts) < 1 {
				// Fail once
				return nil, fmt.Errorf("Failing intentionally")
			} else {
				// Eventually succeed
				return net.Dial(network, addr)
			}
		},
	}

	// Test failure with no dialers
	b := New()
	_, err = b.Dial("tcp", addr)
	assert.Error(t, err, "Dialing with no dialers should have failed")

	// Test successful single dialer
	b = New(dialer1)
	defer func() {
		b.Close()
		time.Sleep(250 * time.Millisecond)
		assert.Equal(t, int32(1), atomic.LoadInt32(&dialer1Closed), "Dialer 1 should have been closed")
		_, err := b.Dial("tcp", addr)
		if assert.Error(t, err, "Dialing on closed balancer should fail") {
			assert.Contains(t, "No dialers left to try on pass 0", err.Error(), "Error should have mentioned that there were no dialers left to try")
		}
	}()
	conn, err := b.Dial("tcp", addr)
	assert.NoError(t, err, "Dialing should have succeeded")
	assert.Equal(t, 1, atomic.LoadInt32(&dialedBy), "Wrong dialedBy")
	if err == nil {
		doTestConn(t, conn)
	}

	// Test QOS
	dialedBy = 0
	b = New(dialer1, dialer2)
	defer b.Close()
	conn, err = b.DialQOS("tcp", addr, 5)
	assert.NoError(t, err, "Dialing should have succeeded")
	assert.Equal(t, 1, atomic.LoadInt32(&dialedBy), "Wrong dialedBy")
	if err == nil {
		doTestConn(t, conn)
	}

	// Test random selection
	dialedBy = 0
	conn, err = b.Dial("tcp", addr)
	assert.NoError(t, err, "Dialing should have succeeded")
	assert.Equal(t, 2, atomic.LoadInt32(&dialedBy), "Wrong dialedBy (note this has a 1/%d chance of failing)", (dialer1.Weight + dialer2.Weight))
	if err == nil {
		doTestConn(t, conn)
	}

	// Test success with failing dialer
	dialedBy = 0
	b = New(dialer1, dialer2, dialer3)
	defer b.Close()
	conn, err = b.DialQOS("tcp", addr, 20)
	assert.NoError(t, err, "Dialing should have succeeded")
	assert.Equal(t, 1, atomic.LoadInt32(&dialedBy), "Wrong dialedBy")
	if err == nil {
		doTestConn(t, conn)
	}

	d5Attempts := int32(0)
	dialer5 := newFailingDialer(5, &dialedBy, &d5Attempts)

	// Test that a dialer that initially fails will successfully get rechecked and ultimately succeed.
	b = New(dialer5)

	// Lower the maximum time between rechecks so the test can run in a reasonable amount of time.
	maxCheckTimeout = 100 * time.Millisecond

	// Dial a bunch of times on multiple goroutines to hit different failure branches. In the case
	// of the failing dialer, this ensures that we "use up" all the failures.
	var wg sync.WaitGroup
	wg.Add(2)
	for j := 0; j < 2; j++ {
		bn := b
		go func() {
			for i := 0; i < 50; i++ {
				_, err := bn.Dial("tcp", addr)
				assert.Error(t, err, "Dialing should have failed")
				time.Sleep(10 * time.Millisecond)
			}
			wg.Done()
		}()
	}

	wg.Wait()
	time.Sleep(1 * time.Second)

	assert.Equal(t, 6, atomic.LoadInt32(&d5Attempts), "Wrong number of check attempts on failed dialer")

	// Test success after successful recheck using custom check
	conn, err = b.DialQOS("tcp", addr, 20)
	assert.NoError(t, err, "Dialing should have succeeded on initially failing dialer")
	assert.Equal(t, 5, atomic.LoadInt32(&dialedBy), "Wrong dialedBy")
	if err == nil {
		doTestConn(t, conn)
	}

	// Test failure
	b = New(dialer4, dialer4)
	_, err = b.Dial("tcp", addr)
	assert.NoError(t, err, "Dialing should have succeeded as we have 2nd try")
	assert.Equal(t, 2, atomic.LoadInt32(&d4attempts), "Wrong number of dial attempts on failed dialer")

	// Test success after successful retest using default check
	conn, err = b.DialQOS("tcp", addr, 20)
	assert.NoError(t, err, "Dialing should have succeeded")
	assert.Equal(t, 4, atomic.LoadInt32(&dialedBy), "Wrong dialedBy")
	if err == nil {
		doTestConn(t, conn)
	}

}
Esempio n. 15
0
// X-Lantern-Auth-Token + X-Lantern-Device-Id -> 200 OK <- Tunneled request -> 200 OK
func TestConnectOK(t *testing.T) {
	connectReq := "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n"
	connectResp := "HTTP/1.1 200 OK\r\n"

	testHTTP := func(conn net.Conn, proxy *server.Server, originURL *url.URL) {
		req := fmt.Sprintf(connectReq, originURL.Host, originURL.Host)
		t.Log("\n" + req)
		_, err := conn.Write([]byte(req))
		if !assert.NoError(t, err, "should write CONNECT request") {
			t.FailNow()
		}

		var buf [400]byte
		_, err = conn.Read(buf[:])
		if !assert.Contains(t, string(buf[:]), connectResp,
			"should get 200 OK") {
			t.FailNow()
		}

		_, err = conn.Write([]byte(tunneledReq))
		if !assert.NoError(t, err, "should write tunneled data") {
			t.FailNow()
		}

		buf = [400]byte{}
		_, err = conn.Read(buf[:])
		assert.Contains(t, string(buf[:]), originResponse, "should read tunneled response")
	}

	testTLS := func(conn net.Conn, proxy *server.Server, originURL *url.URL) {
		req := fmt.Sprintf(connectReq, originURL.Host, originURL.Host)
		t.Log("\n" + req)
		_, err := conn.Write([]byte(req))
		if !assert.NoError(t, err, "should write CONNECT request") {
			t.FailNow()
		}

		var buf [400]byte
		_, err = conn.Read(buf[:])
		if !assert.Contains(t, string(buf[:]), connectResp,
			"should get 200 OK") {
			t.FailNow()
		}

		// HTTPS-Tunneled HTTPS
		tunnConn := tls.Client(conn, &tls.Config{
			InsecureSkipVerify: true,
		})
		tunnConn.Handshake()

		_, err = tunnConn.Write([]byte(tunneledReq))
		if !assert.NoError(t, err, "should write tunneled data") {
			t.FailNow()
		}

		buf = [400]byte{}
		_, err = tunnConn.Read(buf[:])
		assert.Contains(t, string(buf[:]), originResponse, "should read tunneled response")
	}

	testRoundTrip(t, httpProxy, httpOriginServer, testHTTP)
	testRoundTrip(t, tlsProxy, httpOriginServer, testHTTP)

	testRoundTrip(t, httpProxy, tlsOriginServer, testTLS)
	testRoundTrip(t, tlsProxy, tlsOriginServer, testTLS)
}