How to check client IP before connection in FreeRTOS+TCP server (RA6M3)

Hello,

I am using FreeRTOS+TCP on a Renesas RA6M3 device.
The device acts as a server, and I want to allow connections only from specific client IP addresses.

Currently, I check the client IP address after FreeRTOS_accept(), and if the IP is not allowed, I call FreeRTOS_closesocket() to disconnect.
However, with this approach, the client briefly sees the connection as established before being disconnected.

My question is:
Is there a way to check the client’s IP address before the connection is fully established, and reject connections from disallowed IPs?

Thank you for your advice.

What you are looking for is some sort of firewall. I do not think we have firewall in FreeRTOS-Plus-TCP. @htibosch Can you confirm?

I agree with you, it is not elegant to pick up the phone and smash it down within a second. It is better to reply with a tcpTCP_FLAG_RST packet before the negotiation starts.

In FreeRTOS_TCP_State_Handling_IPv[46].c you find:

 FreeRTOS_Socket_t * prvHandleListen_IPV[46]( FreeRTOS_Socket_t * pxSocket,
                                              NetworkBufferDescriptor_t * pxNetworkBuffer )
 {
     ...
+    if( IP_Address_allowed() == pdFALSE )
+    {
+        prvTCPSendReset( pxNetworkBuffer );
+    }
     if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog )
     {
         prvTCPSendReset( pxNetworkBuffer );
     }
     ...
 }

I would recommend to check here if the source IP-address is allowed to login.
The call to prvTCPSendReset() makes sure that the peer will receive a proper RST packet. The peer will see an errno of ECONNREFUSED, and it will not try it again.

We could introduce a new application hook:

BaseType_t IP_Address_allowed( IPv46_Address_t pxAddress, uint16_t usPort );

We could choose to give each TCP socket this new hook, or extend it to become a global function:

BaseType_t IP_Address_allowed(
    IPv46_Address_t * pxSourceAddress,
    uint16_t usSourcePort,
    IPv46_Address_t * pxTargetAddress,
    uint16_t usTargetPort );

I would check the full address: IP and port number.

What are your thoughts?

In some of my projects, I filter on the source port number: only source port 2403 was allowed. In that way I made sure that a single device could only connect one time.

Thank you for the advice.
This looks like exactly what I needed.
I will implement it and run some tests.
I may ask again if I have further questions.

Hi @Taki, please check this branch.

It expects you to define in your FreeRTOSIPConfig.h :

#define ipconfigHAS_TCP_ACCEPT_HOOK    ipconfigENABLE

And in my main() I defined this test:

#if ipconfigIS_ENABLED ( ipconfigHAS_TCP_ACCEPT_HOOK )
BaseType_t xApplicationTCPAcceptHook(
    const IPv46_Address_t * pxSourceAddress,
    uint16_t usSourcePort,
    const IPv46_Address_t * pxTargetAddress,
    uint16_t usTargetPort )
{
    uint16_t usPort = FreeRTOS_ntohs( usSourcePort );
    BaseType_t xAllowed = ( usPort & 1 ) == 1;
    FreeRTOS_printf( ( "%s connection from port %u\n",
        xAllowed ? "Allowing" : "Denying", usPort ) );
    return xAllowed;
}
#endif

It only allow connections when the source port number is odd (1, 3, 5, etc).

In refused connections, a RST flag will be sent.

Thank you for the update and for providing the sample for the TCP Accept Hook.

I have reviewed the method using ipconfigHAS_TCP_ACCEPT_HOOK.
I will consider this approach together with the previously suggested method of checking the IP address inside prvHandleListen_IPV4() before deciding which one to adopt.

I plan to test both options and evaluate which implementation fits my requirements best.
Thank you again for sharing this information.

The previous sample you provided worked correctly when I implemented and tested it.
Regarding the new TCP Accept Hook approach, I would appreciate your advice on whether it would be preferable to use this new method instead.

Hi @taki ,

I have reviewed the method using ipconfigHAS_TCP_ACCEPT_HOOK.

I prefer the second method because :

  • The code size does not increase unless the new property is used
  • You can handle the question within a single handler xApplicationTCPAcceptHook, for both IPv4 and IPv6 (if enabled)
  • The implementation doesn’t interfere much with the existing code

Or in short: I think it is a good implementation of a simple firewall.

Thank you for your reply.
I will try implementing the second method as well and verify its behavior.
I will close this question for now.