1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2002-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation.  You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //--------------------------------------------------------------------------
19 // cd_icmp4.cc author Josh Rosenbaum <jrosenba@cisco.com>
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <daq.h>
26 
27 #include "codecs/codec_module.h"
28 #include "framework/codec.h"
29 #include "log/text_log.h"
30 #include "main/snort_config.h"
31 #include "protocols/icmp4.h"
32 
33 #include "checksum.h"
34 
35 using namespace snort;
36 
37 #define CD_ICMP4_NAME "icmp4"
38 #define CD_ICMP4_HELP "support for Internet control message protocol v4"
39 
40 namespace
41 {
42 const PegInfo pegs[]
43 {
44     { CountType::SUM, "bad_checksum", "non-zero icmp checksums" },
45     { CountType::SUM, "checksum_bypassed", "checksum calculations bypassed" },
46     { CountType::END, nullptr, nullptr }
47 };
48 
49 struct Stats
50 {
51     PegCount bad_ip4_cksum;
52     PegCount cksum_bypassed;
53 };
54 
55 static THREAD_LOCAL Stats stats;
56 
57 static const RuleMap icmp4_rules[] =
58 {
59     { DECODE_ICMP_DGRAM_LT_ICMPHDR, "ICMP header truncated" },
60     { DECODE_ICMP_DGRAM_LT_TIMESTAMPHDR, "ICMP timestamp header truncated" },
61     { DECODE_ICMP_DGRAM_LT_ADDRHDR, "ICMP address header truncated" },
62     { DECODE_ICMP_ORIG_IP_TRUNCATED, "ICMP original IP header truncated" },
63     { DECODE_ICMP_ORIG_IP_VER_MISMATCH, "ICMP version and original IP header versions differ" },
64     { DECODE_ICMP_ORIG_DGRAM_LT_ORIG_IP,
65       "ICMP original datagram length < original IP header length" },
66     { DECODE_ICMP_ORIG_PAYLOAD_LT_64, "ICMP original IP payload < 64 bits" },
67     { DECODE_ICMP_ORIG_PAYLOAD_GT_576, "ICMP original IP payload > 576 bytes" },
68     { DECODE_ICMP_ORIG_IP_WITH_FRAGOFFSET, "ICMP original IP fragmented and offset not 0" },
69     { DECODE_ICMP4_DST_MULTICAST, "ICMP4 packet to multicast dest address" },
70     { DECODE_ICMP4_DST_BROADCAST, "ICMP4 packet to broadcast dest address" },
71     { DECODE_ICMP4_TYPE_OTHER, "ICMP4 type other" },
72     { DECODE_ICMP_PING_NMAP, "ICMP ping Nmap" },
73     { DECODE_ICMP_ICMPENUM, "ICMP icmpenum v1.1.1" },
74     { DECODE_ICMP_REDIRECT_HOST, "ICMP redirect host" },
75     { DECODE_ICMP_REDIRECT_NET, "ICMP redirect net" },
76     { DECODE_ICMP_TRACEROUTE_IPOPTS, "ICMP traceroute ipopts" },
77     { DECODE_ICMP_SOURCE_QUENCH, "ICMP source quench" },
78     { DECODE_ICMP_BROADSCAN_SMURF_SCANNER, "broadscan smurf scanner" },
79     { DECODE_ICMP_DST_UNREACH_ADMIN_PROHIBITED,
80       "ICMP destination unreachable communication administratively prohibited" },
81     { DECODE_ICMP_DST_UNREACH_DST_HOST_PROHIBITED,
82       "ICMP destination unreachable communication with destination host is "
83       "administratively prohibited" },
84     { DECODE_ICMP_DST_UNREACH_DST_NET_PROHIBITED,
85       "ICMP destination unreachable communication with destination network is "
86       "administratively prohibited" },
87     { DECODE_ICMP_PATH_MTU_DOS, "ICMP path MTU denial of service attempt" },
88     { DECODE_ICMP_DOS_ATTEMPT, "Linux ICMP header DOS attempt" },
89     { DECODE_ICMP4_HDR_TRUNC, "truncated ICMP4 header" },
90     { 0, nullptr }
91 };
92 
93 class Icmp4Module : public BaseCodecModule
94 {
95 public:
Icmp4Module()96     Icmp4Module() : BaseCodecModule(CD_ICMP4_NAME, CD_ICMP4_HELP) { }
97 
get_rules() const98     const RuleMap* get_rules() const override
99     { return icmp4_rules; }
100 
get_pegs() const101     const PegInfo* get_pegs() const override
102     { return pegs; }
103 
get_counts() const104     PegCount* get_counts() const override
105     { return (PegCount*)&stats; }
106 };
107 
108 class Icmp4Codec : public Codec
109 {
110 public:
Icmp4Codec()111     Icmp4Codec() : Codec(CD_ICMP4_NAME) { }
112 
113     void get_protocol_ids(std::vector<ProtocolId>&) override;
114     bool decode(const RawData&, CodecData&, DecodeData&) override;
115     void update(const ip::IpApi&, const EncodeFlags, uint8_t* raw_pkt,
116         uint16_t lyr_len, uint32_t& updated_len) override;
117     void format(bool reverse, uint8_t* raw_pkt, DecodeData& snort) override;
118     void log(TextLog* const, const uint8_t* pkt, const uint16_t len) override;
119 
120 private:
121     bool valid_checksum_from_daq(const RawData&);
122     void ICMP4AddrTests(const DecodeData& snort, const CodecData& codec);
123     void ICMP4MiscTests(const ICMPHdr* const, const CodecData&, const uint16_t);
124 };
125 } // namespace
126 
get_protocol_ids(std::vector<ProtocolId> & v)127 void Icmp4Codec::get_protocol_ids(std::vector<ProtocolId>& v)
128 { v.emplace_back(ProtocolId::ICMPV4); }
129 
valid_checksum_from_daq(const RawData & raw)130 inline bool Icmp4Codec::valid_checksum_from_daq(const RawData& raw)
131 {
132     const DAQ_PktDecodeData_t* pdd =
133         (const DAQ_PktDecodeData_t*) daq_msg_get_meta(raw.daq_msg, DAQ_PKT_META_DECODE_DATA);
134     if (!pdd || !pdd->flags.bits.l4_checksum || !pdd->flags.bits.icmp || !pdd->flags.bits.l4)
135         return false;
136     // Sanity check to make sure we're talking about the same thing if offset is available
137     if (pdd->l4_offset != DAQ_PKT_DECODE_OFFSET_INVALID)
138     {
139         const uint8_t* data = daq_msg_get_data(raw.daq_msg);
140         if (raw.data - data != pdd->l4_offset)
141             return false;
142     }
143     stats.cksum_bypassed++;
144     return true;
145 }
146 
decode(const RawData & raw,CodecData & codec,DecodeData & snort)147 bool Icmp4Codec::decode(const RawData& raw, CodecData& codec,DecodeData& snort)
148 {
149     if (raw.len < icmp::ICMP_BASE_LEN)
150     {
151         codec_event(codec, DECODE_ICMP4_HDR_TRUNC);
152         return false;
153     }
154 
155     /* set the header ptr first */
156     const ICMPHdr* const icmph = reinterpret_cast<const ICMPHdr*>(raw.data);
157     uint16_t len = 0;
158 
159     if (snort::get_network_policy()->icmp_checksums() && !valid_checksum_from_daq(raw))
160     {
161         uint16_t csum = checksum::cksum_add((const uint16_t*)icmph, raw.len);
162 
163         if (csum && !codec.is_cooked())
164         {
165             stats.bad_ip4_cksum++;
166             snort.decode_flags |= DECODE_ERR_CKSUM_ICMP;
167             return false;
168         }
169     }
170 
171     switch (icmph->type)
172     {
173     // fall through ...
174     case icmp::IcmpType::SOURCE_QUENCH:
175     case icmp::IcmpType::DEST_UNREACH:
176     case icmp::IcmpType::REDIRECT:
177     case icmp::IcmpType::TIME_EXCEEDED:
178     case icmp::IcmpType::PARAMETERPROB:
179     case icmp::IcmpType::ECHOREPLY:
180     case icmp::IcmpType::ECHO_4:
181     case icmp::IcmpType::ROUTER_ADVERTISE:
182     case icmp::IcmpType::ROUTER_SOLICIT:
183     case icmp::IcmpType::INFO_REQUEST:
184     case icmp::IcmpType::INFO_REPLY:
185         if (raw.len < 8)
186         {
187             codec_event(codec, DECODE_ICMP_DGRAM_LT_ICMPHDR);
188             return false;
189         }
190         break;
191 
192     case icmp::IcmpType::TIMESTAMP:
193     case icmp::IcmpType::TIMESTAMPREPLY:
194         if (raw.len < 20)
195         {
196             codec_event(codec, DECODE_ICMP_DGRAM_LT_TIMESTAMPHDR);
197             return false;
198         }
199         break;
200 
201     case icmp::IcmpType::ADDRESS:
202     case icmp::IcmpType::ADDRESSREPLY:
203         if (raw.len < 12)
204         {
205             codec_event(codec, DECODE_ICMP_DGRAM_LT_ADDRHDR);
206             return false;
207         }
208         break;
209 
210     default:
211         codec_event(codec, DECODE_ICMP4_TYPE_OTHER);
212         break;
213     }
214 
215     len =  icmp::ICMP_BASE_LEN;
216 
217     switch (icmph->type)
218     {
219     case icmp::IcmpType::ECHO_4:
220         ICMP4AddrTests(snort, codec);
221     // fall through ...
222 
223     case icmp::IcmpType::ECHOREPLY:
224         /* setup the pkt id and seq numbers */
225         /* add the size of the echo ext to the data
226          * ptr and subtract it from the data size */
227         len += sizeof(ICMPHdr::icmp_hun.idseq);
228         break;
229 
230     case icmp::IcmpType::DEST_UNREACH:
231         if ((icmph->code == icmp::IcmpCode::FRAG_NEEDED)
232             && (ntohs(icmph->s_icmp_nextmtu) < 576))
233         {
234             codec_event(codec, DECODE_ICMP_PATH_MTU_DOS);
235         }
236 
237     /* Fall through */
238 
239     case icmp::IcmpType::SOURCE_QUENCH:
240     case icmp::IcmpType::REDIRECT:
241     case icmp::IcmpType::TIME_EXCEEDED:
242     case icmp::IcmpType::PARAMETERPROB:
243         /* account for extra 4 bytes in header */
244         len += 4;
245         codec.next_prot_id = ProtocolId::IP_EMBEDDED_IN_ICMP4;
246         break;
247 
248     default:
249         break;
250     }
251 
252     ICMP4MiscTests(icmph, codec, (uint16_t)raw.len - len);
253 
254     snort.set_pkt_type(PktType::ICMP);
255     snort.icmph = icmph;
256     codec.proto_bits |= PROTO_BIT__ICMP;
257     codec.lyr_len = len;
258     return true;
259 }
260 
ICMP4AddrTests(const DecodeData & snort,const CodecData & codec)261 void Icmp4Codec::ICMP4AddrTests(const DecodeData& snort, const CodecData& codec)
262 {
263     uint32_t dst = snort.ip_api.get_dst()->get_ip4_value();
264 
265     // check all 32 bits; all set so byte order is irrelevant ...
266     if ( dst == ip::IP4_BROADCAST )
267         codec_event(codec, DECODE_ICMP4_DST_BROADCAST);
268 
269     /* - don't use htonl for speed reasons -
270      * s_addr is always in network order */
271 #ifdef WORDS_BIGENDIAN
272     uint8_t msb_dst = (uint8_t)(dst >> 24);
273 #else
274     uint8_t msb_dst = (uint8_t)(dst & 0xff);
275 #endif
276 
277     // check the 'msn' (most significant nibble) ...
278     msb_dst >>= 4;
279 
280     if ( msb_dst == ip::IP4_MULTICAST )
281         codec_event(codec, DECODE_ICMP4_DST_MULTICAST);
282 }
283 
ICMP4MiscTests(const ICMPHdr * const icmph,const CodecData & codec,const uint16_t dsize)284 void Icmp4Codec::ICMP4MiscTests(const ICMPHdr* const icmph,
285     const CodecData& codec,
286     const uint16_t dsize)
287 {
288     if ((dsize == 0) &&
289         (icmph->type == icmp::IcmpType::ECHO_4))
290         codec_event(codec, DECODE_ICMP_PING_NMAP);
291 
292     if ((dsize == 0) &&
293         (icmph->s_icmp_seq == 666))
294         codec_event(codec, DECODE_ICMP_ICMPENUM);
295 
296     if ((icmph->type == icmp::IcmpType::REDIRECT) &&
297         (icmph->code == icmp::IcmpCode::REDIR_HOST))
298         codec_event(codec, DECODE_ICMP_REDIRECT_HOST);
299 
300     if ((icmph->type == icmp::IcmpType::REDIRECT) &&
301         (icmph->code == icmp::IcmpCode::REDIR_NET))
302         codec_event(codec, DECODE_ICMP_REDIRECT_NET);
303 
304     if ((icmph->type == icmp::IcmpType::ECHOREPLY) &&
305         (codec.codec_flags & CODEC_IPOPT_RR_SEEN))
306         codec_event(codec, DECODE_ICMP_TRACEROUTE_IPOPTS);
307 
308     if ((icmph->type == icmp::IcmpType::SOURCE_QUENCH) &&
309         (icmph->code == icmp::IcmpCode::SOURCE_QUENCH_CODE))
310         codec_event(codec, DECODE_ICMP_SOURCE_QUENCH);
311 
312     if ((dsize == 4) &&
313         (icmph->type == icmp::IcmpType::ECHO_4) &&
314         (icmph->s_icmp_seq == 0) &&
315         (icmph->code == icmp::IcmpCode::ECHO_CODE))
316         codec_event(codec, DECODE_ICMP_BROADSCAN_SMURF_SCANNER);
317 
318     if ((icmph->type == icmp::IcmpType::DEST_UNREACH) &&
319         (icmph->code == icmp::IcmpCode::PKT_FILTERED))
320         codec_event(codec, DECODE_ICMP_DST_UNREACH_ADMIN_PROHIBITED);
321 
322     if ((icmph->type == icmp::IcmpType::DEST_UNREACH) &&
323         (icmph->code == icmp::IcmpCode::PKT_FILTERED_HOST))
324         codec_event(codec, DECODE_ICMP_DST_UNREACH_DST_HOST_PROHIBITED);
325 
326     if ((icmph->type == icmp::IcmpType::DEST_UNREACH) &&
327         (icmph->code == icmp::IcmpCode::PKT_FILTERED_NET))
328         codec_event(codec, DECODE_ICMP_DST_UNREACH_DST_NET_PROHIBITED);
329 }
330 
331 /******************************************************************
332  *************************  L O G G E R  **************************
333  ******************************************************************/
334 
log(TextLog * const log,const uint8_t * raw_pkt,const uint16_t)335 void Icmp4Codec::log(TextLog* const log, const uint8_t* raw_pkt,
336     const uint16_t)
337 {
338     const icmp::ICMPHdr* const icmph = reinterpret_cast<const ICMPHdr*>(raw_pkt);
339 
340     /* 32 digits plus 7 colons and a null byte */
341     char buf[8*4 + 7 + 1];
342     TextLog_Print(log, "Type:%d  Code:%d  ", icmph->type, icmph->code);
343     TextLog_Puts(log, "\n\t");
344 
345     switch (icmph->type)
346     {
347     case icmp::IcmpType::ECHOREPLY:
348         TextLog_Print(log, "ID:%d  Seq:%d  ", ntohs(icmph->s_icmp_id),
349             ntohs(icmph->s_icmp_seq));
350         TextLog_Puts(log, "ECHO REPLY");
351         break;
352 
353     case icmp::IcmpType::DEST_UNREACH:
354         TextLog_Puts(log, "DESTINATION UNREACHABLE: ");
355         switch (icmph->code)
356         {
357         case icmp::IcmpCode::NET_UNREACH:
358             TextLog_Puts(log, "NET UNREACHABLE");
359             break;
360 
361         case icmp::IcmpCode::HOST_UNREACH:
362             TextLog_Puts(log, "HOST UNREACHABLE");
363             break;
364 
365         case icmp::IcmpCode::PROT_UNREACH:
366             TextLog_Puts(log, "PROTOCOL UNREACHABLE");
367             break;
368 
369         case icmp::IcmpCode::PORT_UNREACH:
370             TextLog_Puts(log, "PORT UNREACHABLE");
371             break;
372 
373         case icmp::IcmpCode::FRAG_NEEDED:
374             TextLog_Print(log, "FRAGMENTATION NEEDED, DF SET,"
375                 " NEXT LINK MTU: %u",
376                 ntohs(icmph->s_icmp_nextmtu));
377             break;
378 
379         case icmp::IcmpCode::SR_FAILED:
380             TextLog_Puts(log, "SOURCE ROUTE FAILED");
381             break;
382 
383         case icmp::IcmpCode::NET_UNKNOWN:
384             TextLog_Puts(log, "NET UNKNOWN");
385             break;
386 
387         case icmp::IcmpCode::HOST_UNKNOWN:
388             TextLog_Puts(log, "HOST UNKNOWN");
389             break;
390 
391         case icmp::IcmpCode::HOST_ISOLATED:
392             TextLog_Puts(log, "HOST ISOLATED");
393             break;
394 
395         case icmp::IcmpCode::PKT_FILTERED_NET:
396             TextLog_Puts(log, "ADMINISTRATIVELY PROHIBITED NETWORK FILTERED");
397             break;
398 
399         case icmp::IcmpCode::PKT_FILTERED_HOST:
400             TextLog_Puts(log, "ADMINISTRATIVELY PROHIBITED HOST FILTERED");
401             break;
402 
403         case icmp::IcmpCode::NET_UNR_TOS:
404             TextLog_Puts(log, "NET UNREACHABLE FOR TOS");
405             break;
406 
407         case icmp::IcmpCode::HOST_UNR_TOS:
408             TextLog_Puts(log, "HOST UNREACHABLE FOR TOS");
409             break;
410 
411         case icmp::IcmpCode::PKT_FILTERED:
412             TextLog_Puts(log, "ADMINISTRATIVELY PROHIBITED, PACKET FILTERED");
413             break;
414 
415         case icmp::IcmpCode::PREC_VIOLATION:
416             TextLog_Puts(log, "PREC VIOLATION");
417             break;
418 
419         case icmp::IcmpCode::PREC_CUTOFF:
420             TextLog_Puts(log, "PREC CUTOFF");
421             break;
422 
423         default:
424             TextLog_Puts(log, "UNKNOWN");
425             break;
426         }
427         break;
428 
429     case icmp::IcmpType::SOURCE_QUENCH:
430         TextLog_Puts(log, "SOURCE QUENCH");
431         break;
432 
433     case icmp::IcmpType::REDIRECT:
434         TextLog_Puts(log, "REDIRECT");
435         switch (icmph->code)
436         {
437         case icmp::IcmpCode::REDIR_NET:
438             TextLog_Puts(log, " NET");
439             break;
440 
441         case icmp::IcmpCode::REDIR_HOST:
442             TextLog_Puts(log, " HOST");
443             break;
444 
445         case icmp::IcmpCode::REDIR_TOS_NET:
446             TextLog_Puts(log, " TOS NET");
447             break;
448 
449         case icmp::IcmpCode::REDIR_TOS_HOST:
450             TextLog_Puts(log, " TOS HOST");
451             break;
452 
453         default:
454             break;
455         }
456 
457         snort_inet_ntop(AF_INET, (const void*)(&icmph->s_icmp_gwaddr.s_addr),
458             buf, sizeof(buf));
459         TextLog_Print(log, " NEW GW: %s", buf);
460         break;
461 
462     case icmp::IcmpType::ECHO_4:
463         TextLog_Print(log, "ID:%d   Seq:%d  ", ntohs(icmph->s_icmp_id),
464             ntohs(icmph->s_icmp_seq));
465         TextLog_Puts(log, "ECHO");
466         break;
467 
468     case icmp::IcmpType::ROUTER_ADVERTISE:
469         TextLog_Print(log, "ROUTER ADVERTISEMENT: "
470             "Num addrs: %d Addr entry size: %d Lifetime: %u",
471             icmph->s_icmp_num_addrs, icmph->s_icmp_wpa,
472             ntohs(icmph->s_icmp_lifetime));
473         break;
474 
475     case icmp::IcmpType::ROUTER_SOLICIT:
476         TextLog_Puts(log, "ROUTER SOLICITATION");
477         break;
478 
479     case icmp::IcmpType::TIME_EXCEEDED:
480         TextLog_Puts(log, "TTL EXCEEDED");
481         switch (icmph->code)
482         {
483         case icmp::IcmpCode::TIMEOUT_TRANSIT:
484             TextLog_Puts(log, " IN TRANSIT");
485             break;
486 
487         case icmp::IcmpCode::TIMEOUT_REASSY:
488             TextLog_Puts(log, " TIME EXCEEDED IN FRAG REASSEMBLY");
489             break;
490 
491         default:
492             break;
493         }
494 
495         break;
496 
497     case icmp::IcmpType::PARAMETERPROB:
498         TextLog_Puts(log, "PARAMETER PROBLEM");
499         switch (icmph->code)
500         {
501         case icmp::IcmpCode::PARAM_BADIPHDR:
502             TextLog_Print(log, ": BAD IP HEADER BYTE %u",
503                 icmph->s_icmp_pptr);
504             break;
505 
506         case icmp::IcmpCode::PARAM_OPTMISSING:
507             TextLog_Puts(log, ": OPTION MISSING");
508             break;
509 
510         case icmp::IcmpCode::PARAM_BAD_LENGTH:
511             TextLog_Puts(log, ": BAD LENGTH");
512             break;
513 
514         default:
515             break;
516         }
517 
518         break;
519 
520     case icmp::IcmpType::TIMESTAMP:
521         TextLog_Print(log, "ID: %u  Seq: %u  TIMESTAMP REQUEST",
522             ntohs(icmph->s_icmp_id), ntohs(icmph->s_icmp_seq));
523         break;
524 
525     case icmp::IcmpType::TIMESTAMPREPLY:
526         TextLog_Print(log, "ID: %u  Seq: %u  TIMESTAMP REPLY: "
527             "Orig: %u Rtime: %u  Ttime: %u",
528             ntohs(icmph->s_icmp_id), ntohs(icmph->s_icmp_seq),
529             icmph->s_icmp_otime, icmph->s_icmp_rtime,
530             icmph->s_icmp_ttime);
531         break;
532 
533     case icmp::IcmpType::INFO_REQUEST:
534         TextLog_Print(log, "ID: %u  Seq: %u  INFO REQUEST",
535             ntohs(icmph->s_icmp_id), ntohs(icmph->s_icmp_seq));
536         break;
537 
538     case icmp::IcmpType::INFO_REPLY:
539         TextLog_Print(log, "ID: %u  Seq: %u  INFO REPLY",
540             ntohs(icmph->s_icmp_id), ntohs(icmph->s_icmp_seq));
541         break;
542 
543     case icmp::IcmpType::ADDRESS:
544         TextLog_Print(log, "ID: %u  Seq: %u  ADDRESS REQUEST",
545             ntohs(icmph->s_icmp_id), ntohs(icmph->s_icmp_seq));
546         break;
547 
548     case icmp::IcmpType::ADDRESSREPLY:
549         TextLog_Print(log, "ID: %u  Seq: %u  ADDRESS REPLY: 0x%08X",
550             ntohs(icmph->s_icmp_id), ntohs(icmph->s_icmp_seq),
551             ntohl(icmph->s_icmp_mask));
552         break;
553 
554     default:
555         TextLog_Puts(log, "UNKNOWN");
556         break;
557     }
558 }
559 
560 /******************************************************************
561  ******************** E N C O D E R  ******************************
562  ******************************************************************/
563 
564 namespace
565 {
566 struct IcmpHdr
567 {
568     uint8_t type;
569     uint8_t code;
570     uint16_t cksum;
571     uint32_t unused;
572 };
573 } // namespace
574 
update(const ip::IpApi &,const EncodeFlags flags,uint8_t * raw_pkt,uint16_t lyr_len,uint32_t & updated_len)575 void Icmp4Codec::update(const ip::IpApi&, const EncodeFlags flags,
576     uint8_t* raw_pkt, uint16_t lyr_len, uint32_t& updated_len)
577 {
578     IcmpHdr* h = reinterpret_cast<IcmpHdr*>(raw_pkt);
579     updated_len += lyr_len;
580 
581     if ( !(flags & UPD_COOKED) || (flags & UPD_REBUILT_FRAG) )
582     {
583         h->cksum = 0;
584         h->cksum = checksum::icmp_cksum((uint16_t*)h, updated_len);
585     }
586 }
587 
format(bool,uint8_t * raw_pkt,DecodeData & snort)588 void Icmp4Codec::format(bool /*reverse*/, uint8_t* raw_pkt, DecodeData& snort)
589 {
590     // FIXIT-L handle nested icmp4 layers
591     snort.icmph = reinterpret_cast<ICMPHdr*>(raw_pkt);
592     snort.set_pkt_type(PktType::ICMP);
593 }
594 
595 //-------------------------------------------------------------------------
596 // api
597 //-------------------------------------------------------------------------
598 
mod_ctor()599 static Module* mod_ctor()
600 { return new Icmp4Module; }
601 
mod_dtor(Module * m)602 static void mod_dtor(Module* m)
603 { delete m; }
604 
ctor(Module *)605 static Codec* ctor(Module*)
606 { return new Icmp4Codec(); }
607 
dtor(Codec * cd)608 static void dtor(Codec* cd)
609 { delete cd; }
610 
611 static const CodecApi icmp4_api =
612 {
613     {
614         PT_CODEC,
615         sizeof(CodecApi),
616         CDAPI_VERSION,
617         0,
618         API_RESERVED,
619         API_OPTIONS,
620         CD_ICMP4_NAME,
621         CD_ICMP4_HELP,
622         mod_ctor,
623         mod_dtor
624     },
625     nullptr, // pinit
626     nullptr, // pterm
627     nullptr, // tinit
628     nullptr, // tterm
629     ctor, // ctor
630     dtor, // dtor
631 };
632 
633 #ifdef BUILDING_SO
634 SO_PUBLIC const BaseApi* snort_plugins[] =
635 #else
636 const BaseApi* cd_icmp4[] =
637 #endif
638 {
639     &icmp4_api.base,
640     nullptr
641 };
642 
643