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
19 // gtp_module.cc author Russ Combs <rucombs@cisco.com>
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gtp_module.h"
26
27 #include <cassert>
28
29 #include "profiler/profiler.h"
30 #include "trace/trace.h"
31
32 #include "gtp.h"
33
34 using namespace snort;
35
36 THREAD_LOCAL const Trace* gtp_inspect_trace = nullptr;
37
38 THREAD_LOCAL ProfileStats gtp_inspect_prof;
39
40 #define GTP_EVENT_BAD_MSG_LEN_STR "message length is invalid"
41 #define GTP_EVENT_BAD_IE_LEN_STR "information element length is invalid"
42 #define GTP_EVENT_OUT_OF_ORDER_IE_STR "information elements are out of order"
43 #define GTP_EVENT_MISSING_TEID_STR "TEID is missing"
44
45 //-------------------------------------------------------------------------
46 // stats
47 //-------------------------------------------------------------------------
48
49 const PegInfo peg_names[] =
50 {
51 { CountType::SUM, "sessions", "total sessions processed" },
52 { CountType::NOW, "concurrent_sessions", "total concurrent gtp sessions" },
53 { CountType::MAX, "max_concurrent_sessions", "maximum concurrent gtp sessions" },
54 { CountType::SUM, "events", "requests" },
55 { CountType::SUM, "unknown_types", "unknown message types" },
56 { CountType::SUM, "unknown_infos", "unknown information elements" },
57
58 { CountType::END, nullptr, nullptr }
59 };
60
get_pegs() const61 const PegInfo* GtpInspectModule::get_pegs() const
62 { return peg_names; }
63
get_counts() const64 PegCount* GtpInspectModule::get_counts() const
65 { return (PegCount*)>p_stats; }
66
67 //-------------------------------------------------------------------------
68 // rules
69 //-------------------------------------------------------------------------
70
71 static const RuleMap gtp_rules[] =
72 {
73 { GTP_EVENT_BAD_MSG_LEN, GTP_EVENT_BAD_MSG_LEN_STR },
74 { GTP_EVENT_BAD_IE_LEN, GTP_EVENT_BAD_IE_LEN_STR },
75 { GTP_EVENT_OUT_OF_ORDER_IE, GTP_EVENT_OUT_OF_ORDER_IE_STR },
76 { GTP_EVENT_MISSING_TEID, GTP_EVENT_MISSING_TEID_STR },
77
78 { 0, nullptr }
79 };
80
get_rules() const81 const RuleMap* GtpInspectModule::get_rules() const
82 { return gtp_rules; }
83
84 //-------------------------------------------------------------------------
85 // params
86 //-------------------------------------------------------------------------
87
88 static const Parameter gtp_msg_params[] =
89 {
90 { "type", Parameter::PT_INT, "0:255", "0",
91 "message type code" },
92
93 { "name", Parameter::PT_STRING, nullptr, nullptr,
94 "message name" },
95
96 { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
97 };
98
99 static const Parameter gtp_info_params[] =
100 {
101 { "type", Parameter::PT_INT, "0:255", "0",
102 "information element type code" },
103
104 { "name", Parameter::PT_STRING, nullptr, nullptr,
105 "information element name" },
106
107 { "length", Parameter::PT_INT, "0:255", "0",
108 "information element type code" },
109
110 { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
111 };
112
113
114 static const Parameter gtp_params[] =
115 {
116 { "version", Parameter::PT_INT, "0:2", "2",
117 "GTP version" },
118
119 { "messages", Parameter::PT_LIST, gtp_msg_params, nullptr,
120 "message dictionary" },
121
122 { "infos", Parameter::PT_LIST, gtp_info_params, nullptr,
123 "information element dictionary" },
124
125 { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
126 };
127
GtpInspectModule()128 GtpInspectModule::GtpInspectModule() : Module(GTP_NAME, GTP_HELP, gtp_params, true)
129 { }
130
set_trace(const Trace * trace) const131 void GtpInspectModule::set_trace(const Trace* trace) const
132 { gtp_inspect_trace = trace; }
133
get_trace_options() const134 const TraceOption* GtpInspectModule::get_trace_options() const
135 {
136 #ifndef DEBUG_MSGS
137 return nullptr;
138 #else
139 static const TraceOption gtp_inspect_trace_options(nullptr, 0, nullptr);
140 return >p_inspect_trace_options;
141 #endif
142 }
143
set(const char *,Value & v,SnortConfig *)144 bool GtpInspectModule::set(const char*, Value& v, SnortConfig*)
145 {
146 if ( v.is("version") )
147 stuff.version = v.get_uint8();
148
149 else if ( v.is("type") )
150 stuff.type = v.get_uint8();
151
152 else if ( v.is("length") )
153 stuff.length = v.get_uint8();
154
155 else if ( v.is("name") )
156 stuff.name = v.get_string();
157
158 return true;
159 }
160
begin(const char * fqn,int idx,SnortConfig *)161 bool GtpInspectModule::begin(const char* fqn, int idx, SnortConfig*)
162 {
163 if ( !strcmp(fqn, "gtp_inspect") and !idx )
164 {
165 temp.clear();
166 config.clear();
167 }
168
169 // version persists
170 stuff.name.clear();
171 stuff.type = 0;
172 stuff.length = -1;
173
174 return true;
175 }
176
177 // we may not get current version until after lists are loaded
178 // so the lists go to temp and when the list item is closed we
179 // move to the main config.
end(const char * fqn,int idx,SnortConfig *)180 bool GtpInspectModule::end(const char* fqn, int idx, SnortConfig*)
181 {
182 if ( !strcmp(fqn, "gtp_inspect") and idx )
183 {
184 for ( unsigned i = 0; i < temp.size(); ++i )
185 {
186 temp[i].version = stuff.version;
187 config.emplace_back(temp[i]);
188 }
189 temp.clear();
190 }
191 else if ( !strcmp(fqn, "gtp_inspect.messages") and idx )
192 {
193 assert(stuff.length < 0);
194 temp.emplace_back(stuff);
195 }
196 else if ( !strcmp(fqn, "gtp_inspect.infos") and idx )
197 {
198 assert(stuff.length >= 0);
199 temp.emplace_back(stuff);
200 }
201 return true;
202 }
203