Skip to content

Commit 7b523cb

Browse files
committed
Fix Blackhole implementation for e2e tests
Based on the ideas discussed in the issues [1] and PRs [2][3][6], it's been decided to switch from using an L4 reverse proxy to an L7 forward proxy to properly block peer network traffic, without the need to use external tools. The design aims to implement only the minimal required features that satisfy blocking incoming and outgoing peer traffic. Complicated features such as packet reordering, packet delivery delay, etc. to a future container-based solution. A peer will (a) receive traffic from its peers (b) initiate connections to its peers (via stream and pipeline). Thus, the current mechanism of only blocking peer traffic via the peer's existing reverse proxy is insufficient, since only scenario (a) is handled, and network traffic in scenario (b) is not blocked at all. We introduce an L7 forward proxy for each peer, which will be proxying all the connections initiated from a peer to its peers. We will remove the current use of the L4 reverse proxy, as the L7 forward proxy holds the information of the destination, we can block all incoming and outgoing traffic that is initiated from a peer to others, without having to resort to external tools, such as iptables. The modified architecture will look something like this: ``` A --- A's forward proxy --- B ^ newly introduced ``` The main subtasks are - redesigned as an L7 forward proxy - introduce a new environment variable `E2E_TEST_FORWARD_PROXY_IP` to bypass the limitation of `http.ProxyFromEnvironment` - implement an L7 forward proxy Known limitations are - Doesn't support unix socket, as L7 HTTP transport proxy only supports HTTP/HTTPS/and socks5 -> Although the e2e test supports unix sockets for peer communication, only a few of the e2e test cases use unix sockets as the majority of e2e test cases use HTTP/HTTPS. It's been discussed and decided that it is ok for now without the unix socket support. - it's L7 so we need to send a perfectly crafted HTTP request - doesn’t support reordering, dropping, or manipulating packets on the fly - `make gofail-enable && make build && make gofail-disable && go test -timeout 60s -run ^TestBlackholeByMockingPartitionLeader$ go.etcd.io/etcd/tests/v3/e2e -v -count=1` - `make gofail-enable && make build && make gofail-disable && go test -timeout 60s -run ^TestBlackholeByMockingPartitionFollower$ go.etcd.io/etcd/tests/v3/e2e -v -count=1` - `go test -timeout 30s -run ^TestServer_ go.etcd.io/etcd/pkg/v3/proxy -v -failfast` [1] issue #17737 [2] PR (V1) https://github.com/henrybear327/etcd/tree/fix/e2e_blackhole [3] PR (V2) #17891 [4] #17938 (comment) [5] #17985 (comment) [6] #17938 Please read https://github.com/etcd-io/etcd/blob/main/CONTRIBUTING.md#contribution-flow. Signed-off-by: Siyuan Zhang <[email protected]> Signed-off-by: Iván Valdés Castillo <[email protected]> Signed-off-by: Chun-Hung Tseng <[email protected]>
1 parent ea9179a commit 7b523cb

File tree

8 files changed

+782
-660
lines changed

8 files changed

+782
-660
lines changed

client/pkg/transport/transport.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,29 @@ import (
1818
"context"
1919
"net"
2020
"net/http"
21+
"net/url"
22+
"os"
2123
"strings"
2224
"time"
2325
)
2426

2527
type unixTransport struct{ *http.Transport }
2628

29+
var httpTransportProxyParsingFunc = determineHTTPTransportProxyParsingFunc
30+
31+
func determineHTTPTransportProxyParsingFunc() func(req *http.Request) (*url.URL, error) {
32+
// according to the comment of http.ProxyFromEnvironment: if the proxy URL is "localhost"
33+
// (with or without a port number), then a nil URL and nil error will be returned.
34+
// Thus, we workaround this limitation by manually setting an ENV named E2E_TEST_FORWARD_PROXY_IP
35+
// and parse the URL (which is a localhost in our case)
36+
if forwardProxy, exists := os.LookupEnv("E2E_TEST_FORWARD_PROXY_IP"); exists {
37+
return func(req *http.Request) (*url.URL, error) {
38+
return url.Parse(forwardProxy)
39+
}
40+
}
41+
return http.ProxyFromEnvironment
42+
}
43+
2744
func NewTransport(info TLSInfo, dialtimeoutd time.Duration) (*http.Transport, error) {
2845
cfg, err := info.ClientConfig()
2946
if err != nil {
@@ -39,7 +56,7 @@ func NewTransport(info TLSInfo, dialtimeoutd time.Duration) (*http.Transport, er
3956
}
4057

4158
t := &http.Transport{
42-
Proxy: http.ProxyFromEnvironment,
59+
Proxy: httpTransportProxyParsingFunc(),
4360
DialContext: (&net.Dialer{
4461
Timeout: dialtimeoutd,
4562
LocalAddr: ipAddr,
@@ -60,7 +77,7 @@ func NewTransport(info TLSInfo, dialtimeoutd time.Duration) (*http.Transport, er
6077
return dialer.DialContext(ctx, "unix", addr)
6178
}
6279
tu := &http.Transport{
63-
Proxy: http.ProxyFromEnvironment,
80+
Proxy: httpTransportProxyParsingFunc(),
6481
DialContext: dialContext,
6582
TLSHandshakeTimeout: 10 * time.Second,
6683
TLSClientConfig: cfg,

0 commit comments

Comments
 (0)