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*)&gtp_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 &gtp_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