Ist it possible to check the peer address before accepting a TCP connection?
I wrote a simple Perl server that listens on a TCP port/socket, accepting connections.
Now I wonder:
When wanting to implement address-based access control, is it possible to check the address of the peer requesting a connection before accepting it?
If possible I could reject the connection request (I hope) instead of accepting the connection and the immediately closing it again.
The TCP/IP connection is established by the kernel and then your application gets to work with the connection.
The only way to filter/prevent unneeded connections is by using a kernel firewall. You’ve not specified your OS, but in Linux that’ll be iptables/nftables.
I don’t claim any expertise in Perl – but I suspect it is not possible. For controlling access to a server I would restrict (in order of preference):
- By interface / bind address
- By kernel firewall (iptables, nftables, eBPF)
- By TCP wrappers or host config
Given that the facility to restrict by host config does not currently exist, apparently choosing this as the starting point seems unusual.
Assuming that 1 and 2 above are not an option, then I would suggest using TCP wrappers from your Perl code. This should get you up and running with minimal code changes while leveraging a flexible, standard and robust mechanism for network access control. See also https://metacpan.org/pod/Net::TCPwrappers
I believe its also possible to apply tcp-wrappers by tweaking the LD_LIBRARY_PATH at runtime (i.e. without any code changes) but couldn’t find reference to this in a quick Google search.
Not really an answer, but a few pointers too long for comments:
On MacOS X man accept
says:
One can obtain user connection request data without confirming the connection by issuing a recvmsg(2) call with an msg_iovlen of 0 and a non-zero msg_controllen, or by issuing a getsockopt(2) request. Similarly, one can provide user connection rejection information by issuing a
sendmsg(2) call with providing only the control information, or by calling setsockopt(2).
(emphasis mine)
Can’t find any more details in man recvmsg
, man getsockopt
or man tcp
on that topic though.
On Debian, man accept
says:
In order to be notified of incoming connections on a socket, you can use select(2), poll(2), or epoll(7). A readable event will be delivered when a new connection is attempted and you may then call accept() to get a socket for that connection. Alternatively, you can
set the socket to deliver SIGIO when activity occurs on a socket; see socket(7) for details.
IMHO the only one in there which may be able to deliver more info would be epoll
.
But even if you can get actually the info, I’m not quite sure how you would reject the connection if you don’t like it.
You’re probably better off doing the filtering at the network stack/firewall level (iptables and friends).
Transmission control protocol is not used for Access control.
I advise you to check TLS https://en.m.wikipedia.org/wiki/Transport_Layer_Security
Besides, have a look to netfilter firewall input hooks. You can drop and reject unwanted peers.