1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // ipv6.h author Josh Rosenbaum <jrosenba@cisco.com>
19
20 #ifndef PROTOCOLS_IPV6_H
21 #define PROTOCOLS_IPV6_H
22
23 #include <arpa/inet.h>
24
25 #include "protocols/protocol_ids.h"
26
27 namespace snort
28 {
29 namespace ip
30 {
31 constexpr uint8_t IP6_HEADER_LEN = 40;
32 constexpr uint32_t MIN_EXT_LEN = 8;
33 constexpr uint8_t IP6_MULTICAST = 0xFF; // first/most significant octet
34
35 constexpr uint16_t IP6F_MF_MASK = 0x0001; /* more-fragments flag */
36 constexpr uint16_t IP6F_RES_MASK = 0x0006; /* reserved bits */
37
38 enum class MulticastScope : uint8_t
39 {
40 RESERVED = 0x00,
41 INTERFACE = 0x01,
42 LINK = 0x02,
43 ADMIN = 0x04,
44 SITE = 0x05,
45 ORG = 0x08,
46 GLOBAL = 0x0E,
47 };
48
49 /* IPv6 address */
50 struct snort_in6_addr
51 {
52 union
53 {
54 uint8_t u6_addr8[16];
55 uint16_t u6_addr16[8];
56 uint32_t u6_addr32[4];
57 };
58 };
59
60 struct IP6Hdr
61 {
62 uint32_t ip6_vtf; /* 4 bits version, 8 bits TC,len
63 20 bits flow-ID */
64 uint16_t ip6_payload_len; /* payload length */
65 IpProtocol ip6_next; /* next header */
66 uint8_t ip6_hoplim; /* hop limit */
67
68 snort_in6_addr ip6_src; /* source address */
69 snort_in6_addr ip6_dst; /* destination address */
70
lenIP6Hdr71 inline uint16_t len() const
72 { return ntohs(ip6_payload_len); }
73
74 /* Same function as ipv4 */
protoIP6Hdr75 inline IpProtocol proto() const
76 { return ip6_next; }
77
nextIP6Hdr78 inline IpProtocol next() const
79 { return ip6_next; }
80
hop_limIP6Hdr81 inline uint8_t hop_lim() const
82 { return ip6_hoplim; }
83
verIP6Hdr84 inline uint8_t ver() const
85 { return (uint8_t)(ntohl(ip6_vtf) >> 28); }
86
tosIP6Hdr87 inline uint16_t tos() const
88 { return (uint16_t)((ntohl(ip6_vtf) & 0x0FF00000) >> 20); }
89
flowIP6Hdr90 inline uint32_t flow() const
91 { return (ntohl(ip6_vtf) & 0x000FFFFF); }
92
93 // because Snort expects this in terms of 32 bit words.
hlenIP6Hdr94 inline uint8_t hlen() const
95 { return IP6_HEADER_LEN; }
96
get_srcIP6Hdr97 inline const snort_in6_addr* get_src() const
98 { return &ip6_src; }
99
get_dstIP6Hdr100 inline const snort_in6_addr* get_dst() const
101 { return &ip6_dst; }
102
get_dst_multicast_scopeIP6Hdr103 inline MulticastScope get_dst_multicast_scope() const
104 { return static_cast<MulticastScope>(ip6_dst.u6_addr8[1] & 0x0F); }
105
106 /* booleans */
is_src_multicastIP6Hdr107 inline bool is_src_multicast() const
108 { return (ip6_src.u6_addr8[0] == IP6_MULTICAST); }
109
is_dst_multicastIP6Hdr110 inline bool is_dst_multicast() const
111 { return ip6_dst.u6_addr8[0] == IP6_MULTICAST; }
112
is_dst_multicast_scope_reservedIP6Hdr113 inline bool is_dst_multicast_scope_reserved() const
114 { return static_cast<MulticastScope>(ip6_dst.u6_addr8[1]) == MulticastScope::RESERVED; }
115
is_dst_multicast_scope_interfaceIP6Hdr116 inline bool is_dst_multicast_scope_interface() const
117 { return static_cast<MulticastScope>(ip6_dst.u6_addr8[1]) == MulticastScope::INTERFACE; }
118
is_dst_multicast_scope_linkIP6Hdr119 inline bool is_dst_multicast_scope_link() const
120 { return static_cast<MulticastScope>(ip6_dst.u6_addr8[1]) == MulticastScope::LINK; }
121
is_dst_multicast_scope_siteIP6Hdr122 inline bool is_dst_multicast_scope_site() const
123 { return (static_cast<MulticastScope>(ip6_dst.u6_addr8[1]) == MulticastScope::SITE); }
124
is_dst_multicast_scope_globalIP6Hdr125 inline bool is_dst_multicast_scope_global() const
126 { return (static_cast<MulticastScope>(ip6_dst.u6_addr8[1]) == MulticastScope::GLOBAL); }
127
is_valid_next_headerIP6Hdr128 inline bool is_valid_next_header() const
129 {
130 switch (ip6_next)
131 {
132 case IpProtocol::NONEXT:
133 case IpProtocol::TCP:
134 case IpProtocol::UDP:
135 case IpProtocol::ICMPV6:
136 case IpProtocol::HOPOPTS:
137 case IpProtocol::DSTOPTS:
138 case IpProtocol::ROUTING:
139 case IpProtocol::FRAGMENT:
140 case IpProtocol::MPLS_IP:
141 case IpProtocol::GRE:
142 case IpProtocol::MOBILITY_IPV6:
143 return true;
144 default:
145 break;
146 }
147 return false;
148 }
149
150 /* setters */
set_lenIP6Hdr151 inline void set_len(uint16_t new_len)
152 { ip6_payload_len = htons(new_len); }
153
set_protoIP6Hdr154 inline void set_proto(IpProtocol prot)
155 { ip6_next = prot; }
156
set_raw_lenIP6Hdr157 inline void set_raw_len(uint16_t new_len)
158 { ip6_payload_len = new_len; }
159
160 /* Access raw data */
161
raw_lenIP6Hdr162 inline uint16_t raw_len() const
163 { return ip6_payload_len; }
164 };
165
166 enum class HopByHopOptions : uint8_t
167 {
168 PAD1 = 0x00,
169 PADN = 0x01,
170 TUNNEL_ENCAP = 0x04,
171 RTALERT = 0x05,
172 QUICK_START = 0x06,
173 CALIPSO = 0x07,
174 HOME_ADDRESS = 0xC9,
175 JUMBO = 0xC2,
176 ENDPOINT_IDENT = 0x8A,
177 };
178
179 /* to store references to IP6 Extension Headers */
180 struct IP6Option
181 {
182 uint8_t type;
183 const uint8_t* data;
184 };
185
186 /* Generic Extension Header */
187 struct IP6Extension
188 {
189 IpProtocol ip6e_nxt;
190 uint8_t ip6e_len;
191 /* options follow */
192 uint8_t ip6e_pad[6];
193 };
194
195 /* Fragment header */
196 struct IP6Frag
197 {
198 IpProtocol ip6f_nxt; /* next header */
199 uint8_t ip6f_reserved; /* reserved field */
200 uint16_t ip6f_offlg; /* offset, reserved, and flag */
201 uint32_t ip6f_ident; /* identification */
202
nextIP6Frag203 inline IpProtocol next() const
204 { return ip6f_nxt; }
205
off_w_flagsIP6Frag206 inline uint16_t off_w_flags() const
207 { return ntohs(ip6f_offlg); }
208
offIP6Frag209 inline uint16_t off() const
210 { return ntohs(ip6f_offlg) & 0xFFF8; }
211
mfIP6Frag212 inline uint16_t mf() const
213 { return ntohs(ip6f_offlg) & IP6F_MF_MASK; }
214
rbIP6Frag215 inline uint16_t rb() const
216 { return ntohs(ip6f_offlg) & IP6F_RES_MASK; }
217
idIP6Frag218 inline uint32_t id() const
219 { return ntohl(ip6f_ident); }
220
resIP6Frag221 inline uint8_t res() const
222 { return ip6f_reserved; }
223
raw_off_w_flagsIP6Frag224 inline uint16_t raw_off_w_flags() const
225 { return ip6f_offlg; }
226
raw_idIP6Frag227 inline uint32_t raw_id() const
228 { return ip6f_ident; }
229 };
230
231 // Reflects the recommended IPv6 order in RFC 2460 4.1
232 constexpr int IPV6_ORDER_MAX = 7;
IPV6IdExtensionOrder(const ProtocolId prot_id)233 inline int IPV6IdExtensionOrder(const ProtocolId prot_id)
234 {
235 switch (prot_id)
236 {
237 case ProtocolId::HOPOPTS: return 1;
238 case ProtocolId::DSTOPTS: return 2;
239 case ProtocolId::ROUTING: return 3;
240 case ProtocolId::FRAGMENT: return 4;
241 case ProtocolId::AUTH: return 5;
242 case ProtocolId::ESP: return 6;
243 default: return IPV6_ORDER_MAX;
244 }
245 }
246
IPV6ExtensionOrder(const IpProtocol ip_proto)247 inline int IPV6ExtensionOrder(const IpProtocol ip_proto)
248 {
249 return IPV6IdExtensionOrder((ProtocolId)ip_proto);
250 }
251 } // namespace ip
252 } // namespace snort
253 #endif
254
255