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 */
|