4

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.

1
  • 2
    Even if you can get the address, there seems to be no portable way to reject() the connection. Related: stackoverflow.com/questions/16590847/… Commented Nov 13, 2023 at 18:07

4 Answers 4

6

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.

3
  • My idea was: You listen to a socket, and the socket signals that there is a connection request, basically un-blocking accept. So my idea was whether I could query the pending connection requests and somehow deny the request. However, as it seems, it's not possible under application control, but only from the kernel firewall (netfolter). Commented Nov 13, 2023 at 10:25
  • 1
    I deliberately did not specify the variant of UNIX, because I would have preferred a solution that works on "any UNIX" (even though I'm using Linux)). Commented Nov 13, 2023 at 10:26
  • 1
    @U.Windl I haven't yet tried it myself, but by a combination of using Wireshark to monitor a connection while stepping a client and server program, so can pause execution between listen and accept calls, you could see at which point the network stack in the Kernel has completed the TCP 3-Way Handshake Process. Commented Nov 13, 2023 at 18:05
5

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).

2
  • The getsockopt is an interesting idea: I found IP_MSFILTER (since Linux 2.4.22 / 2.5.68) that is intended for multicast filtering (RFC 3376: "Version 3 of IGMP adds support for "source filtering", that is, the ability for a system to report interest in receiving packets only from specific source addresses, or from all but specific source addresses, sent to a particular multicast address."). Would be interesting trying to mis-use that for non-multicast. Commented Nov 14, 2023 at 13:31
  • Also interesting could be ` IP_PKTINFO` (since Linux 2.2) "that supplies some information about the incoming packet.". Commented Nov 14, 2023 at 13:39
1

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):

  1. By interface / bind address
  2. By kernel firewall (iptables, nftables, eBPF)
  3. 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.

1
  • 1
    As I understand it, libwrap also accepts the connections first, just to close them immediately if access is denied. So probably the only way (except from dealing with Linux raw sockets) is to use the kernel firewall to block access before accepting the connections. Commented Nov 13, 2023 at 13:44
-1

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.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.