LCOV - code coverage report
Current view: top level - util/net - fd_ip4.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 101 108 93.5 %
Date: 2026-09-17 04:28:31 Functions: 19 2328 0.8 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_util_net_fd_ip4_h
       2             : #define HEADER_fd_src_util_net_fd_ip4_h
       3             : 
       4             : #include "../bits/fd_bits.h"
       5             : 
       6             : /* FIXME: IP4 CRASH COURSE HERE */
       7             : 
       8             : #define FD_IP4_HDR_TOS_PREC_INTERNETCONTROL ((uchar)0xc0) /* This packet is should have Internet control type of service */
       9             : 
      10             : #define FD_IP4_HDR_FRAG_OFF_RF   ((ushort)0x8000) /* (in host byte order) Mask for the frag off reserved bit */
      11         210 : #define FD_IP4_HDR_FRAG_OFF_DF   ((ushort)0x4000) /* (in host byte order) Mask for the frag off don't frag bit */
      12             : #define FD_IP4_HDR_FRAG_OFF_MF   ((ushort)0x2000) /* (in host byte order) Mask for the frag off more frags bit */
      13             : #define FD_IP4_HDR_FRAG_OFF_MASK ((ushort)0x1fff) /* (in host byte order) Mask for the frag off offset bits */
      14             : 
      15             : #define FD_IP4_HDR_PROTOCOL_IP4  ((uchar) 0) /* The IP4 packet encapsulates an IP4  packet */
      16           0 : #define FD_IP4_HDR_PROTOCOL_ICMP ((uchar) 1) /* The IP4 packet encapsulates an ICMP packet */
      17             : #define FD_IP4_HDR_PROTOCOL_IGMP ((uchar) 2) /* The IP4 packet encapsulates an IGMP packet */
      18           0 : #define FD_IP4_HDR_PROTOCOL_TCP  ((uchar) 6) /* The IP4 packet encapsulates an TCP  packet */
      19   127743635 : #define FD_IP4_HDR_PROTOCOL_UDP  ((uchar)17) /* The IP4 packet encapsulates an UDP  packet */
      20         258 : #define FD_IP4_HDR_PROTOCOL_GRE  ((uchar)47) /* The IP4 packet encapsulates a GRE  packet */
      21             : 
      22             : #define FD_IP4_OPT_RA  ((uchar)148) /* This option is a router alert option */
      23             : #define FD_IP4_OPT_EOL ((uchar)0)   /* This is the end of the options list */
      24             : 
      25             : /* All of the below are in network byte order */
      26             : 
      27             : /* RFC 791 - "This network" */
      28         183 : #define IP4_THIS_NET_START_NET       FD_IP4_ADDR(  0,   0,   0,   0)
      29         183 : #define IP4_THIS_NET_END_NET         FD_IP4_ADDR(  0, 255, 255, 255)
      30             : 
      31             : /* RFC 1112 - Reserved/future use */
      32         111 : #define IP4_RESERVED_START_NET       FD_IP4_ADDR(240,   0,   0,   0)
      33          12 : #define IP4_RESERVED_END_NET         FD_IP4_ADDR(255, 255, 255, 254)
      34             : 
      35             : /* RFC 1122 - Loopback */
      36          60 : #define IP4_LOOPBACK_START_NET       FD_IP4_ADDR(127,   0,   0,   0)
      37          33 : #define IP4_LOOPBACK_END_NET         FD_IP4_ADDR(127, 255, 255, 255)
      38             : 
      39             : /* RFC 1918 - Private-use */
      40         162 : #define IP4_PRIVATE_RANGE1_START_NET FD_IP4_ADDR( 10,   0,   0,   0)
      41         141 : #define IP4_PRIVATE_RANGE1_END_NET   FD_IP4_ADDR( 10, 255, 255, 255)
      42         150 : #define IP4_PRIVATE_RANGE2_START_NET FD_IP4_ADDR(172,  16,   0,   0)
      43          99 : #define IP4_PRIVATE_RANGE2_END_NET   FD_IP4_ADDR(172,  31, 255, 255)
      44         141 : #define IP4_PRIVATE_RANGE3_START_NET FD_IP4_ADDR(192, 168,   0,   0)
      45          54 : #define IP4_PRIVATE_RANGE3_END_NET   FD_IP4_ADDR(192, 168, 255, 255)
      46             : 
      47             : /* RFC 2544 - Benchmarking */
      48          84 : #define IP4_BENCH_START_NET          FD_IP4_ADDR(198,  18,   0,   0)
      49          21 : #define IP4_BENCH_END_NET            FD_IP4_ADDR(198,  19, 255, 255)
      50             : 
      51             : /* RFC 3927 - Link-local */
      52         129 : #define IP4_LINK_LOCAL_START_NET     FD_IP4_ADDR(169, 254,   0,   0)
      53          87 : #define IP4_LINK_LOCAL_END_NET       FD_IP4_ADDR(169, 254, 255, 255)
      54             : 
      55             : /* RFC 5737 - Documentation */
      56         102 : #define IP4_TEST_NET_1_START_NET     FD_IP4_ADDR(192,   0,   2,   0)
      57          57 : #define IP4_TEST_NET_1_END_NET       FD_IP4_ADDR(192,   0,   2, 255)
      58          96 : #define IP4_TEST_NET_2_START_NET     FD_IP4_ADDR(198,  51, 100,   0)
      59          24 : #define IP4_TEST_NET_2_END_NET       FD_IP4_ADDR(198,  51, 100, 255)
      60          90 : #define IP4_TEST_NET_3_START_NET     FD_IP4_ADDR(203,   0, 113,   0)
      61          18 : #define IP4_TEST_NET_3_END_NET       FD_IP4_ADDR(203,   0, 113, 255)
      62             : 
      63             : /* RFC 6598 - Shared address (CGNAT) */
      64         120 : #define IP4_CGNAT_START_NET          FD_IP4_ADDR(100,  64,   0,   0)
      65          96 : #define IP4_CGNAT_END_NET            FD_IP4_ADDR(100, 127, 255, 255)
      66             : 
      67             : /* RFC 6890 - IETF protocol assignments
      68             :    Note: 192.0.0.9 (PCP anycast, RFC 7723) and 192.0.0.10 (TURN anycast,
      69             :    RFC 8155) are globally reachable but intentionally not carved out; no
      70             :    validator will serve snapshots or publish gossip from these addresses. */
      71          78 : #define IP4_PROTO_ASSIGN_START_NET   FD_IP4_ADDR(192,   0,   0,   0)
      72          45 : #define IP4_PROTO_ASSIGN_END_NET     FD_IP4_ADDR(192,   0,   0, 255)
      73             : 
      74             : /* RFC 7526 - 6to4 relay anycast (deprecated) */
      75          69 : #define IP4_6TO4_RELAY_START_NET     FD_IP4_ADDR(192,  88,  99,   0)
      76          27 : #define IP4_6TO4_RELAY_END_NET       FD_IP4_ADDR(192,  88,  99, 255)
      77             : 
      78             : union fd_ip4_hdr {
      79             :   struct {
      80             :     uchar  verihl;       /* 4 msb: IP version (==4), assumes little endian */
      81             :                          /* 4 lsb: Header length in words (>=5) */
      82             :     uchar  tos;          /* Type of service */
      83             :     ushort net_tot_len;  /* Frag size in bytes, incl ip hdr, net order */
      84             :     ushort net_id;       /* Frag id, unique from sender for long enough, net order */
      85             :     ushort net_frag_off; /* Frag off (dbl words)+status (top 3 bits), net order */
      86             :     uchar  ttl;          /* Frag time to live */
      87             :     uchar  protocol;     /* Type of payload */
      88             :     ushort check;        /* Header checksum ("invariant" order) */
      89             :     union __attribute__((packed)) {
      90             :       uchar saddr_c[4];  /* Address of sender, technically net order but all APIs below work with this directly */
      91             :       uint  saddr;
      92             :     };
      93             :     union __attribute__((packed)) {
      94             :       uchar daddr_c[4];  /* Address of destination, technically net order but all APIs below work with this directly */
      95             :       uint  daddr;
      96             :     };
      97             :     /* Up to 40 bytes of options here */
      98             :   };
      99             : };
     100             : 
     101             : typedef union fd_ip4_hdr fd_ip4_hdr_t;
     102             : 
     103             : /* FD_IP4_GET_VERSION obtains the version from the supplied fd_ip4_hdr */
     104             : 
     105     7650223 : #define FD_IP4_GET_VERSION(ip4) ((uchar)( ( (uint)(ip4).verihl >> 4u ) & 0x0fu ))
     106             : 
     107             : /* FD_IP4_SET_VERSION sets the version in the supplied fd_ip4_hdr */
     108             : 
     109             : #define FD_IP4_SET_VERSION(ip4,value) (ip4).verihl = ((uchar)( \
     110             :       ( (uint)(ip4).verihl & 0x0fu ) | ( ( (uint)(value) & 0x0fu ) << 4u ) ))
     111             : 
     112             : /* FD_IP4_GET_IHL retrieves the IHL field from the supplied fd_ip4_hdr */
     113             : 
     114     7650622 : #define FD_IP4_GET_IHL(ip4) ((uchar)( (uint)(ip4).verihl & 0x0fu ))
     115             : 
     116             : /* FD_IP4_GET_LEN retrieves and adjusts the IHL field from the supplied fd_ip4_hdr */
     117             : 
     118     7650622 : #define FD_IP4_GET_LEN(ip4) ( FD_IP4_GET_IHL(ip4) * 4u )
     119             : 
     120             : /* FD_IP4_SET_IHL sets the IHL field in the supplied fd_ip4_hdr */
     121             : 
     122             : #define FD_IP4_SET_IHL(ip4,value) (ip4).verihl = ((uchar)( \
     123             :       ( (uint)(ip4).verihl & 0xf0u ) | ( (uint)(value) & 0x0fu ) ))
     124             : 
     125             : /* FD_IP4_VERIHL combines the supplied IHL and VERSION into a single verihl fields */
     126             : 
     127   247837011 : #define FD_IP4_VERIHL(version,ihl) ((uchar)( ( ((uint)(version) & 0x0fu) << 4u ) | \
     128   247837011 :                                                ((uint)(ihl)     & 0x0fu) ))
     129             : 
     130             : /* FD_IP4_ADDR constructs an IP4 address from the 4-tuple x.y.z.w.
     131             :    Assumes x,y,z,w are all integers in [0,255]. */
     132             : 
     133   240802478 : #define FD_IP4_ADDR(x,y,z,w) (((uint)(x)) | (((uint)(y)) << 8) | (((uint)(z)) << 16) | (((uint)(w)) << 24))
     134             : 
     135             : /* FD_IP4_ADDR_FMT / FD_IP4_ADDR_FMT_ARGS are used to pretty print a
     136             :    ip4 address by a printf style formatter.  a must be safe against
     137             :    multiple evaluation.  Example usage:
     138             : 
     139             :      fd_ip4_hdr_t * hdr = ...;
     140             :      FD_LOG_NOTICE(( "DST MAC: " FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( hdr->daddr ) */
     141             : 
     142           0 : #define FD_IP4_ADDR_FMT         "%u.%u.%u.%u"
     143           0 : #define FD_IP4_ADDR_FMT_ARGS(a) ((a) & 255U),(((a)>>8) & 255U),(((a)>>16) & 255U),((a)>>24)
     144             : 
     145             : /* FIXME: CONSIDER AN OVERALL HEADER PRETTY PRINTER? */
     146             : 
     147             : FD_PROTOTYPES_BEGIN
     148             : 
     149             : /* fd_ip4_addr_is_{mcast,bcast,loopback} returns 1 if the ipaddr is
     150             :    {multicast (in [224-239].y.z.w), global broadcast
     151             :    (255.255.255.255), loopback (127.y.z.w)} and 0 otherwise.
     152             :    fd_ip4_hdr_net_frag_off_is_unfragmented returns 1 if the
     153             :    net_frag_off field of the ip4 header indicates the encapsulated
     154             :    packet is not fragmented (i.e. entirely containing the IP4 packet)
     155             :    and 0 otherwise (i.e. fragmented into multiple IP4 packets). */
     156             : 
     157         126 : FD_FN_CONST static inline int fd_ip4_addr_is_mcast( uint addr ) { return (((uchar)addr)>>4)==(uchar)0xe; }
     158          21 : FD_FN_CONST static inline int fd_ip4_addr_is_bcast( uint addr ) { return addr==~0U;                      }
     159          60 : FD_FN_CONST static inline int fd_ip4_addr_is_loopback( uint addr ) {
     160          60 :    return fd_uint_bswap( addr ) >= fd_uint_bswap( IP4_LOOPBACK_START_NET ) &&
     161          60 :           fd_uint_bswap( addr ) <= fd_uint_bswap( IP4_LOOPBACK_END_NET   );
     162          60 :  }
     163             : 
     164             : FD_FN_CONST static inline int
     165           0 : fd_ip4_hdr_net_frag_off_is_unfragmented( ushort net_frag_off ) { /* net order */
     166           0 :   return !(((uint)net_frag_off) & 0xff3fU); /* ff3f is fd_ushort_bswap( NET_IP_HDR_FRAG_OFF_MASK | NET_IP_HDR_FRAG_OFF_MF ) */
     167           0 : }
     168             : 
     169             : /* fd_ip4_hdr_check is used for hdr check field computation and
     170             :    validation.  hdr points to the first byte a memory region containing
     171             :    an ip4 header and any options that might follow it.  If the header
     172             :    has checksum (check==0), this returns the value to use for check.  If
     173             :    hdr has a checksum (check!=0), this returns 0 if hdr has a valid
     174             :    checksum (or non-zero if not).  This is mostly for use in cases where
     175             :    the overhead doesn't matter or when the hardware sending/receiving
     176             :    the packet doesn't do various checksum offload computations. */
     177             : 
     178             : FD_FN_PURE static inline ushort
     179         108 : fd_ip4_hdr_check( void const * vp_hdr ) {
     180         108 :   uchar * cp = (uchar*)vp_hdr;
     181             : 
     182         108 :   uint n = ( (*cp) & 0x0fu );
     183             : 
     184         108 :   ulong        c = 0UL;
     185         648 :   for( uint i=0U; i<n; i++ ) {
     186         540 :     uint u;
     187             : 
     188             :     /* the compiler elides the copy in practice */
     189         540 :     memcpy( &u, cp + i*4, 4 );
     190         540 :     c += (ulong)u;
     191         540 :   }
     192             : 
     193         108 :   c  = ( c>>32            ) +
     194         108 :        ((c>>16) & 0xffffUL) +
     195         108 :        ( c      & 0xffffUL);
     196         108 :   c  = ( c>>16            ) +
     197         108 :        ( c      & 0xffffUL);
     198         108 :   c += ( c>>16            );
     199             : 
     200         108 :   return (ushort)~c;
     201         108 : }
     202             : 
     203             : /* fd_ip4_hdr_check_fast is the same as the above but assumes that the
     204             :    header has no options (i.e. ihl==5) */
     205             : 
     206             : FD_FN_PURE static inline ushort
     207     7652395 : fd_ip4_hdr_check_fast( void const * vp_hdr ) {
     208     7652395 :   uchar * cp = (uchar*)vp_hdr;
     209             : 
     210     7652395 :   uint n = ( (*cp) & 0x0fu );
     211             : 
     212             :   /* branches aren't taken don't use branch table entries */
     213     7652395 :   if( FD_UNLIKELY( n != 5 ) ) return fd_ip4_hdr_check(vp_hdr);
     214             : 
     215             :   /* the compiler knows n here and completely unrolls the loop */
     216     7652395 :   ulong c = 0UL;
     217    45914370 :   for( uint i=0U; i<n; i++ ) {
     218    38261975 :     uint u;
     219             : 
     220             :     /* the compiler elides the copy in practice */
     221    38261975 :     memcpy( &u, cp + i*4, 4 );
     222    38261975 :     c += (ulong)u;
     223    38261975 :   }
     224             : 
     225     7652395 :   c  = ( c>>32            ) +
     226     7652395 :        ((c>>16) & 0xffffUL) +
     227     7652395 :        ( c      & 0xffffUL);
     228     7652395 :   c  = ( c>>16            ) +
     229     7652395 :        ( c      & 0xffffUL);
     230     7652395 :   c += ( c>>16            );
     231             : 
     232     7652395 :   return (ushort)~c;
     233     7652395 : }
     234             : 
     235             : /* fd_cstr_to_ip4_addr parses an IPv4 address matching format
     236             :    %u.%u.%u.%u  On success stores address to out and returns 1. On fail
     237             :    returns 0.  The given address is returned in network byte order such
     238             :    that "1.0.0.0" => 0x00000001. */
     239             : 
     240             : int
     241             : fd_cstr_to_ip4_addr( char const * s,
     242             :                      uint *       addr );
     243             : 
     244             : /* fd_ip4_addr_is_public checks if the given IPv4 address is a public address.
     245             :    assumed to be in net byte order.  */
     246             : 
     247             : FD_FN_CONST static inline int
     248         183 : fd_ip4_addr_is_public( uint addr ) {
     249         183 :   uint addr_host = fd_uint_bswap( addr );
     250         183 :   return !((addr_host >= fd_uint_bswap( IP4_THIS_NET_START_NET       ) && addr_host <= fd_uint_bswap( IP4_THIS_NET_END_NET       )) ||
     251         183 :            (addr_host >= fd_uint_bswap( IP4_PRIVATE_RANGE1_START_NET ) && addr_host <= fd_uint_bswap( IP4_PRIVATE_RANGE1_END_NET )) ||
     252         183 :            (addr_host >= fd_uint_bswap( IP4_PRIVATE_RANGE2_START_NET ) && addr_host <= fd_uint_bswap( IP4_PRIVATE_RANGE2_END_NET )) ||
     253         183 :            (addr_host >= fd_uint_bswap( IP4_PRIVATE_RANGE3_START_NET ) && addr_host <= fd_uint_bswap( IP4_PRIVATE_RANGE3_END_NET )) ||
     254         183 :            (addr_host >= fd_uint_bswap( IP4_LINK_LOCAL_START_NET     ) && addr_host <= fd_uint_bswap( IP4_LINK_LOCAL_END_NET     )) ||
     255         183 :            (addr_host >= fd_uint_bswap( IP4_CGNAT_START_NET          ) && addr_host <= fd_uint_bswap( IP4_CGNAT_END_NET          )) ||
     256         183 :            (addr_host >= fd_uint_bswap( IP4_RESERVED_START_NET       ) && addr_host <= fd_uint_bswap( IP4_RESERVED_END_NET       )) ||
     257         183 :            (addr_host >= fd_uint_bswap( IP4_TEST_NET_1_START_NET     ) && addr_host <= fd_uint_bswap( IP4_TEST_NET_1_END_NET     )) ||
     258         183 :            (addr_host >= fd_uint_bswap( IP4_TEST_NET_2_START_NET     ) && addr_host <= fd_uint_bswap( IP4_TEST_NET_2_END_NET     )) ||
     259         183 :            (addr_host >= fd_uint_bswap( IP4_TEST_NET_3_START_NET     ) && addr_host <= fd_uint_bswap( IP4_TEST_NET_3_END_NET     )) ||
     260         183 :            (addr_host >= fd_uint_bswap( IP4_BENCH_START_NET          ) && addr_host <= fd_uint_bswap( IP4_BENCH_END_NET          )) ||
     261         183 :            (addr_host >= fd_uint_bswap( IP4_PROTO_ASSIGN_START_NET   ) && addr_host <= fd_uint_bswap( IP4_PROTO_ASSIGN_END_NET   )) ||
     262         183 :            (addr_host >= fd_uint_bswap( IP4_6TO4_RELAY_START_NET     ) && addr_host <= fd_uint_bswap( IP4_6TO4_RELAY_END_NET     )) ||
     263         183 :            fd_ip4_addr_is_loopback( addr ));
     264         183 : }
     265             : 
     266             : /* fd_ip4_hdr_bswap reverses the endianness of all fields in the IPv4
     267             :    header. */
     268             : 
     269             : static inline void
     270    15300203 : fd_ip4_hdr_bswap( fd_ip4_hdr_t * hdr ) {
     271    15300203 :   hdr->net_tot_len  = (ushort)fd_ushort_bswap( hdr->net_tot_len  );
     272    15300203 :   hdr->net_id       = (ushort)fd_ushort_bswap( hdr->net_id       );
     273    15300203 :   hdr->net_frag_off = (ushort)fd_ushort_bswap( hdr->net_frag_off );
     274    15300203 :   hdr->check        = (ushort)fd_ushort_bswap( hdr->check        );
     275    15300203 : }
     276             : 
     277             : FD_PROTOTYPES_END
     278             : 
     279             : #endif /* HEADER_fd_src_util_net_fd_ip4_h */

Generated by: LCOV version 1.14