(self)
| 143 | self.addr_remote = resolve_address('www.python.org.', 80) |
| 144 | |
| 145 | def testConnectTimeout(self): |
| 146 | # Testing connect timeout is tricky: we need to have IP connectivity |
| 147 | # to a host that silently drops our packets. We can't simulate this |
| 148 | # from Python because it's a function of the underlying TCP/IP stack. |
| 149 | # So, the following port on the pythontest.net host has been defined: |
| 150 | blackhole = resolve_address('pythontest.net', 56666) |
| 151 | |
| 152 | # Blackhole has been configured to silently drop any incoming packets. |
| 153 | # No RSTs (for TCP) or ICMP UNREACH (for UDP/ICMP) will be sent back |
| 154 | # to hosts that attempt to connect to this address: which is exactly |
| 155 | # what we need to confidently test connect timeout. |
| 156 | |
| 157 | # However, we want to prevent false positives. It's not unreasonable |
| 158 | # to expect certain hosts may not be able to reach the blackhole, due |
| 159 | # to firewalling or general network configuration. In order to improve |
| 160 | # our confidence in testing the blackhole, a corresponding 'whitehole' |
| 161 | # has also been set up using one port higher: |
| 162 | whitehole = resolve_address('pythontest.net', 56667) |
| 163 | |
| 164 | # This address has been configured to immediately drop any incoming |
| 165 | # packets as well, but it does it respectfully with regards to the |
| 166 | # incoming protocol. RSTs are sent for TCP packets, and ICMP UNREACH |
| 167 | # is sent for UDP/ICMP packets. This means our attempts to connect to |
| 168 | # it should be met immediately with ECONNREFUSED. The test case has |
| 169 | # been structured around this premise: if we get an ECONNREFUSED from |
| 170 | # the whitehole, we proceed with testing connect timeout against the |
| 171 | # blackhole. If we don't, we skip the test (with a message about not |
| 172 | # getting the required RST from the whitehole within the required |
| 173 | # timeframe). |
| 174 | |
| 175 | # For the records, the whitehole/blackhole configuration has been set |
| 176 | # up using the 'iptables' firewall, using the following rules: |
| 177 | # |
| 178 | # -A INPUT -p tcp --destination-port 56666 -j DROP |
| 179 | # -A INPUT -p udp --destination-port 56666 -j DROP |
| 180 | # -A INPUT -p tcp --destination-port 56667 -j REJECT |
| 181 | # -A INPUT -p udp --destination-port 56667 -j REJECT |
| 182 | # |
| 183 | # See https://github.com/python/psf-salt/blob/main/pillar/base/firewall/snakebite.sls |
| 184 | # for the current configuration. |
| 185 | |
| 186 | skip = True |
| 187 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: |
| 188 | try: |
| 189 | timeout = support.LOOPBACK_TIMEOUT |
| 190 | sock.settimeout(timeout) |
| 191 | sock.connect((whitehole)) |
| 192 | except TimeoutError: |
| 193 | pass |
| 194 | except OSError as err: |
| 195 | if err.errno == errno.ECONNREFUSED: |
| 196 | skip = False |
| 197 | |
| 198 | if skip: |
| 199 | self.skipTest( |
| 200 | "We didn't receive a connection reset (RST) packet from " |
| 201 | "{}:{} within {} seconds, so we're unable to test connect " |
| 202 | "timeout against the corresponding {}:{} (which is " |
nothing calls this directly
no test coverage detected