Search code examples
clinuxnetwork-programmingicmpraw-sockets

Linux, setsockopt ICMP_FILTER option


I'm interested in filtering ICMP packets. More precisely I open a raw socket

int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)

and I'm interested to send PING_ECHO and to receive PING_ECHOREPLY packets. I'm using respectively sendto and recvfrom function. So far, so good.

I would like to filter the received icmp packets using setsockopt with ICMP_FILTER option, which can be find in man raw. However they are a bit cryptic to me:

ICMP_FILTER

Enable a special filter for raw sockets bound to the IPPROTO_ICMP protocol. The value has a bit set for each ICMP message type which should be filtered out. The default is to filter no ICMP messages.

How can I set these bits safely? I cannot find documentation online. Looking around I've found that there is a struct icmp_filter defined in linux/icmp.h header. However I do not know if it is the correct header to include.


Solution

  • icmp.h is indeed the correct header. You can examine the source code of icmp.h for this stuff:

    #define ICMP_ECHOREPLY      0   /* Echo Reply           */
    #define ICMP_DEST_UNREACH   3   /* Destination Unreachable  */
    #define ICMP_SOURCE_QUENCH  4   /* Source Quench        */
    #define ICMP_REDIRECT       5   /* Redirect (change route)  */
    #define ICMP_ECHO       8   /* Echo Request         */
    #define ICMP_TIME_EXCEEDED  11  /* Time Exceeded        */
    #define ICMP_PARAMETERPROB  12  /* Parameter Problem        */
    #define ICMP_TIMESTAMP      13  /* Timestamp Request        */
    #define ICMP_TIMESTAMPREPLY 14  /* Timestamp Reply      */
    #define ICMP_INFO_REQUEST   15  /* Information Request      */
    #define ICMP_INFO_REPLY     16  /* Information Reply        */
    #define ICMP_ADDRESS        17  /* Address Mask Request     */
    #define ICMP_ADDRESSREPLY   18  /* Address Mask Reply       */
    

    These are the bit definitions (it says so explicitly in man icmp), so you need to set the corresponding bit for the option you want, usually using a shift, using | to or multiple bits together. You define your filter object, then set the data field

    struct icmp_filter my_filter = {
      1U << ICMP_ECHO | 
      1U << ICMP_TIME_EXCEEDED ...
    };
    

    etc, and pass it to the socket options using setsockopt.