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 // tcp_options.h author Josh Rosenbaum <jrosenba@cisco.com>
19 
20 #ifndef PROTOCOLS_TCP_OPTIONS_H
21 #define PROTOCOLS_TCP_OPTIONS_H
22 
23 #include "main/snort_types.h"
24 
25 namespace snort
26 {
27 struct Packet;
28 
29 namespace tcp
30 {
31 struct TCPHdr;
32 
33 /* http://www.iana.org/assignments/tcp-parameters
34  *
35  * tcp options stuff. used to be in <netinet/tcp.h> but it breaks
36  * things on AIX
37  */
38 
39 enum class TcpOptCode : std::uint8_t
40 {
41     EOL = 0,    /* End of Option List [RFC793] */
42     NOP = 1,    /* No-Option [RFC793] */
43     MAXSEG = 2, /* Maximum Segment Size [RFC793] */
44     WSCALE = 3, /* Window scaling option [RFC1323] */
45     SACKOK = 4, /* Experimental [RFC2018]*/
46     SACK = 5,   /* Experimental [RFC2018] variable length */
47     ECHO = 6,   /* Echo (obsoleted by option 8)      [RFC1072] */
48     ECHOREPLY = 7,  /* Echo Reply (obsoleted by option 8)[RFC1072] */
49     TIMESTAMP = 8,  /* Timestamp [RFC1323], 10 bytes */
50     PARTIAL_PERM = 9,   /* Partial Order Permitted/ Experimental [RFC1693] */
51     PARTIAL_SVC = 10,   /*  Partial Order Profile [RFC1693] */
52     CC = 11,        /*  T/TCP Connection count  [RFC1644] */
53     CC_NEW = 12,    /*  CC.NEW [RFC1644] */
54     CC_ECHO = 13,   /*  CC.ECHO [RFC1644] */
55 
56     ALTCSUM = 15,   /* TCP Alternate Checksum Data [RFC1146], variable length */
57     SKEETER = 16,   /* Skeeter [Knowles] */
58     BUBBA = 17,     /* Bubba   [Knowles] */
59     TRAILER_CSUM = 18,  /* Trailer Checksum Option [Subbu & Monroe] */
60     MD5SIG = 19,    /* MD5 Signature Option [RFC2385] */
61 
62     /* Space Communications Protocol Standardization */
63     SCPS = 20,  /* Capabilities [Scott] */
64     SELNEGACK = 21,     /* Selective Negative Acknowledgements [Scott] */
65     RECORDBOUND = 22,   /* Record Boundaries [Scott] */
66     CORRUPTION = 23,    /* Corruption experienced [Scott] */
67     SNAP = 24,  /* SNAP [Sukonnik] -- anyone have info?*/
68     UNASSIGNED = 25,    /* Unassigned (released 12/18/00) */
69     COMPRESSION = 26,   /* TCP Compression Filter [Bellovin] */
70     /* http://www.research.att.com/~smb/papers/draft-bellovin-tcpcomp-00.txt*/
71 
72     AUTH = 29,  /* [RFC5925] - The TCP Authentication Option
73                              Intended to replace MD5 Signature Option [RFC2385] */
74 };
75 
76 /*  Associated lengths */
77 const uint8_t TCPOLEN_EOL = 1;      /* Always one byte - [RFC793]*/
78 const uint8_t TCPOLEN_NOP = 1;      /* Always one byte - [RFC793]*/
79 const uint8_t TCPOLEN_MAXSEG = 4;   /* Always 4 bytes - [RFC793] */
80 const uint8_t TCPOLEN_WSCALE = 3;   /* 1 byte with logarithmic values - [RFC1323]*/
81 const uint8_t TCPOLEN_SACKOK = 2;   /* Experimental [RFC2018]*/
82 const uint8_t TCPOLEN_ECHO = 6;     /* 6 bytes  - Echo (obsoleted by option 8)      [RFC1072] */
83 const uint8_t TCPOLEN_ECHOREPLY = 6;    /* 6 bytes  - Echo Reply (obsoleted by option 8)[RFC1072]*/
84 const uint8_t TCPOLEN_TIMESTAMP = 10;   /* Timestamp [RFC1323], 10 bytes */
85 const uint8_t TCPOLEN_PARTIAL_PERM = 2; /* Partial Order Permitted/ Experimental [RFC1693] */
86 const uint8_t TCPOLEN_PARTIAL_SVC = 3;  /*  3 bytes long -- Experimental - [RFC1693] */
87 
88 /* at least decode T/TCP options... */
89 const uint8_t TCPOLEN_CC = 6;       /* page 17 of rfc1644 */
90 const uint8_t TCPOLEN_CC_NEW = 6;   /* page 17 of rfc1644 */
91 const uint8_t TCPOLEN_CC_ECHO = 6;  /* page 17 of rfc1644 */
92 
93 const uint8_t TCPOLEN_TRAILER_CSUM = 3;
94 const uint8_t TCPOLEN_MD5SIG = 18;
95 
96 // FIXIT-L reduce all these classes to a simple pointer based approach
97 // that doesn't require any reinterpret casts (see also ipv4_options.h)
98 struct TcpOption
99 {
100     TcpOptCode code;
101     uint8_t len;
102     uint8_t data[40];  // maximum possible
103 
get_lenTcpOption104     inline uint8_t get_len() const
105     { return ((uint8_t)code <= 1) ? 1 : len; }
106 
get_dataTcpOption107     inline const uint8_t* get_data() const
108     { return ((uint8_t)code <= 1 || len < 2) ? nullptr : &data[0]; }
109 
nextTcpOption110     inline const TcpOption& next() const
111     {
112         if ( (uint8_t)code <= 1 )
113             return reinterpret_cast<const TcpOption&>(len);
114         else
115             return reinterpret_cast<const TcpOption&>(data[len -2]);
116     }
117 };
118 
119 class TcpOptIterator;
120 
121 /*
122  * Use TcpOptIterator ... this should NOT be called directly
123  * unless you want to an actual iterator or some buggy code.
124  */
125 class SO_PUBLIC TcpOptIteratorIter
126 {
127 public:
128     TcpOptIteratorIter(const TcpOption*, const TcpOptIterator*);
129 
130     bool operator==(const TcpOptIteratorIter& rhs)
131     { return opt == rhs.opt; }
132 
133     bool operator!=(const TcpOptIteratorIter& rhs)
134     { return opt != rhs.opt; }
135 
136     const TcpOptIteratorIter& operator++();
137     const TcpOption& operator*() const;
138 
139 private:
140     const TcpOption* opt;
141     const TcpOptIterator* iter;
142 };
143 
144 /*
145  * Use IP ranged for loop rather than calling this directly.
146  * i.e.,
147  *      IpOptionIter iter(tcph, p)
148  *      for (const TcpOption& opt : iter)
149  *      {
150  *          do_something
151  *      }
152  */
153 class SO_PUBLIC TcpOptIterator
154 {
155 public:
156     /* CONSTRUCTOR VALID AFTER DECODE()
157      * Some options in the provided header may not be valid.
158      * Provide the packet struct ensures only valid options
159      * will be returned
160      */
161     TcpOptIterator(const TCPHdr* const, const Packet* const);
162     /* If you already know the validated option length (for instance,
163      * if you are in a decode() method), then call this constructor.*/
164     TcpOptIterator(const TCPHdr* const, const uint32_t valid_hdr_len);
165     TcpOptIteratorIter begin() const;
166     TcpOptIteratorIter end() const;
167 
168 private:
169     const uint8_t* start_ptr;
170     const uint8_t* end_ptr;
171 };
172 } // namespace tcp
173 } // namespace snort
174 
175 #endif
176 
177