55 * @author Pavel Siska <[email protected] > 66 * @date 2025
77 *
8- * Copyright (c) 2025 CESNET
8+ * Provides a plugin that extracts NetBIOS suffix and name from packets,
9+ * stores them in per-flow plugin data, and exposes fields via FieldManager.
910 *
10- * SPDX-License-Identifier: BSD-3-Clause
11+ * @copyright Copyright (c) 2025 CESNET, z.s.p.o.
1112 */
1213
1314#include " netbios.hpp"
1415
15- #ifdef WITH_NEMEA
16- #include < unirec/unirec.h>
17- #endif
16+ #include " netbiosGetters.hpp"
1817
18+ #include < cmath>
1919#include < iostream>
2020
21- #include < ipfixprobe/pluginFactory/pluginManifest.hpp>
22- #include < ipfixprobe/pluginFactory/pluginRegistrar.hpp>
21+ #include < dns-utils.hpp>
22+ #include < fieldGroup.hpp>
23+ #include < fieldManager.hpp>
24+ #include < flowRecord.hpp>
25+ #include < ipfixprobe/options.hpp>
26+ #include < pluginFactory.hpp>
27+ #include < pluginManifest.hpp>
28+ #include < pluginRegistrar.hpp>
29+ #include < utils/spanUtils.hpp>
30+ #include < utils/stringViewUtils.hpp>
2331
24- namespace ipxp {
32+ namespace ipxp ::process::netbios {
2533
2634static const PluginManifest netbiosPluginManifest = {
2735 .name = " netbios" ,
@@ -34,121 +42,95 @@ static const PluginManifest netbiosPluginManifest = {
3442 parser.usage (std::cout);
3543 },
3644};
37- NETBIOSPlugin::NETBIOSPlugin (const std::string& params, int pluginID)
38- : ProcessPlugin(pluginID)
39- , total_netbios_packets(0 )
40- {
41- init (params.c_str ());
42- }
4345
44- NETBIOSPlugin::~NETBIOSPlugin ()
46+ static FieldGroup
47+ createNetBIOSSchema (FieldManager& fieldManager, FieldHandlers<NetBIOSFields>& fieldHandlers)
4548{
46- close ();
47- }
49+ FieldGroup schema = fieldManager.createFieldGroup (" netbios" );
4850
49- void NETBIOSPlugin::init (const char * params)
50- {
51- (void ) params;
52- }
51+ fieldHandlers.insert (
52+ NetBIOSFields::NB_SUFFIX,
53+ schema.addScalarField (" NB_SUFFIX" , getNBSuffixField));
5354
54- void NETBIOSPlugin::close () {}
55+ fieldHandlers. insert (NetBIOSFields::NB_NAME, schema. addScalarField ( " NB_NAME " , getNBNameField));
5556
56- ProcessPlugin* NETBIOSPlugin::copy ()
57- {
58- return new NETBIOSPlugin (*this );
57+ return schema;
5958}
6059
61- int NETBIOSPlugin::post_create (Flow& rec, const Packet& pkt )
60+ NetBIOSPlugin::NetBIOSPlugin ([[maybe_unused]] const std::string& params, FieldManager& manager )
6261{
63- if (pkt.dst_port == 137 || pkt.src_port == 137 ) {
64- return add_netbios_ext (rec, pkt);
65- }
66-
67- return 0 ;
62+ createNetBIOSSchema (manager, m_fieldHandlers);
6863}
6964
70- int NETBIOSPlugin::post_update (Flow& rec, const Packet& pkt )
65+ OnInitResult NetBIOSPlugin::onInit ( const FlowContext& flowContext, void * pluginContext )
7166{
72- if (pkt.dst_port == 137 || pkt.src_port == 137 ) {
73- return add_netbios_ext (rec, pkt);
67+ constexpr uint8_t NETBIOS_PORT = 137 ;
68+ if (flowContext.flowRecord .flowKey .srcPort == NETBIOS_PORT
69+ || flowContext.flowRecord .flowKey .dstPort == NETBIOS_PORT) {
70+ auto & netbiosContext = *std::construct_at (reinterpret_cast <NetBIOSContext*>(pluginContext));
71+ parseNetBIOS (
72+ flowContext.flowRecord ,
73+ getPayload (*flowContext.packetContext .packet ),
74+ netbiosContext);
75+ return OnInitResult::ConstructedFinal;
7476 }
7577
76- return 0 ;
78+ return OnInitResult::Irrelevant ;
7779}
7880
79- int NETBIOSPlugin::add_netbios_ext (Flow& rec , const Packet& pkt )
81+ constexpr static char compressCharPair ( const char first , const char second )
8082{
81- RecordExtNETBIOS* ext = new RecordExtNETBIOS (m_pluginID);
82- if (parse_nbns (ext, pkt)) {
83- total_netbios_packets++;
84- rec.add_extension (ext);
85- } else {
86- delete ext;
87- }
88-
89- return 0 ;
83+ return static_cast <char >(((first - ' A' ) << 4 ) | (second - ' A' ));
9084}
9185
92- bool NETBIOSPlugin::parse_nbns (RecordExtNETBIOS* rec, const Packet& pkt)
86+ void NetBIOSPlugin::parseNetBIOS (
87+ FlowRecord& flowRecord,
88+ std::span<const std::byte> payload,
89+ NetBIOSContext& netbiosContext) noexcept
9390{
94- const char * payload = reinterpret_cast <const char *>(pkt.payload );
95-
96- int qry_cnt = get_query_count (payload, pkt.payload_len );
97- payload += sizeof (struct dns_hdr );
98- if (qry_cnt < 1 ) {
99- return false ;
91+ if (payload.size () < sizeof (dns_hdr) || !netbiosContext.name .empty ()) {
92+ return ;
10093 }
10194
102- return store_first_query (payload, rec);
103- }
104-
105- int NETBIOSPlugin::get_query_count (const char * payload, uint16_t payload_length)
106- {
107- if (payload_length < sizeof (struct dns_hdr )) {
108- return -1 ;
95+ const std::size_t queryCount
96+ = reinterpret_cast <const dns_hdr*>(payload.data ())->question_rec_cnt ;
97+ if (queryCount == 0 ) {
98+ return ;
10999 }
110100
111- struct dns_hdr * hdr = (struct dns_hdr *) payload;
112- return ntohs (hdr->question_rec_cnt );
113- }
114-
115- bool NETBIOSPlugin::store_first_query (const char * payload, RecordExtNETBIOS* rec)
116- {
117- uint8_t nb_name_length = *payload++;
118- if (nb_name_length != 32 ) {
119- return false ;
101+ const uint8_t nameLength = *reinterpret_cast <const uint8_t *>(payload.data () + sizeof (dns_hdr));
102+ constexpr std::size_t VALID_NB_NAME_LENGTH = 32 ;
103+ if (nameLength != VALID_NB_NAME_LENGTH) {
104+ return ;
120105 }
121106
122- rec->netbios_name = " " ;
123- for (int i = 0 ; i < nb_name_length; i += 2 , payload += 2 ) {
124- if (i != 30 ) {
125- rec->netbios_name += compress_nbns_name_char (payload);
126- } else {
127- rec->netbios_suffix = get_nbns_suffix (payload);
128- }
107+ auto nameIt = reinterpret_cast <const std::pair<char , char >*>(payload.data ());
108+ for (; reinterpret_cast <const std::byte*>(nameIt) != payload.data () + payload.size () - 2 ;
109+ nameIt++) {
110+ netbiosContext.name .push_back (compressCharPair (nameIt->first , nameIt->second ));
129111 }
130- return true ;
131- }
112+ m_fieldHandlers[NetBIOSFields::NB_NAME].setAsAvailable (flowRecord);
132113
133- char NETBIOSPlugin::compress_nbns_name_char (const char * uncompressed)
134- {
135- return (((uncompressed[0 ] - ' A' ) << 4 ) | (uncompressed[1 ] - ' A' ));
114+ netbiosContext.suffix = compressCharPair (nameIt->first , nameIt->second );
115+ m_fieldHandlers[NetBIOSFields::NB_SUFFIX].setAsAvailable (flowRecord);
136116}
137117
138- uint8_t NETBIOSPlugin::get_nbns_suffix ( const char * uncompressed)
118+ void NetBIOSPlugin::onDestroy ( void * pluginContext) noexcept
139119{
140- return compress_nbns_name_char (uncompressed );
120+ std::destroy_at ( reinterpret_cast <NetBIOSContext*>(pluginContext) );
141121}
142122
143- void NETBIOSPlugin::finish ( bool print_stats)
123+ PluginDataMemoryLayout NetBIOSPlugin::getDataMemoryLayout () const noexcept
144124{
145- if (print_stats) {
146- std::cout << " NETBIOS plugin stats: " << std::endl;
147- std::cout << " Parsed NBNS packets in total: " << total_netbios_packets << std::endl;
148- }
125+ return {
126+ . size = sizeof (NetBIOSContext),
127+ . alignment = alignof (NetBIOSContext),
128+ };
149129}
150130
151- static const PluginRegistrar<NETBIOSPlugin, ProcessPluginFactory>
131+ static const PluginRegistrar<
132+ NetBIOSPlugin,
133+ PluginFactory<ProcessPlugin, const std::string&, FieldManager&>>
152134 netbiosRegistrar (netbiosPluginManifest);
153135
154- } // namespace ipxp
136+ } // namespace ipxp::process::netbios
0 commit comments