suricata
decode-ipv4.h
Go to the documentation of this file.
1 /* Copyright (C) 2007-2022 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  * \author Brian Rectanus <brectanu@gmail.com>
23  */
24 
25 #ifndef SURICATA_DECODE_IPV4_H
26 #define SURICATA_DECODE_IPV4_H
27 
28 #define IPV4_HEADER_LEN 20 /**< Header length */
29 #define IPV4_OPTMAX 40 /**< Max options length */
30 #define IPV4_MAXPACKET_LEN 65535 /**< Maximum packet size */
31 
32 /** IP Option Types */
33 #define IPV4_OPT_EOL 0x00 /**< Option: End of List */
34 #define IPV4_OPT_NOP 0x01 /**< Option: No op */
35 #define IPV4_OPT_RR 0x07 /**< Option: Record Route */
36 #define IPV4_OPT_QS 0x19 /**< Option: Quick Start */
37 #define IPV4_OPT_TS 0x44 /**< Option: Timestamp */
38 #define IPV4_OPT_SEC 0x82 /**< Option: Security */
39 #define IPV4_OPT_LSRR 0x83 /**< Option: Loose Source Route */
40 #define IPV4_OPT_ESEC 0x85 /**< Option: Extended Security */
41 #define IPV4_OPT_CIPSO 0x86 /**< Option: Commercial IP Security */
42 #define IPV4_OPT_SID 0x88 /**< Option: Stream Identifier */
43 #define IPV4_OPT_SSRR 0x89 /**< Option: Strict Source Route */
44 #define IPV4_OPT_RTRALT 0x94 /**< Option: Router Alert */
45 
46 /** IP Option Lengths (fixed) */
47 #define IPV4_OPT_SID_LEN 4 /**< SID Option Fixed Length */
48 #define IPV4_OPT_RTRALT_LEN 4 /**< RTRALT Option Fixed Length */
49 
50 /** IP Option Lengths (variable) */
51 #define IPV4_OPT_SEC_MIN 3 /**< SEC, ESEC Option Min Length */
52 #define IPV4_OPT_ROUTE_MIN 3 /**< RR, SRR, LTRR Option Min Length */
53 #define IPV4_OPT_QS_MIN 8 /**< QS Option Min Length */
54 #define IPV4_OPT_TS_MIN 5 /**< TS Option Min Length */
55 #define IPV4_OPT_CIPSO_MIN 10 /**< CIPSO Option Min Length */
56 
57 /** IP Option fields */
58 #define IPV4_OPTS ip4vars.ip_opts
59 #define IPV4_OPTS_CNT ip4vars.ip_opt_cnt
60 
61 typedef struct IPV4Opt_ {
62  /** \todo We may want to break type up into its 3 fields
63  * as the reassembler may want to know which options
64  * must be copied to each fragment.
65  */
66  uint8_t type; /**< option type */
67  uint8_t len; /**< option length (type+len+data) */
68  const uint8_t *data; /**< option data */
70 
71 typedef struct IPV4Hdr_
72 {
73  uint8_t ip_verhl; /**< version & header length */
74  uint8_t ip_tos; /**< type of service */
75  uint16_t ip_len; /**< length */
76  uint16_t ip_id; /**< id */
77  uint16_t ip_off; /**< frag offset */
78  uint8_t ip_ttl; /**< time to live */
79  uint8_t ip_proto; /**< protocol (tcp, udp, etc) */
80  uint16_t ip_csum; /**< checksum */
81  union {
82  struct {
83  struct in_addr ip_src;/**< source address */
84  struct in_addr ip_dst;/**< destination address */
86  uint16_t ip_addrs[4];
89 
90 
91 #define s_ip_src ip4_hdrun1.ip4_un1.ip_src
92 #define s_ip_dst ip4_hdrun1.ip4_un1.ip_dst
93 #define s_ip_addrs ip4_hdrun1.ip_addrs
94 
95 #define IPV4_GET_RAW_VER(ip4h) (((ip4h)->ip_verhl & 0xf0) >> 4)
96 #define IPV4_GET_RAW_HLEN(ip4h) ((ip4h)->ip_verhl & 0x0f)
97 #define IPV4_GET_RAW_IPTOS(ip4h) ((ip4h)->ip_tos)
98 #define IPV4_GET_RAW_IPLEN(ip4h) ((ip4h)->ip_len)
99 #define IPV4_GET_RAW_IPID(ip4h) ((ip4h)->ip_id)
100 #define IPV4_GET_RAW_IPOFFSET(ip4h) ((ip4h)->ip_off)
101 #define IPV4_GET_RAW_IPTTL(ip4h) ((ip4h)->ip_ttl)
102 #define IPV4_GET_RAW_IPPROTO(ip4h) ((ip4h)->ip_proto)
103 #define IPV4_GET_RAW_IPSRC(ip4h) ((ip4h)->s_ip_src)
104 #define IPV4_GET_RAW_IPDST(ip4h) ((ip4h)->s_ip_dst)
105 
106 /** return the raw (directly from the header) src ip as uint32_t */
107 #define IPV4_GET_RAW_IPSRC_U32(ip4h) (uint32_t)((ip4h)->s_ip_src.s_addr)
108 /** return the raw (directly from the header) dst ip as uint32_t */
109 #define IPV4_GET_RAW_IPDST_U32(ip4h) (uint32_t)((ip4h)->s_ip_dst.s_addr)
110 
111 /* we need to change them as well as get them */
112 #define IPV4_SET_RAW_VER(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0x0f) | (value << 4)))
113 #define IPV4_SET_RAW_HLEN(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0xf0) | (value & 0x0f)))
114 #define IPV4_SET_RAW_IPTOS(ip4h, value) ((ip4h)->ip_tos = value)
115 #define IPV4_SET_RAW_IPLEN(ip4h, value) ((ip4h)->ip_len = value)
116 #define IPV4_SET_RAW_IPPROTO(ip4h, value) ((ip4h)->ip_proto = value)
117 
118 /* ONLY call these functions after making sure that:
119  * 1. p->ip4h is set
120  * 2. p->ip4h is valid (len is correct)
121  */
122 #define IPV4_GET_VER(p) \
123  IPV4_GET_RAW_VER((p)->ip4h)
124 #define IPV4_GET_HLEN(p) ((uint8_t)(IPV4_GET_RAW_HLEN((p)->ip4h) << 2))
125 #define IPV4_GET_IPTOS(p) \
126  IPV4_GET_RAW_IPTOS((p)->ip4h)
127 #define IPV4_GET_IPLEN(p) \
128  (SCNtohs(IPV4_GET_RAW_IPLEN((p)->ip4h)))
129 #define IPV4_GET_IPID(p) \
130  (SCNtohs(IPV4_GET_RAW_IPID((p)->ip4h)))
131 /* _IPV4_GET_IPOFFSET: get the content of the offset header field in host order */
132 #define _IPV4_GET_IPOFFSET(p) \
133  (SCNtohs(IPV4_GET_RAW_IPOFFSET((p)->ip4h)))
134 /* IPV4_GET_IPOFFSET: get the final offset */
135 #define IPV4_GET_IPOFFSET(p) \
136  (_IPV4_GET_IPOFFSET(p) & 0x1fff)
137 /* IPV4_GET_RF: get the RF flag. Use _IPV4_GET_IPOFFSET to save a SCNtohs call. */
138 #define IPV4_GET_RF(p) \
139  (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x8000) >> 15)
140 /* IPV4_GET_DF: get the DF flag. Use _IPV4_GET_IPOFFSET to save a SCNtohs call. */
141 #define IPV4_GET_DF(p) \
142  (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x4000) >> 14)
143 /* IPV4_GET_MF: get the MF flag. Use _IPV4_GET_IPOFFSET to save a SCNtohs call. */
144 #define IPV4_GET_MF(p) \
145  (uint8_t)((_IPV4_GET_IPOFFSET((p)) & 0x2000) >> 13)
146 #define IPV4_GET_IPTTL(p) \
147  IPV4_GET_RAW_IPTTL(p->ip4h)
148 #define IPV4_GET_IPPROTO(p) \
149  IPV4_GET_RAW_IPPROTO((p)->ip4h)
150 
151 #define CLEAR_IPV4_PACKET(p) do { \
152  (p)->ip4h = NULL; \
153  (p)->level3_comp_csum = -1; \
154  memset(&p->ip4vars, 0x00, sizeof(p->ip4vars)); \
155 } while (0)
156 
170 };
171 
172 /* helper structure with parsed ipv4 info */
173 typedef struct IPV4Vars_
174 {
175  int32_t comp_csum; /* checksum computed over the ipv4 packet */
176 
177  uint16_t opt_cnt;
178  uint16_t opts_set;
180 
181 
182 void DecodeIPV4RegisterTests(void);
183 
184 /** ----- Inline functions ----- */
185 
186 /**
187  * \brief Calculate or validate the checksum for the IP packet
188  *
189  * \param pkt Pointer to the start of the IP packet
190  * \param hlen Length of the IP header
191  * \param init The current checksum if validating, 0 if generating.
192  *
193  * \retval csum For validation 0 will be returned for success, for calculation
194  * this will be the checksum.
195  */
196 static inline uint16_t IPV4Checksum(const uint16_t *pkt, uint16_t hlen, uint16_t init)
197 {
198  uint32_t csum = init;
199 
200  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] +
201  pkt[8] + pkt[9];
202 
203  hlen -= 20;
204  pkt += 10;
205 
206  if (hlen == 0) {
207  ;
208  } else if (hlen == 4) {
209  csum += pkt[0] + pkt[1];
210  } else if (hlen == 8) {
211  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3];
212  } else if (hlen == 12) {
213  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5];
214  } else if (hlen == 16) {
215  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
216  pkt[7];
217  } else if (hlen == 20) {
218  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
219  pkt[7] + pkt[8] + pkt[9];
220  } else if (hlen == 24) {
221  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
222  pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11];
223  } else if (hlen == 28) {
224  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
225  pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13];
226  } else if (hlen == 32) {
227  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
228  pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
229  pkt[14] + pkt[15];
230  } else if (hlen == 36) {
231  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
232  pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
233  pkt[14] + pkt[15] + pkt[16] + pkt[17];
234  } else if (hlen == 40) {
235  csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
236  pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
237  pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19];
238  }
239 
240  csum = (csum >> 16) + (csum & 0x0000FFFF);
241  csum += (csum >> 16);
242 
243  return (uint16_t) ~csum;
244 }
245 
246 #endif /* SURICATA_DECODE_IPV4_H */
IPV4Vars_
Definition: decode-ipv4.h:174
IPV4Hdr_::ip_addrs
uint16_t ip_addrs[4]
Definition: decode-ipv4.h:86
IPV4Hdr_::ip_ttl
uint8_t ip_ttl
Definition: decode-ipv4.h:78
IPV4Hdr_::ip_id
uint16_t ip_id
Definition: decode-ipv4.h:76
IPV4_OPT_FLAG_SEC
@ IPV4_OPT_FLAG_SEC
Definition: decode-ipv4.h:166
IPV4Hdr_::ip_tos
uint8_t ip_tos
Definition: decode-ipv4.h:74
DecodeIPV4RegisterTests
void DecodeIPV4RegisterTests(void)
Definition: decode-ipv4.c:1686
IPV4Opt_::len
uint8_t len
Definition: decode-ipv4.h:67
IPV4Hdr
struct IPV4Hdr_ IPV4Hdr
IPV4Hdr_::ip_src
struct in_addr ip_src
Definition: decode-ipv4.h:83
IPV4Vars
struct IPV4Vars_ IPV4Vars
IPV4_OPT_FLAG_NOP
@ IPV4_OPT_FLAG_NOP
Definition: decode-ipv4.h:159
IPV4Hdr_::ip_len
uint16_t ip_len
Definition: decode-ipv4.h:75
IPV4OptionFlags
IPV4OptionFlags
Definition: decode-ipv4.h:157
IPV4Vars_::opt_cnt
uint16_t opt_cnt
Definition: decode-ipv4.h:177
IPV4_OPT_FLAG_SID
@ IPV4_OPT_FLAG_SID
Definition: decode-ipv4.h:165
IPV4_OPT_FLAG_QS
@ IPV4_OPT_FLAG_QS
Definition: decode-ipv4.h:162
IPV4_OPT_FLAG_RR
@ IPV4_OPT_FLAG_RR
Definition: decode-ipv4.h:160
IPV4_OPT_FLAG_CIPSO
@ IPV4_OPT_FLAG_CIPSO
Definition: decode-ipv4.h:167
IPV4Opt_::data
const uint8_t * data
Definition: decode-ipv4.h:68
IPV4Hdr_
Definition: decode-ipv4.h:72
IPV4Hdr_::ip4_un1
struct IPV4Hdr_::@25::@26 ip4_un1
IPV4_OPT_FLAG_TS
@ IPV4_OPT_FLAG_TS
Definition: decode-ipv4.h:161
IPV4_OPT_FLAG_RTRALT
@ IPV4_OPT_FLAG_RTRALT
Definition: decode-ipv4.h:168
IPV4Opt_::type
uint8_t type
Definition: decode-ipv4.h:66
IPV4Opt
struct IPV4Opt_ IPV4Opt
IPV4Hdr_::ip_dst
struct in_addr ip_dst
Definition: decode-ipv4.h:84
IPV4Hdr_::ip4_hdrun1
union IPV4Hdr_::@25 ip4_hdrun1
IPV4_OPT_FLAG_ESEC
@ IPV4_OPT_FLAG_ESEC
Definition: decode-ipv4.h:169
IPV4_OPT_FLAG_SSRR
@ IPV4_OPT_FLAG_SSRR
Definition: decode-ipv4.h:164
IPV4Hdr_::ip_csum
uint16_t ip_csum
Definition: decode-ipv4.h:80
IPV4Vars_::opts_set
uint16_t opts_set
Definition: decode-ipv4.h:178
IPV4Hdr_::ip_off
uint16_t ip_off
Definition: decode-ipv4.h:77
IPV4Opt_
Definition: decode-ipv4.h:61
IPV4_OPT_FLAG_LSRR
@ IPV4_OPT_FLAG_LSRR
Definition: decode-ipv4.h:163
IPV4Hdr_::ip_proto
uint8_t ip_proto
Definition: decode-ipv4.h:79
IPV4Hdr_::ip_verhl
uint8_t ip_verhl
Definition: decode-ipv4.h:73
IPV4Vars_::comp_csum
int32_t comp_csum
Definition: decode-ipv4.h:175
IPV4_OPT_FLAG_EOL
@ IPV4_OPT_FLAG_EOL
Definition: decode-ipv4.h:158