LCOV - code coverage report
Current view: top level - util/net - fd_ip4.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 48 70 68.6 %
Date: 2024-11-13 11:58:15 Functions: 9 1736 0.5 %

          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           0 : #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             : #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             : #define FD_IP4_HDR_PROTOCOL_TCP  ((uchar) 6) /* The IP4 packet encapsulates an TCP  packet */
      19    44587325 : #define FD_IP4_HDR_PROTOCOL_UDP  ((uchar)17) /* The IP4 packet encapsulates an UDP  packet */
      20             : 
      21             : #define FD_IP4_OPT_RA  ((uchar)148) /* This option is a router alert option */
      22             : #define FD_IP4_OPT_EOL ((uchar)0)   /* This is the end of the options list */
      23             : 
      24             : /* All of the below are in network byte order */
      25          42 : #define IP4_PRIVATE_RANGE1_START_NET FD_IP4_ADDR( 10,   0,   0,   0)
      26          36 : #define IP4_PRIVATE_RANGE1_END_NET   FD_IP4_ADDR( 10, 255, 255, 255)
      27          30 : #define IP4_PRIVATE_RANGE2_START_NET FD_IP4_ADDR(172,  16,   0,   0)
      28          18 : #define IP4_PRIVATE_RANGE2_END_NET   FD_IP4_ADDR(172,  31, 255, 255)
      29          21 : #define IP4_PRIVATE_RANGE3_START_NET FD_IP4_ADDR(192, 168,   0,   0)
      30           9 : #define IP4_PRIVATE_RANGE3_END_NET   FD_IP4_ADDR(192, 168, 255, 255)
      31             : 
      32          12 : #define IP4_LOOPBACK_START_NET       FD_IP4_ADDR(127,   0,   0,   0)
      33           3 : #define IP4_LOOPBACK_END_NET         FD_IP4_ADDR(127, 255, 255, 255)
      34             : 
      35             : union fd_ip4_hdr {
      36             :   struct {
      37             :     uchar  verihl;       /* 4 lsb: IP version (==4), assumes little endian */
      38             :                          /* 4 msb: Header length in words (>=5) */
      39             :     uchar  tos;          /* Type of service */
      40             :     ushort net_tot_len;  /* Frag size in bytes, incl ip hdr, net order */
      41             :     ushort net_id;       /* Frag id, unique from sender for long enough, net order */
      42             :     ushort net_frag_off; /* Frag off (dbl words)+status (top 3 bits), net order */
      43             :     uchar  ttl;          /* Frag time to live */
      44             :     uchar  protocol;     /* Type of payload */
      45             :     ushort check;        /* Header checksum ("invariant" order) */
      46             :     uchar  saddr_c[4];   /* Address of sender, technically net order but all APIs below work with this directly */
      47             :     uchar  daddr_c[4];   /* Address of destination, technically net order but all APIs below work with this directly */
      48             :     /* Up to 40 bytes of options here */
      49             :   };
      50             : };
      51             : 
      52             : typedef union fd_ip4_hdr fd_ip4_hdr_t;
      53             : 
      54             : /* FD_IP4_GET_VERSION obtains the version from the supplied fd_ip4_hdr */
      55             : 
      56    18218092 : #define FD_IP4_GET_VERSION(ip4) ((uchar)( ( (uint)(ip4).verihl >> 4u ) & 0x0fu ))
      57             : 
      58             : /* FD_IP4_SET_VERSION sets the version in the supplied fd_ip4_hdr */
      59             : 
      60             : #define FD_IP4_SET_VERSION(ip4,value) (ip4).verihl = ((uchar)( \
      61             :       ( (uint)(ip4).verihl & 0x0fu ) | ( ( (uint)(value) & 0x0fu ) << 4u ) ))
      62             : 
      63             : /* FD_IP4_GET_IHL retrieves the IHL field from the supplied fd_ip4_hdr */
      64             : 
      65    18218092 : #define FD_IP4_GET_IHL(ip4) ((uchar)( (uint)(ip4).verihl & 0x0fu ))
      66             : 
      67             : /* FD_IP4_GET_LEN retrieves and adjusts the IHL field from the supplied fd_ip4_hdr */
      68             : 
      69    18218092 : #define FD_IP4_GET_LEN(ip4) ( FD_IP4_GET_IHL(ip4) * 4u )
      70             : 
      71             : /* FD_IP4_SET_IHL sets the IHL field in the supplied fd_ip4_hdr */
      72             : 
      73             : #define FD_IP4_SET_IHL(ip4,value) ((uchar)( \
      74             :       ( (uint)(ip4).verihl & 0xf0u ) | ( (uint)(value) & 0x0fu ) ))
      75             : 
      76             : /* FD_IP4_VERIHL combines the supplied IHL and VERSION into a single verihl fields */
      77             : 
      78    69751136 : #define FD_IP4_VERIHL(version,ihl) ((uchar)( ( ((uint)(version) & 0x0fu) << 4u ) | \
      79    69751136 :                                                ((uint)(ihl)     & 0x0fu) ))
      80             : 
      81             : /* FD_IP4_ADDR constructs an IP4 address from the 4-tuple x.y.z.w.
      82             :    Assumes x,y,z,w are all integers in [0,255]. */
      83             : 
      84      300207 : #define FD_IP4_ADDR(x,y,z,w) (((uint)(x)) | (((uint)(y)) << 8) | (((uint)(z)) << 16) | (((uint)(w)) << 24))
      85             : 
      86             : /* FD_IP4_ADDR_FMT / FD_IP4_ADDR_FMT_ARGS are used to pretty print a
      87             :    ip4 address by a printf style formatter.  a must be safe against
      88             :    multiple evaluation.  Example usage:
      89             : 
      90             :      fd_ip4_hdr_t * hdr = ...;
      91             :      FD_LOG_NOTICE(( "DST MAC: " FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( hdr->daddr ) */
      92             : 
      93             : #define FD_IP4_ADDR_FMT         "%u.%u.%u.%u"
      94             : #define FD_IP4_ADDR_FMT_ARGS(a) ((a) & 255U),(((a)>>8) & 255U),(((a)>>16) & 255U),((a)>>24)
      95             : 
      96             : /* FIXME: CONSIDER AN OVERALL HEADER PRETTY PRINTER? */
      97             : 
      98             : FD_PROTOTYPES_BEGIN
      99             : 
     100             : /* fd_ip4_addr_is_{mcast,bcast} returns 1 if the ipaddr is {multicast
     101             :    (in [224-239].y.z.w),global broadcast (255.255.255.255)} and 0
     102             :    otherwise. fd_ip4_hdr_net_frag_off_is_unfragmented returns 1 if the
     103             :    net_frag_off field of the ip4 header indicates the encapsulated
     104             :    packet is not fragmented (i.e. entirely containing the IP4 packet)
     105             :    and 0 otherwise (i.e. fragmented into multiple IP4 packets). */
     106             : 
     107           9 : FD_FN_CONST static inline int fd_ip4_addr_is_mcast( uint addr ) { return (((uchar)addr)>>4)==(uchar)0xe; }
     108           9 : FD_FN_CONST static inline int fd_ip4_addr_is_bcast( uint addr ) { return addr==~0U;                      }
     109             : 
     110             : FD_FN_CONST static inline int
     111           0 : fd_ip4_hdr_net_frag_off_is_unfragmented( ushort net_frag_off ) { /* net order */
     112           0 :   return !(((uint)net_frag_off) & 0xff3fU); /* ff3f is fd_ushort_bswap( NET_IP_HDR_FRAG_OFF_MASK | NET_IP_HDR_FRAG_OFF_MF ) */
     113           0 : }
     114             : 
     115             : /* fd_ip4_hdr_check is used for hdr check field computation and
     116             :    validation.  hdr points to the first byte a memory region containing
     117             :    an ip4 header and any options that might follow it.  If the header
     118             :    has checksum (check==0), this returns the value to use for check.  If
     119             :    hdr has a checksum (check!=0), this returns 0 if hdr has a valid
     120             :    checksum (or non-zero if not).  This is mostly for use in cases where
     121             :    the overhead doesn't matter or when the hardware sending/receiving
     122             :    the packet doesn't do various checksum offload computations. */
     123             : 
     124             : FD_FN_PURE static inline ushort
     125           0 : fd_ip4_hdr_check( void const * vp_hdr ) {
     126           0 :   uchar * cp = (uchar*)vp_hdr;
     127             : 
     128           0 :   uint n = ( (*cp) & 0x0fu );
     129             : 
     130             :   /* optimizes the first 5 by unrolling */
     131           0 :   if( n < 5 ) __builtin_unreachable();
     132             : 
     133           0 :   ulong        c = 0UL;
     134           0 :   for( uint i=0U; i<n; i++ ) {
     135           0 :     uint u;
     136             : 
     137             :     /* the compiler elides the copy in practice */
     138           0 :     memcpy( &u, cp + i*4, 4 );
     139           0 :     c += (ulong)u;
     140           0 :   }
     141             : 
     142           0 :   c  = ( c>>32            ) +
     143           0 :        ((c>>16) & 0xffffUL) +
     144           0 :        ( c      & 0xffffUL);
     145           0 :   c  = ( c>>16            ) +
     146           0 :        ( c      & 0xffffUL);
     147           0 :   c += ( c>>16            );
     148             : 
     149           0 :   return (ushort)~c;
     150           0 : }
     151             : 
     152             : /* fd_ip4_hdr_check_fast is the same as the above but assumes that the
     153             :    header has no options (i.e. ihl==5) */
     154             : 
     155             : FD_FN_PURE static inline ushort
     156    19423514 : fd_ip4_hdr_check_fast( void const * vp_hdr ) {
     157    19423514 :   uchar * cp = (uchar*)vp_hdr;
     158             : 
     159    19423514 :   uint n = ( (*cp) & 0x0fu );
     160             : 
     161             :   /* branches aren't taken don't use branch table entries */
     162    19423514 :   if( FD_UNLIKELY( n != 5 ) ) return fd_ip4_hdr_check(vp_hdr);
     163             : 
     164             :   /* the compiler knows n here and completely unrolls the loop */
     165    19423514 :   ulong c = 0UL;
     166   116541084 :   for( uint i=0U; i<n; i++ ) {
     167    97117570 :     uint u;
     168             : 
     169             :     /* the compiler elides the copy in practice */
     170    97117570 :     memcpy( &u, cp + i*4, 4 );
     171    97117570 :     c += (ulong)u;
     172    97117570 :   }
     173             : 
     174    19423514 :   c  = ( c>>32            ) +
     175    19423514 :        ((c>>16) & 0xffffUL) +
     176    19423514 :        ( c      & 0xffffUL);
     177    19423514 :   c  = ( c>>16            ) +
     178    19423514 :        ( c      & 0xffffUL);
     179    19423514 :   c += ( c>>16            );
     180             : 
     181    19423514 :   return (ushort)~c;
     182    19423514 : }
     183             : 
     184             : /* fd_cstr_to_ip4_addr parses an IPv4 address matching format
     185             :    %u.%u.%u.%u  On success stores address to out and returns 1. On fail
     186             :    returns 0.  The given address is returned in host byte order such
     187             :    that "1.0.0.0" => 0x01000000. */
     188             : 
     189             : int
     190             : fd_cstr_to_ip4_addr( char const * s,
     191             :                      uint *       addr );
     192             : 
     193             : /* fd_ip4_addr_is_public checks if the given IPv4 address is a public address.
     194             :    assumed to be in net byte order.  */
     195             :   
     196             : FD_FN_CONST static inline int 
     197          42 : fd_ip4_addr_is_public( uint addr ) {
     198          42 :   uint addr_host = fd_uint_bswap( addr );
     199          42 :   return !((addr_host >= fd_uint_bswap( IP4_PRIVATE_RANGE1_START_NET ) && addr_host <= fd_uint_bswap( IP4_PRIVATE_RANGE1_END_NET )) ||
     200          42 :            (addr_host >= fd_uint_bswap( IP4_PRIVATE_RANGE2_START_NET ) && addr_host <= fd_uint_bswap( IP4_PRIVATE_RANGE2_END_NET )) ||
     201          42 :            (addr_host >= fd_uint_bswap( IP4_PRIVATE_RANGE3_START_NET ) && addr_host <= fd_uint_bswap( IP4_PRIVATE_RANGE3_END_NET )) ||
     202          42 :            (addr_host >= fd_uint_bswap( IP4_LOOPBACK_START_NET )       && addr_host <= fd_uint_bswap( IP4_LOOPBACK_END_NET )));
     203          42 : }
     204             : 
     205             : /* fd_ip4_hdr_bswap reverses the endianness of all fields in the IPv4
     206             :    header. */
     207             : 
     208             : static inline void
     209    37643694 : fd_ip4_hdr_bswap( fd_ip4_hdr_t * hdr ) {
     210    37643694 :   hdr->net_tot_len  = (ushort)fd_ushort_bswap( hdr->net_tot_len  );
     211    37643694 :   hdr->net_id       = (ushort)fd_ushort_bswap( hdr->net_id       );
     212    37643694 :   hdr->net_frag_off = (ushort)fd_ushort_bswap( hdr->net_frag_off );
     213    37643694 :   hdr->check        = (ushort)fd_ushort_bswap( hdr->check        );
     214    37643694 : }
     215             : 
     216             : FD_PROTOTYPES_END
     217             : 
     218             : #endif /* HEADER_fd_src_util_net_fd_ip4_h */

Generated by: LCOV version 1.14