def __init__(self): self.flows = [] self.layers = [ lambda ctx: layers.modes.HttpProxy(ctx), lambda ctx: layers.HttpLayer(ctx, HTTPMode.regular), lambda ctx: layers.TCPLayer(ctx), ]
def next_layer(nextlayer: layer.NextLayer): ctx.log(f"{nextlayer.context=}\n" f"{nextlayer.data_client()[:70]=}\n" f"{nextlayer.data_server()[:70]=}\n") if nextlayer.context.server.address == ("example.com", 443): nextlayer.context.server.address = ("example.com", 80) # We are disabling ALPN negotiation as our curl client would otherwise agree on HTTP/2, # which our example server here does not accept for plaintext connections. nextlayer.context.client.alpn = b"" # We know all layers that come next: First negotiate TLS with the client, then do simple TCP passthrough. # Setting only one layer here would also work, in that case next_layer would be called again after TLS establishment. nextlayer.layer = layers.ClientTLSLayer(nextlayer.context) nextlayer.layer.child_layer = layers.TCPLayer(nextlayer.context)
def _next_layer(self, context: context.Context, data_client: bytes, data_server: bytes) -> Optional[layer.Layer]: if len(context.layers) == 0: return self.make_top_layer(context) if len(data_client) < 3 and not data_server: return None # not enough data yet to make a decision # helper function to quickly check if the existing layer stack matches a particular configuration. def s(*layers): return stack_match(context, layers) # 1. check for --ignore/--allow ignore = self.ignore_connection(context.server.address, data_client) if ignore is True: return layers.TCPLayer(context, ignore=True) if ignore is None: return None # 2. Check for TLS client_tls = is_tls_record_magic(data_client) if client_tls: # client tls usually requires a server tls layer as parent layer, except: # - a secure web proxy doesn't have a server part. # - reverse proxy mode manages this itself. if (s(modes.HttpProxy) or s(modes.ReverseProxy) or s(modes.ReverseProxy, layers.ServerTLSLayer)): return layers.ClientTLSLayer(context) else: # We already assign the next layer here os that ServerTLSLayer # knows that it can safely wait for a ClientHello. ret = layers.ServerTLSLayer(context) ret.child_layer = layers.ClientTLSLayer(context) return ret # 3. Setup the HTTP layer for a regular HTTP proxy or an upstream proxy. if (s(modes.HttpProxy) or # or a "Secure Web Proxy", see https://www.chromium.org/developers/design-documents/secure-web-proxy s(modes.HttpProxy, layers.ClientTLSLayer)): if ctx.options.mode == "regular": return layers.HttpLayer(context, HTTPMode.regular) else: return layers.HttpLayer(context, HTTPMode.upstream) # 4. Check for --tcp if any( (context.server.address and rex.search(context.server.address[0])) or (context.client.sni and rex.search(context.client.sni)) for rex in self.tcp_hosts): return layers.TCPLayer(context) # 5. Check for raw tcp mode. very_likely_http = (context.client.alpn and context.client.alpn in HTTP_ALPNS) probably_no_http = not very_likely_http and ( not data_client[:3].isalpha( ) # the first three bytes should be the HTTP verb, so A-Za-z is expected. or data_server # a server greeting would be uncharacteristic. ) if ctx.options.rawtcp and probably_no_http: return layers.TCPLayer(context) # 6. Assume HTTP by default. return layers.HttpLayer(context, HTTPMode.transparent)
def _next_layer(self, context: context.Context, data_client: bytes, data_server: bytes) -> Optional[layer.Layer]: if len(context.layers) == 0: return self.make_top_layer(context) if len(data_client) < 3 and not data_server: return None client_tls = is_tls_record_magic(data_client) def s(*layers): return stack_match(context, layers) top_layer = context.layers[-1] # 1. check for --ignore/--allow ignore = self.ignore_connection(context.server.address, data_client) if ignore is True: return layers.TCPLayer(context, ignore=True) if ignore is None: return None # 2. Check for TLS if client_tls: # client tls requires a server tls layer as parent layer # reverse proxy mode manages this itself. # a secure web proxy doesn't have a server part. if isinstance(top_layer, layers.ServerTLSLayer) or s( modes.ReverseProxy) or s(modes.HttpProxy): return layers.ClientTLSLayer(context) else: return layers.ServerTLSLayer(context) # 3. Setup the HTTP layer for a regular HTTP proxy or an upstream proxy. if any([ s(modes.HttpProxy), # or a "Secure Web Proxy", see https://www.chromium.org/developers/design-documents/secure-web-proxy s(modes.HttpProxy, layers.ClientTLSLayer), ]): if ctx.options.mode == "regular": return layers.HttpLayer(context, HTTPMode.regular) else: return layers.HttpLayer(context, HTTPMode.upstream) # 4. Check for --tcp if any( (context.server.address and rex.search(context.server.address[0])) or (context.client.sni and rex.search(context.client.sni)) for rex in self.tcp_hosts): return layers.TCPLayer(context) # 5. Check for raw tcp mode. very_likely_http = (context.client.alpn and context.client.alpn in HTTP_ALPNS) probably_no_http = not very_likely_http and ( not data_client[:3].isalpha( ) # the first three bytes should be the HTTP verb, so A-Za-z is expected. or data_server # a server greeting would be uncharacteristic. ) if ctx.options.rawtcp and probably_no_http: return layers.TCPLayer(context) # 6. Assume HTTP by default. return layers.HttpLayer(context, HTTPMode.transparent)