00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 //
00004 // This program is free software; you can redistribute it and/or modify it
00005 // under the terms of the GNU General Public License Version 2 as published
00006 // by the Free Software Foundation. You may not use, modify or distribute
00007 // this program under any other version of the GNU General Public License.
00008 //
00009 // This program is distributed in the hope that it will be useful, but
00010 // WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program; if not, write to the Free Software Foundation, Inc.,
00016 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 //--------------------------------------------------------------------------
00018 // codec_manager.cc author Josh Rosenbaum <jrosenba@cisco.com>
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include "config.h"
00022 #endif
00023
00024 #include "codec_manager.h"
00025
00026 #include "log/messages.h"
00027 #include "main/snort_config.h"
00028 #include "packet_io/sfdaq.h"
00029 #include "protocols/packet_manager.h"
00030 #include "utils/dnet_header.h"
00031
00032 struct CodecManager::CodecApiWrapper
00033 {
00034 const CodecApi* api;
00035 bool init;
00036 };
00037
00038 // CodecManager Private Data
00039
00040 // the zero initialization is not required but quiets the compiler
00041 std::vector<CodecManager::CodecApiWrapper> CodecManager::s_codecs;
00042 std::array<uint8_t, num_protocol_ids> CodecManager::s_proto_map {
00043 { 0 }
00044 };
00045 std::array<Codec*, UINT8_MAX> CodecManager::s_protocols {
00046 { 0 }
00047 };
00048
00049 THREAD_LOCAL ProtocolId CodecManager::grinder_id = ProtocolId::ETHERTYPE_NOT_SET;
00050 THREAD_LOCAL uint8_t CodecManager::grinder = 0;
00051 THREAD_LOCAL uint8_t CodecManager::max_layers = DEFAULT_LAYERMAX;
00052
00053 // This is hardcoded into Snort++
00054 extern const CodecApi* default_codec;
00055
00056 // Local variables for various tasks
00057 static const uint16_t IP_ID_COUNT = 8192;
00058 static THREAD_LOCAL std::array<uint16_t, IP_ID_COUNT> s_id_pool {
00059 { 0 }
00060 };
00061 static THREAD_LOCAL rand_t* s_rand = nullptr;
00062
00063 /*
00064 * Begin search from index 1. 0 is a special case in that it is the default
00065 * codec and is actually a duplicate. i.e., we can find the 0 indexed
00066 * codec somewhere else in the array too.
00067 *
00068 * Returns: 0 on failure, index on success
00069 */
00070 uint8_t CodecManager::get_codec(const char* const keyword)
00071 {
00072 // starting at 1 since 0 is default
00073 for ( uint8_t i = 1; i < s_protocols.size(); i++)
00074 {
00075 if (s_protocols[i])
00076 {
00077 const char* name = s_protocols[i]->get_name();
00078 if ( !strncasecmp(name, keyword, strlen(name)) )
00079 return i;
00080 }
00081 }
00082 return 0;
00083 }
00084
00085 CodecManager::CodecApiWrapper& CodecManager::get_api_wrapper(const CodecApi* cd_api)
00086 {
00087 for (CodecApiWrapper& caw : s_codecs)
00088 {
00089 if (caw.api == cd_api)
00090 return caw;
00091 }
00092
00093 ParseAbort("Attempting to instantiate Codec '%s', "
00094 "but codec has not been added", cd_api->base.name);
00095 }
00096
00097 void CodecManager::add_plugin(const CodecApi* api)
00098 {
00099 if (!api->ctor)
00100 ParseError("CodecApi ctor() for Codec %s: ctor() must be implemented", api->base.name);
00101
00102 if (!api->dtor)
00103 ParseError("CodecApi ctor() for Codec %s: ctor() must be implemented", api->base.name);
00104
00105 CodecApiWrapper wrap;
00106 wrap.api = api;
00107 wrap.init = false;
00108
00109 s_codecs.push_back(wrap);
00110 }
00111
00112 void CodecManager::release_plugins()
00113 {
00114 for ( CodecApiWrapper& wrap : s_codecs )
00115 {
00116 if (wrap.api->pterm)
00117 {
00118 wrap.api->pterm();
00119 wrap.init = false; // Future proofing this function.
00120 }
00121
00122 uint8_t index = get_codec(wrap.api->base.name);
00123 if ( index != 0)
00124 {
00125 wrap.api->dtor(s_protocols[index]);
00126 s_protocols[index] = nullptr;
00127 }
00128 }
00129
00130 // The default codec is NOT part of the plugin list
00131 if (default_codec->pterm)
00132 default_codec->pterm();
00133
00134 if (s_protocols[0])
00135 {
00136 default_codec->dtor(s_protocols[0]);
00137 s_protocols[0] = nullptr;
00138 }
00139
00140 s_codecs.clear();
00141 s_proto_map.fill(0);
00142 }
00143
00144 void CodecManager::instantiate(CodecApiWrapper& wrap, Module* m, SnortConfig*)
00145 {
00146 static std::size_t codec_id = 1;
00147
00148 if (!wrap.init)
00149 {
00150 std::vector<ProtocolId> ids;
00151 const CodecApi* const cd_api = wrap.api;
00152
00153 if (codec_id >= s_protocols.size())
00154 ParseError("A maximum of 256 codecs can be registered");
00155
00156 if (cd_api->pinit)
00157 cd_api->pinit();
00158
00159 Codec* cd = cd_api->ctor(m);
00160 cd->get_protocol_ids(ids);
00161 for (auto id : ids)
00162 {
00163 if (s_proto_map[to_utype(id)] != 0)
00164 ParseError("The Codecs %s and %s have both been registered "
00165 "for protocol_id %d. Codec %s will be used\n",
00166 s_protocols[s_proto_map[to_utype(id)]]->get_name(), cd->get_name(),
00167 static_cast<uint16_t>(id), cd->get_name());
00168
00169 s_proto_map[to_utype(id)] = (decltype(s_proto_map[to_utype(id)]))codec_id; // future proofing
00170 }
00171
00172 wrap.init = true;
00173 s_protocols[codec_id++] = cd;
00174 }
00175 }
00176
00177 void CodecManager::instantiate(const CodecApi* cd_api, Module* m, SnortConfig* sc)
00178 {
00179 CodecApiWrapper& wrap = get_api_wrapper(cd_api);
00180 instantiate(wrap, m, sc);
00181 }
00182
00183 void CodecManager::instantiate()
00184 {
00185 CodecApiWrapper tmp_wrap;
00186 tmp_wrap.api = default_codec;
00187 tmp_wrap.init = false;
00188 instantiate(tmp_wrap, nullptr, nullptr);
00189
00190 // default codec is the api ... I want the codec.
00191 s_protocols[0] = s_protocols[get_codec(default_codec->base.name)];
00192
00193 // and instantiate every codec which does not have a module
00194 for (CodecApiWrapper& wrap : s_codecs)
00195 instantiate(wrap, nullptr, nullptr);
00196 }
00197
00198 void CodecManager::thread_init(SnortConfig* sc)
00199 {
00200 max_layers = sc->num_layers;
00201
00202 for ( CodecApiWrapper& wrap : s_codecs )
00203 if (wrap.api->tinit)
00204 wrap.api->tinit();
00205
00206 int daq_dlt = SFDAQ::get_base_protocol();
00207 for (int i = 0; s_protocols[i] != nullptr; i++)
00208 {
00209 Codec* cd = s_protocols[i];
00210 std::vector<int> data_link_types;
00211
00212 cd->get_data_link_type(data_link_types);
00213 for (auto curr_dlt : data_link_types)
00214 {
00215 if (curr_dlt == daq_dlt)
00216 {
00217 if (grinder != 0)
00218 WarningMessage("The Codecs %s and %s have both been registered "
00219 "as the raw decoder. Codec %s will be used\n",
00220 s_protocols[grinder]->get_name(), cd->get_name(),
00221 cd->get_name());
00222
00223 std::vector<ProtocolId> ids;
00224 s_protocols[i]->get_protocol_ids(ids);
00225
00226 grinder_id = ( !ids.empty() ) ? ids[0] : ProtocolId::FINISHED_DECODE;
00227 grinder = (uint8_t)i;
00228 }
00229 }
00230 }
00231
00232 if (!grinder)
00233 ParseError("Unable to find a Codec with data link type %d", daq_dlt);
00234
00235 if ( s_rand )
00236 rand_close(s_rand);
00237
00238 // rand_open() can yield valgrind errors because the
00239 // starting seed may come from "random stack contents"
00240 // (see man 3 dnet)
00241 s_rand = rand_open();
00242
00243 if ( !s_rand )
00244 ParseError("rand_open() failed.");
00245
00246 rand_get(s_rand, s_id_pool.data(), s_id_pool.size());
00247 }
00248
00249 void CodecManager::thread_term()
00250 {
00251 PacketManager::accumulate(); // statistics
00252
00253 for ( CodecApiWrapper& wrap : s_codecs )
00254 {
00255 if (wrap.api->tterm)
00256 wrap.api->tterm();
00257 }
00258
00259 if ( s_rand )
00260 {
00261 rand_close(s_rand);
00262 s_rand = nullptr;
00263 }
00264 }
00265
00266 void CodecManager::dump_plugins()
00267 {
00268 Dumper d("Codecs");
00269
00270 for ( CodecApiWrapper& wrap : s_codecs )
00271 d.dump(wrap.api->base.name, wrap.api->base.version);
00272 }
00273
00274 #ifdef PIGLET
00275 const CodecApi* CodecManager::find_api(const char* name)
00276 {
00277 for ( auto wrap : CodecManager::s_codecs )
00278 if ( !strcmp(wrap.api->base.name, name) )
00279 return wrap.api;
00280
00281 return nullptr;
00282 }
00283
00284 CodecWrapper* CodecManager::instantiate(const char* name, Module* m, SnortConfig*)
00285 {
00286 auto api = find_api(name);
00287 if ( !api )
00288 return nullptr;
00289
00290 auto p = api->ctor(m);
00291 if ( !p )
00292 return nullptr;
00293
00294 return new CodecWrapper(api, p);
00295 }
00296 #endif
00297
END OF CODE