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