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