1# 2# Copyright 2018 - The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from acts import asserts 17from acts import base_test 18from acts.test_decorators import test_tracker_info 19from acts.test_utils.net.net_test_utils import start_tcpdump 20from acts.test_utils.net.net_test_utils import stop_tcpdump 21from acts.test_utils.wifi import wifi_test_utils as wutils 22from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest 23 24 25from scapy.all import IP 26from scapy.all import TCP 27from scapy.all import UDP 28from scapy.all import Raw 29from scapy.all import rdpcap 30from scapy.all import Scapy_Exception 31 32 33class ProxyTest(WifiBaseTest): 34 """ Network proxy tests """ 35 36 def setup_class(self): 37 """ Setup devices for tests and unpack params """ 38 self.dut = self.android_devices[0] 39 req_params = ("proxy_pac", "proxy_server", 40 "proxy_port", "bypass_host", "non_bypass_host") 41 opt_params = ["reference_networks", "wpa_networks",] 42 self.unpack_userparams(req_param_names=req_params, 43 opt_param_names=opt_params) 44 if "AccessPoint" in self.user_params: 45 self.legacy_configure_ap_and_start(wpa_network=True) 46 asserts.assert_true(len(self.reference_networks) > 0, 47 "Need at least one reference network with psk.") 48 self.wifi_network = self.reference_networks[0]["2g"] 49 wutils.wifi_test_device_init(self.dut) 50 wutils.wifi_toggle_state(self.dut, True) 51 wutils.wifi_connect(self.dut, self.wifi_network) 52 self.tcpdump_pid = None 53 self.proxy_port = int(self.proxy_port) 54 55 def teardown_test(self): 56 self.dut.droid.connectivityResetGlobalProxy() 57 global_proxy = self.dut.droid.connectivityGetGlobalProxy() 58 if global_proxy: 59 self.log.error("Failed to reset global proxy settings") 60 61 def teardown_class(self): 62 wutils.reset_wifi(self.dut) 63 64 def on_fail(self, test_name, begin_time): 65 self.dut.take_bug_report(test_name, begin_time) 66 67 """ Helper methods """ 68 69 def _verify_http_request(self, ad): 70 """ Send http requests to hosts 71 72 Steps: 73 1. Send http requests to hosts 74 a. Host that is bypassed by proxy server 75 b. Host that goes through proxy server 76 2. Verify that both return valid responses 77 78 Args: 79 1. ad: dut to run http requests 80 """ 81 for host in [self.bypass_host, self.non_bypass_host]: 82 host = "https://%s" % host 83 result = ad.droid.httpRequestString(host) 84 asserts.assert_true(result, "Http request failed for %s" % host) 85 86 def _verify_proxy_server(self, pcap_file, bypass_host, hostname): 87 """ Verify that http requests are going through proxy server 88 89 Args: 90 1. tcpdump: pcap file 91 2. bypass_host: boolean value if the request goes through proxy 92 3. hostname: hostname requested 93 94 Returns: 95 True/False if the bypass condition met 96 """ 97 self.log.info("Checking proxy server for query to: %s" % hostname) 98 try: 99 packets = rdpcap(pcap_file) 100 except Scapy_Exception: 101 asserts.fail("Not a valid pcap file") 102 103 dns_query = False 104 http_query = False 105 for pkt in packets: 106 summary = "%s" % pkt.summary() 107 if UDP in pkt and pkt[UDP].dport == 53 and hostname in summary: 108 dns_query = True 109 break 110 if TCP in pkt and pkt[TCP].dport == self.proxy_port and Raw in pkt\ 111 and hostname in str(pkt[Raw]): 112 http_query = True 113 114 self.log.info("Bypass hostname set to: %s" % bypass_host) 115 self.log.info("Found DNS query for host: %s" % dns_query) 116 self.log.info("Found HTTP query for host: %s" % http_query) 117 if bypass_host and http_query and not dns_query or \ 118 not bypass_host and not http_query and dns_query: 119 return False 120 return True 121 122 def _test_proxy(self): 123 """ Test pac piroxy and manual proxy settings 124 125 Steps: 126 1. Start tcpdump 127 2. Run http requests 128 3. Stop tcpdump 129 4. Verify the packets from tcpdump have valid queries 130 """ 131 132 # start tcpdump on the device 133 self.tcpdump_pid = start_tcpdump(self.dut, self.test_name) 134 135 # verify http requests 136 self._verify_http_request(self.dut) 137 138 # stop tcpdump on the device 139 pcap_file = stop_tcpdump(self.dut, self.tcpdump_pid, self.test_name) 140 141 # verify proxy server 142 result = self._verify_proxy_server(pcap_file, True, self.bypass_host) 143 asserts.assert_true(result, "Proxy failed for %s" % self.bypass_host) 144 result = self._verify_proxy_server(pcap_file, False, self.non_bypass_host) 145 asserts.assert_true(result, "Proxy failed for %s" % self.non_bypass_host) 146 147 """ Test Cases """ 148 149 @test_tracker_info(uuid="16881315-1a50-48ce-bd36-7b0d2f21b734") 150 def test_pac_proxy_over_wifi(self): 151 """ Test proxy with auto config over wifi 152 153 Steps: 154 1. Connect to a wifi network 155 2. Set a global proxy with auto config 156 3. Do a http request on the hostnames 157 4. Verify that no DNS packets seen for non bypassed hostnames 158 5. Verify that DNS packets seen for bypassed hostnames 159 """ 160 # set global pac proxy 161 self.log.info("Setting global proxy to: %s" % self.proxy_pac) 162 self.dut.droid.connectivitySetGlobalPacProxy(self.proxy_pac) 163 global_proxy = self.dut.droid.connectivityGetGlobalProxy() 164 asserts.assert_true(global_proxy['PacUrl'] == self.proxy_pac, 165 "Failed to set pac proxy") 166 167 # test proxy 168 self._test_proxy() 169 170 @test_tracker_info(uuid="4d3361f6-866d-423c-9ed7-5a6943575fe9") 171 def test_manual_proxy_over_wifi(self): 172 """ Test manual proxy over wifi 173 174 Steps: 175 1. Connect to a wifi network 176 2. Set a global manual proxy with proxy server, port & bypass URLs 177 3. Do a http request on the hostnames 178 4. Verify that no DNS packets are seen for non bypassed hostnames 179 5. Verify that DNS packets seen for bypassed hostnames 180 """ 181 # set global manual proxy 182 self.log.info("Setting global proxy to: %s %s %s" % 183 (self.proxy_server, self.proxy_port, self.bypass_host)) 184 self.dut.droid.connectivitySetGlobalProxy(self.proxy_server, 185 self.proxy_port, 186 self.bypass_host) 187 global_proxy = self.dut.droid.connectivityGetGlobalProxy() 188 asserts.assert_true(global_proxy['Hostname'] == self.proxy_server, 189 "Failed to set manual proxy") 190 191 # test proxy 192 self._test_proxy() 193