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
net/http: unable to use getpeername to authenticate Unix socket requests #16385
Comments
There are many issues with exposing the underlying socket, which is why we haven't done so yet. What are you trying to do? (instead of stating your problem, it seems you're asking for a specific solution?) |
I like to authenticate local Unix connections inside the HTTP request handler ServeHTTP() with https://golang.org/pkg/syscall/#GetsockoptUcred and security context (#16374). I'm currently porting some parts of a Python application to Go. Specifically a HTTP forwarder that accepts connections on a Unix socket file, authenticate the request with peer credentials and security context of the connection and then forwards the HTTP request to an upstream service. It was very easy to write the Unix socket listener and HTTP forwarder with Go -- until I hit this road block. |
Did you consider writing a |
Yes, I also looked into I'm not a Go expert. How would a custom |
I'm not sure what you want, but perhaps
FWIW, the implementation of socket type and its methods varies between platforms, but in general you need to make a named socket if you want to know its near and far endpoint names even in the case of wildcard names. |
@mikioh: the far end name does not matter (and most likely it's not even bound on Linux), what matters are the credentials of the process on the far end. The actual issue is that there is no easy way of bubbling up this information from - say - an |
If you wrote your own net.Listener wrapper it could return your own net.Conn implementation that embeds the actual net.Conn but overrides the RemoteAddr method, and your implementation could return not just the remote socket name but also the credentials. So I don't think anything has to go into net/http to make this possible. Of course, it could be made easier, but I think we'd need to figure out how widespread the need for this is. |
This is waiting on a concrete proposal at this point. |
Timed out in state WaitingForInfo. Closing. (I am just a bot, though. Please speak up if this is a mistake or you have the requested information.) |
Sorry @gopherbot, this is still waiting on a concrete proposal. |
Please answer these questions before submitting your issue. Thanks!
go version
)?go version go1.6.2 linux/amd64
go env
)?Fedora 24 X86_64
Go doesn't let me access the file descriptor of the connection socket in net.http.HandlerFunc's ServeHTTP() function. While I agree that users should not mess with the file descriptor when it is under control of a HTTP library, it also prevents other use cases. I have written a HTTP server that listens on a Unix domain socket file. Unix sockets are local sockets that have some interesting properties. For example they allow to get the pid, uid, gid and security context (SELinux label) of the peer. This feature can be used for authentication and authorization (GetsockoptUcred syscall interface missing GetsockoptUcred #3836, x/sys/unix: GetsockoptPeerSec support #16374).
With Go 1.6 neither http.ResponseWriter nor http.Request have a public field or func that let me access the connection object, file or file descriptor. The connection is contained within the package internal http.conn struct. I also looked into Go 1.7 RC. Request got a context, but I don't see how that might solve the problem at hand.
Some mailing list posts suggest to use http.Server's ConnState hook to track connections in a map. For IPv4 and IPv6 connection it is possible to map conn.RemoteAddr to conn and then use http.Request.RemoteAddr to retrieve the connection. After all the combination of (src ip, src port, dest ip, dest port) is a unique identifier for TCP over IP. However that is not true for AF_UNIX / SOCK_STREAM. Unix socket's don't implement getpeername(). For a UnixListener the RemoteAddr of a http.Request is always the string '@'. net.Conn and http.Request don't share any other field that could be used as a common identifier.
Eventually I worked around the problem with http.Hijack(). This is a rather ugly solution because I have to roll my own response handling. It also prevents HTTP 1/1 persistent connections. https://github.com/tiran/custodia_goforwarder/blob/master/custodia_goforwarder.go#L95
Please provide a better and simpler way to access the file descriptor.
The text was updated successfully, but these errors were encountered: