| 180 | self.log("transports closed!", logging.DEBUG) |
| 181 | |
| 182 | async def open_connection(self, command: commands.OpenConnection) -> None: |
| 183 | if not command.connection.address: |
| 184 | self.log(f"Cannot open connection, no hostname given.") |
| 185 | await self.server_event( |
| 186 | events.OpenConnectionCompleted( |
| 187 | command, f"Cannot open connection, no hostname given." |
| 188 | ) |
| 189 | ) |
| 190 | return |
| 191 | |
| 192 | hook_data = server_hooks.ServerConnectionHookData( |
| 193 | client=self.client, server=command.connection |
| 194 | ) |
| 195 | await self.handle_hook(server_hooks.ServerConnectHook(hook_data)) |
| 196 | if err := command.connection.error: |
| 197 | self.log( |
| 198 | f"server connection to {human.format_address(command.connection.address)} killed before connect: {err}" |
| 199 | ) |
| 200 | await self.handle_hook(server_hooks.ServerConnectErrorHook(hook_data)) |
| 201 | await self.server_event( |
| 202 | events.OpenConnectionCompleted(command, f"Connection killed: {err}") |
| 203 | ) |
| 204 | return |
| 205 | |
| 206 | async with self.max_conns[command.connection.address]: |
| 207 | reader: asyncio.StreamReader | mitmproxy_rs.Stream |
| 208 | writer: asyncio.StreamWriter | mitmproxy_rs.Stream |
| 209 | try: |
| 210 | command.connection.timestamp_start = time.time() |
| 211 | if command.connection.transport_protocol == "tcp": |
| 212 | reader, writer = await asyncio.open_connection( |
| 213 | *command.connection.address, |
| 214 | local_addr=command.connection.sockname, |
| 215 | ) |
| 216 | elif command.connection.transport_protocol == "udp": |
| 217 | reader = writer = await mitmproxy_rs.udp.open_udp_connection( |
| 218 | *command.connection.address, |
| 219 | local_addr=command.connection.sockname, |
| 220 | ) |
| 221 | else: |
| 222 | raise AssertionError(command.connection.transport_protocol) |
| 223 | except (OSError, asyncio.CancelledError) as e: |
| 224 | err = str(e) |
| 225 | if not err: # str(CancelledError()) returns empty string. |
| 226 | err = "connection cancelled" |
| 227 | self.log(f"error establishing server connection: {err}") |
| 228 | command.connection.error = err |
| 229 | await self.handle_hook(server_hooks.ServerConnectErrorHook(hook_data)) |
| 230 | await self.server_event(events.OpenConnectionCompleted(command, err)) |
| 231 | if isinstance(e, asyncio.CancelledError): |
| 232 | # From https://docs.python.org/3/library/asyncio-exceptions.html#asyncio.CancelledError: |
| 233 | # > In almost all situations the exception must be re-raised. |
| 234 | # It is not really defined what almost means here, but we play safe. |
| 235 | raise |
| 236 | else: |
| 237 | if command.connection.transport_protocol == "tcp": |
| 238 | # TODO: Rename to `timestamp_setup` and make it agnostic for both TCP (SYN/ACK) and UDP (DNS resl.) |
| 239 | command.connection.timestamp_tcp_setup = time.time() |