-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
webconnectivityqa: import test cases using proxies (#1239)
## Checklist - [x] I have read the [contribution guidelines](https://github.com/ooni/probe-cli/blob/master/CONTRIBUTING.md) - [x] reference issue for this pull request: ooni/probe#1803 - [x] if you changed anything related to how experiments work and you need to reflect these changes in the ooni/spec repository, please link to the related ooni/spec pull request: N/A - [x] if you changed code inside an experiment, make sure you bump its version number: N/A ## Description This diff imports into webconnectivityqa test cases using proxies that are currently also implemented by ./QA/webconnectivity.py. The ./QA/webconnectivity.py contains three test cases. Two of them deal with using transparent proxies without DNS lies, which was easy to do using iptables, and much harder now. However, it's doubtful whether those two cases are actually very useful, since there is no measurement feature which allows us to distinguish them from what we would otherwise get (perhaps, possibly latency?). The third case, instead, is interesting and deals with the DNS serving to users the IP addresses of transparent HTTP and TLS proxies. To make this test case more similar to what it was in Python, and considering that LTE uses many resolvers, here I have chosen to use DNS spoofing, which may or may not be the best choice for LTE in the long term. Yet, since the objective currently is to be able to check v0.4 against webconnectivityqa and the A/B comparison and the focus to LTE will come at a later stage, this seems good enough for now.
- Loading branch information
1 parent
f374d21
commit a379ecd
Showing
6 changed files
with
207 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package webconnectivityqa | ||
|
||
import ( | ||
"github.com/ooni/netem" | ||
"github.com/ooni/probe-cli/v3/internal/netemx" | ||
) | ||
|
||
// dnsHijackingToProxyWithHTTPURL is the case where an ISP rule forces clients to always | ||
// use an explicity passthrough proxy for a given domain. | ||
func dnsHijackingToProxyWithHTTPURL() *TestCase { | ||
// TODO(bassosimone): it's debateable whether this case is actually WAI but the | ||
// transparent TLS proxy really makes our analysis a bit more complex | ||
return &TestCase{ | ||
Name: "dnsHijackingToProxyWithHTTPURL", | ||
Flags: TestCaseFlagNoLTE, // BUG: LTE thinks the DNS is consistent | ||
Input: "http://www.example.com/", | ||
Configure: func(env *netemx.QAEnv) { | ||
|
||
// add DPI rule to force all the cleartext DNS queries to | ||
// point the client to used the ISPProxyAddress | ||
env.DPIEngine().AddRule(&netem.DPISpoofDNSResponse{ | ||
Addresses: []string{netemx.ISPProxyAddress}, | ||
Logger: env.Logger(), | ||
Domain: "www.example.com", | ||
}) | ||
|
||
}, | ||
ExpectErr: false, | ||
ExpectTestKeys: &testKeys{ | ||
DNSConsistency: "inconsistent", | ||
BodyLengthMatch: true, | ||
BodyProportion: 1, | ||
StatusCodeMatch: true, | ||
HeadersMatch: true, | ||
TitleMatch: true, | ||
XStatus: 2, // StatusSuccessCleartext | ||
XDNSFlags: 0, | ||
XBlockingFlags: 32, // analysisFlagSuccess | ||
Accessible: true, | ||
Blocking: false, | ||
}, | ||
} | ||
} | ||
|
||
// dnsHijackingToProxyWithHTTPSURL is the case where an ISP rule forces clients to always | ||
// use an explicity passthrough proxy for a given domain. | ||
func dnsHijackingToProxyWithHTTPSURL() *TestCase { | ||
// TODO(bassosimone): it's debateable whether this case is actually WAI but the | ||
// transparent TLS proxy really makes our analysis a bit more complex | ||
return &TestCase{ | ||
Name: "dnsHijackingToProxyWithHTTPSURL", | ||
Flags: TestCaseFlagNoLTE, // BUG: LTE thinks the DNS is consistent | ||
Input: "https://www.example.com/", | ||
Configure: func(env *netemx.QAEnv) { | ||
|
||
// add DPI rule to force all the cleartext DNS queries to | ||
// point the client to used the ISPProxyAddress | ||
env.DPIEngine().AddRule(&netem.DPISpoofDNSResponse{ | ||
Addresses: []string{netemx.ISPProxyAddress}, | ||
Logger: env.Logger(), | ||
Domain: "www.example.com", | ||
}) | ||
|
||
}, | ||
ExpectErr: false, | ||
ExpectTestKeys: &testKeys{ | ||
DNSConsistency: "inconsistent", | ||
BodyLengthMatch: true, | ||
BodyProportion: 1, | ||
StatusCodeMatch: true, | ||
HeadersMatch: true, | ||
TitleMatch: true, | ||
XStatus: 1, // StatusSuccessSecure | ||
XDNSFlags: 0, | ||
XBlockingFlags: 32, // analysisFlagSuccess | ||
Accessible: true, | ||
Blocking: false, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package netemx | ||
|
||
import ( | ||
"io" | ||
"net" | ||
"sync" | ||
|
||
"github.com/ooni/netem" | ||
"github.com/ooni/probe-cli/v3/internal/model" | ||
"github.com/ooni/probe-cli/v3/internal/netxlite" | ||
"github.com/ooni/probe-cli/v3/internal/runtimex" | ||
"github.com/ooni/probe-cli/v3/internal/testingx" | ||
) | ||
|
||
// NewTLSProxyServerFactory is a [NetStackServerFactory] for the TCP echo service. | ||
func NewTLSProxyServerFactory(logger model.Logger, ports ...uint16) NetStackServerFactory { | ||
return &tlsProxyServerFactory{ | ||
logger: logger, | ||
ports: ports, | ||
} | ||
} | ||
|
||
type tlsProxyServerFactory struct { | ||
logger model.Logger | ||
ports []uint16 | ||
} | ||
|
||
// MustNewServer implements NetStackServerFactory. | ||
func (f *tlsProxyServerFactory) MustNewServer(_ NetStackServerFactoryEnv, stack *netem.UNetStack) NetStackServer { | ||
return &tlsProxyServer{ | ||
closers: []io.Closer{}, | ||
logger: f.logger, | ||
mu: sync.Mutex{}, | ||
ports: f.ports, | ||
unet: stack, | ||
} | ||
} | ||
|
||
type tlsProxyServer struct { | ||
closers []io.Closer | ||
logger model.Logger | ||
mu sync.Mutex | ||
ports []uint16 | ||
unet *netem.UNetStack | ||
} | ||
|
||
// Close implements NetStackServer. | ||
func (srv *tlsProxyServer) Close() error { | ||
// "this method MUST be CONCURRENCY SAFE" | ||
defer srv.mu.Unlock() | ||
srv.mu.Lock() | ||
|
||
// make sure we close all the child listeners | ||
for _, closer := range srv.closers { | ||
_ = closer.Close() | ||
} | ||
|
||
// "this method MUST be IDEMPOTENT" | ||
srv.closers = []io.Closer{} | ||
|
||
return nil | ||
} | ||
|
||
// MustStart implements NetStackServer. | ||
func (srv *tlsProxyServer) MustStart() { | ||
// "this method MUST be CONCURRENCY SAFE" | ||
defer srv.mu.Unlock() | ||
srv.mu.Lock() | ||
|
||
// for each port of interest - note that here we panic liberally because we are | ||
// allowed to do so by the [NetStackServer] documentation. | ||
for _, port := range srv.ports { | ||
// create the endpoint address | ||
ipAddr := net.ParseIP(srv.unet.IPAddress()) | ||
runtimex.Assert(ipAddr != nil, "invalid IP address") | ||
epnt := &net.TCPAddr{IP: ipAddr, Port: int(port)} | ||
|
||
server := testingx.MustNewTLSSNIProxyEx( | ||
srv.logger, | ||
&netxlite.Netx{Underlying: &netxlite.NetemUnderlyingNetworkAdapter{UNet: srv.unet}}, | ||
epnt, | ||
srv.unet, | ||
) | ||
|
||
// track this server as something to close later | ||
srv.closers = append(srv.closers, server) | ||
} | ||
} |