Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify proxy modes, introduce UDP protocol detection. #5556

Merged
merged 13 commits into from Aug 30, 2022

Conversation

meitinger
Copy link
Contributor

@meitinger meitinger commented Aug 26, 2022

Description

Contains changes for #5535.

  1. Removed transparent mode in UDP. The way transparent mode for UDP is implemented is far from ideal: It's only supported on Linux, requires sudo for the whole process, prevents full coverage of udp.py and is not even used/enabled.
    Together with add Windows OS proxy mode #5543, I'll plan to do re-add transparent UDP mode later in a similar fashion, i.e. a separate process, asking for sudo if necessary, setting everything up for the user. In the meantime, udp.py has now full coverage.
  2. Updated AsyncioServerInstance and ProxyMode to support both protocols for one ProxyMode. In the process, the need for additional ServerInstances disappeared, so ProxyModes now fully describe proto, port and layer.
  3. Removed make_connection_id. Since we don't know on what layer we'll detect what protocol, we can't use the DNS-ID in ServerManager connection-ID trick anymore - same as goes for QUIC, if we don't want to alter SendData and DataReceived (see Add QUIC support. #5435 (review)).
  4. Changed the proxy mode syntax to what was discussed in New Proxy Modes #5535. Also DNS has now --mode reverse:dns://8.8.8.8 if used with an upstream, --mode dns will launch a local-resolve server.
  5. Adjusted DNS layer to match packets by their ID. As mentioned above, this was previously done through ServerManager connection-IDs, but if we detect DNS higher up, or in the future use some transparent mode, this can't be done this way anymore.
  6. Copied and adjusted TCP layer decisions for UDP.

@meitinger
Copy link
Contributor Author

@mhils: Before I'm adjusting and (re-)adding tests, could you maybe have a quick look as to whether the way the "new" modes are implemented is something you'd sign off on? Thanks :)

Copy link
Member

@mhils mhils left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks great, mostly dumb clarification questions below! Please don't read any judgement/sentiment into these comments, reviewing on mobile is tricky and they might be stupid questions. 😅

@@ -0,0 +1,173 @@
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for moving this out of mode_specs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python and it's cyclic dependencies 😅
But I'll restore the 1:1 ServerInstances, which will move the layers-dependency to mode_servers.py again, so I can move mode.py back into mode_specs.py.

setup.cfg Show resolved Hide resolved
@@ -40,40 +39,37 @@ class DNSLayer(layer.Layer):
Layer that handles resolving DNS queries.
"""

flow: dns.DNSFlow
flows: dict[int, dns.DNSFlow]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How/why do we end up having multiple DNS flows here now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the history here is: We had that before, in the DNS draft. Then we moved the ID into the connection_id of proxyserver (i.e. essentially the dict). However, if we want to do protocol detection and fancy transparent stuff, DNS might not be at the top layer, so the layer itself will have to do it.

It's the same with QUIC. We've talked about connection migration (which currently also uses connection_id in proxyserver) and the change of SendData and DataReceived to include the remote address, that ideally should not happen. So there we will also need a layer that does the routing instead, keeping the old SendData and not using custom connection_id.

And that's actually a good thing: Having uniform connection id's is the only way to reliably do inject_udp in the future.

raise RuntimeError("Proxy modes are frozen.")


class AsyncioProxyMode(ProxyMode, metaclass=ABCMeta):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this complicates things more than it helps. Maybe we can move description into ProxyMode itself and then keep the layer information as part of individual server instance subclasses? That avoids the special-casing in ServerInstance.make, keeps all modes as immediate subclasses of ProxyMode, retains a dumb 1-1 mapping between modes and instances, and avoids any circular spec -> layer -> spec dependencies. This may entirely be "code I wrote myself is easier to understand" bias, so feel free to go ahead with this approach if you feel it's more straightforward. Just a subjective impression. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's just my code-compressing attitude, but you're right. Having 1:1 ServerInstances removes all the if TYPE_CHECKING stuff, so I'll undo the changes.

@mhils mhils mentioned this pull request Aug 27, 2022
@mhils
Copy link
Member

mhils commented Aug 27, 2022

Looks fantastic now! 🍰 😃

@meitinger meitinger marked this pull request as ready for review August 28, 2022 17:31
@meitinger
Copy link
Contributor Author

@mhils This should be ready now :) I've updated the docs as well, that's why I didn't want to merge before you've had the chance to look over the wording. Once we support QUIC and HTTP3, I think it's time to add a table as in #5535.

Copy link
Member

@mhils mhils left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! 🍰

In case you want to inspect raw traffic only for some hosts and HTTP for
others, have a look at the [tcp_hosts]({{< relref "concepts-options" >}}#tcp_hosts)
and [udp_hosts]({{< relref "concepts-options" >}}#udp_hosts) options.
- Say you want to capture DNS traffic to Google's Public DNS server? Then you
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this it probably would make sense to make the default port scheme-specific for reverse proxy mode. DNS should be on 53 by default. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, here's the PR: #5563 :)

@mhils mhils merged commit 1706a9b into mitmproxy:main Aug 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants