Fasthttp: Modifying ListenAndServe

Created on 19 Feb 2019  路  7Comments  路  Source: valyala/fasthttp

We're looking into fasthttp as a drop-in replacement for the standard Golang listener. We do a lot of preprocessing when a connection is first opened up and before we ever attempt to parse the HTTP request. I was wondering if there is an existing way to hook in this type of functionality without needing to fork the code?

Example: In ListenAndServe(), we find that dumb devices sometimes send malformed HTTP (specifically missing the "host" header). We then parse the low level networking tables to determine the original destination. This happens before we attempt to parse the request.

Example 2: In ListenAndServeTLS(), we inspect the CLIENTHELLO message in the initial TLS handshake before we allow the request to continue.

Most helpful comment

@WinstonPrivacy if you need low-level support for WebSockets you can use https://github.com/fasthttp/fastws

All 7 comments

(2) is definitely out of (fast)HTTP domain. You have an option of GetCertificate in https://godoc.org/crypto/tls#Config. But we also intercept raw TLS in a custom TCPListener/TCPConn wrapper -- simple FSM is all you need to track conn state if that's your desire.

For (1) missing header doesn't stop HTTP parser: you could move Host routing to a middleware, plain and simple. Though, we do parse raw HTTP as well -- for this purpose I contributed https://godoc.org/github.com/valyala/fasthttp#RequestHeader.RawHeaders

I've been studying the code and the server/workerpool implementation looks incredible. We're running on a 2 core ARM64 board with little RAM, so this seems like it could be a major improvement over our existing implementation.

It will require a lot of work to completely migrate from net.http to fasthttp. I'm not sure it's even possible. One potentially difficult use case would be proxying streaming video or large downloads... does fasthttp buffer everything in memory? Is there example code for connection forwarding, such as might be used with websockets, for instance?

Maybe we could start by forking server.go and wrap our original ServeHttp functions. Would Server.serveConn() (server.go:1791) be the correct place for this?

I believe you don't need to fork anything.

Apologies in advance for the noob questions. I'm still trying to wrap my head around fasthttp. My questions in particular are related to a proxy-like implementation, not a webserver.

  1. It is unclear to me how hijacking would fit into my use cases, especially as according to the docs, the hijack handler is called after the response is returned to the caller. For instance, in the event of a CONNECT request, we would reply with an HTTP 1.1/200 OK message and then open up a tunnel. That makes sense.

However, in the case of a transparent proxy, we would open up a connection, repeat the request to the destination server and then pipe the server's response back (which could potentially go on for quite a while). We would not send our own response back to the client and doing so would break the protocol (again, we're a transparent proxy). Is this case handled?

  1. Is there an example of a proxy server that someone has already implemented using FastHTTP? This would be exceptionally helpful.

  2. I did not quite understand your final comment about dealing with the lower layers. As a security device, we are in an unusual position where the application layer needs to inspect certain details of the lower level protocols (the TLS handshake in this case) prior to forwarding the request. I understand that this (probably) isn't currently implemented in fasthttp, but it seems like Server.serveConn() would be a natural place for this (even better if we could provide our own handler - then we might not have to fork at all). Or am I thinking about it wrong?

My bad, Hijack was mentioned in answer to your mention of Websockets, but I missed the point that you want to forward it, not process.

I'm not sure fasthttp facilities are needed for something as simple as proxy, you're basically working below HTTP layer. Here's a fairly comprehensive library for SOCKS https://github.com/armon/go-socks5 that you could enhance with sync.Pools where necessary.

If I were you TBH I'd even go deeper and build an L7 firewall, not proxy. F5 and Cisco have these problems solved decades ago. Maybe even contribute to http://l7-filter.clearos.com?

And re (3): I am working on security software and I _did_ implement TLS intercept and inspection on a custom net.Conn. My first comment in this thread elaborates it a little.


But that's a digression. Back to your question, server is currently able to stream data, but fasthttp.Client is not. See this PR https://github.com/valyala/fasthttp/pull/150 and maybe even take over?

It's not so much a matter of implementing TLS interception, proxy networks and inspection as we've already done that and have had it working for quite some time now. We're interested in fasthttp as an improvement on parts of our current work, but I think perhaps only the server implementation would be useful for us (as you say, most of the work happens below the http level, though in our case, not all).

I7 looks interesting though outdated. Not sure how they would classify encrypted traffic but that's not what we're after, so it's more of a curiosity.

@WinstonPrivacy if you need low-level support for WebSockets you can use https://github.com/fasthttp/fastws

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Fenny picture Fenny  路  4Comments

facundomedica picture facundomedica  路  4Comments

Fenny picture Fenny  路  3Comments

mayocream picture mayocream  路  3Comments

danilobuiatti picture danilobuiatti  路  3Comments