1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2005-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 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "norm.h"
25 
26 #include "detection/ips_context.h"
27 #include "main/snort_config.h"
28 #include "packet_io/sfdaq.h"
29 #include "protocols/icmp4.h"
30 #include "protocols/icmp6.h"
31 #include "protocols/ipv4_options.h"
32 #include "protocols/tcp.h"
33 #include "protocols/tcp_options.h"
34 #include "stream/tcp/tcp_normalizer.h"
35 
36 using namespace snort;
37 
38 enum PegCounts
39 {
40     PC_IP4_TRIM,
41     PC_IP4_TOS,
42     PC_IP4_DF,
43     PC_IP4_RF,
44     PC_IP4_TTL,
45     PC_IP4_OPTS,
46     PC_ICMP4_ECHO,
47     PC_IP6_TTL,
48     PC_IP6_OPTS,
49     PC_ICMP6_ECHO,
50     PC_TCP_SYN_OPT,
51     PC_TCP_OPT,
52     PC_TCP_PAD,
53     PC_TCP_RSV,
54     PC_TCP_NS,
55     PC_TCP_URP,
56     PC_TCP_ECN_PKT,
57     PC_TCP_TS_ECR,
58     PC_TCP_REQ_URG,
59     PC_TCP_REQ_PAY,
60     PC_TCP_REQ_URP,
61     PC_MAX
62 };
63 
64 const PegInfo norm_names[] =
65 {
66     { CountType::SUM, "ip4_trim", "eth packets trimmed to datagram size" },
67     { CountType::SUM, "ip4_tos", "type of service normalizations" },
68     { CountType::SUM, "ip4_df", "don't frag bit normalizations" },
69     { CountType::SUM, "ip4_rf", "reserved flag bit clears" },
70     { CountType::SUM, "ip4_ttl", "time-to-live normalizations" },
71     { CountType::SUM, "ip4_opts", "ip4 options cleared" },
72     { CountType::SUM, "icmp4_echo", "icmp4 ping normalizations" },
73     { CountType::SUM, "ip6_hops", "ip6 hop limit normalizations" },
74     { CountType::SUM, "ip6_options", "ip6 options cleared" },
75     { CountType::SUM, "icmp6_echo", "icmp6 echo normalizations" },
76     { CountType::SUM, "tcp_syn_options", "SYN only options cleared from non-SYN packets" },
77     { CountType::SUM, "tcp_options", "packets with options cleared" },
78     { CountType::SUM, "tcp_padding", "packets with padding cleared" },
79     { CountType::SUM, "tcp_reserved", "packets with reserved bits cleared" },
80     { CountType::SUM, "tcp_nonce", "packets with nonce bit cleared" },
81     { CountType::SUM, "tcp_urgent_ptr", "packets without data with urgent pointer cleared" },
82     { CountType::SUM, "tcp_ecn_pkt", "packets with ECN bits cleared" },
83     { CountType::SUM, "tcp_ts_ecr", "timestamp cleared on non-ACKs" },
84     { CountType::SUM, "tcp_req_urg", "cleared urgent pointer when urgent flag is not set" },
85     { CountType::SUM, "tcp_req_pay",
86         "cleared urgent pointer and urgent flag when there is no payload" },
87     { CountType::SUM, "tcp_req_urp", "cleared the urgent flag if the urgent pointer is not set" },
88     { CountType::END, nullptr, nullptr }
89 };
90 
91 static THREAD_LOCAL PegCount normStats[PC_MAX+PC_TCP_MAX][NORM_MODE_MAX];
92 
93 //static int Norm_Eth(Packet*, uint8_t layer, int changes);
94 static int Norm_IP4(NormalizerConfig*, Packet*, uint8_t layer, int changes);
95 static int Norm_ICMP4(NormalizerConfig*, Packet*, uint8_t layer, int changes);
96 static int Norm_IP6(NormalizerConfig*, Packet*, uint8_t layer, int changes);
97 static int Norm_ICMP6(NormalizerConfig*, Packet*, uint8_t layer, int changes);
98 static int Norm_IP6_Opts(NormalizerConfig*, Packet*, uint8_t layer, int changes);
99 //static int Norm_UDP(NormalizerConfig*, Packet*, uint8_t layer, int changes);
100 static int Norm_TCP(NormalizerConfig*, Packet*, uint8_t layer, int changes);
101 
102 static const uint8_t MAX_EOL_PAD[TCP_OPTLENMAX] =
103 {
104     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
106 };
107 
108 // go from inner to outer
Norm_Packet(NormalizerConfig * c,Packet * p)109 int Norm_Packet(NormalizerConfig* c, Packet* p)
110 {
111     uint8_t lyr = p->num_layers;
112     int changes = 0;
113 
114     while ( lyr > 0 )
115     {
116         ProtocolId proto_id = p->layers[--lyr].prot_id;
117         NormalFunc n = c->normalizers[PacketManager::proto_idx(proto_id)];
118 
119         if ( n )
120             changes = n(c, p, lyr, changes);
121     }
122 
123     if ( changes > 0 )
124     {
125         p->packet_flags |= PKT_MODIFIED;
126         return 1;
127     }
128     if ( p->packet_flags & (PKT_RESIZED|PKT_MODIFIED) )
129     {
130         return 1;
131     }
132     return 0;
133 }
134 
135 //-----------------------------------------------------------------------
136 // in the following code, we mostly use the actual packet data and the
137 // packet layers[].  use of other decoded packet members is largely
138 // avoided to ensure that we don't get tripped up by nested protocols.
139 // TCP options count and length are a notable exception.
140 //
141 // also note that checksums are not calculated here.  they are only
142 // calculated once after all normalizations are done (here, stream)
143 // and any replacements are made.
144 //-----------------------------------------------------------------------
145 
146 #if 0
147 static int Norm_Eth(Packet* p, uint8_t layer, int changes)
148 {
149     return 0;
150 }
151 
152 #endif
153 
154 //-----------------------------------------------------------------------
155 
156 #define IP4_FLAG_RF 0x8000
157 #define IP4_FLAG_DF 0x4000
158 #define IP4_FLAG_MF 0x2000
159 
160 // TBD support configurable minimum length / obtain from DAQ
161 // ether header + min payload (excludes FCS, which makes it 64 total)
162 #define ETH_MIN_LEN 60
163 
get_norm_mode(const Packet * const p)164 static inline NormMode get_norm_mode(const Packet * const p)
165 {
166     NormMode mode = NORM_MODE_ON;
167 
168     if ( get_inspection_policy()->policy_mode != POLICY_MODE__INLINE )
169         mode = NORM_MODE_TEST;
170 
171     if ( !SFDAQ::forwarding_packet(p->pkth) )
172         mode = NORM_MODE_TEST;
173 
174     return mode;
175 }
176 
Norm_IP4(NormalizerConfig * c,Packet * p,uint8_t layer,int changes)177 static int Norm_IP4(
178     NormalizerConfig* c, Packet* p, uint8_t layer, int changes)
179 {
180     ip::IP4Hdr* h = (ip::IP4Hdr*)const_cast<uint8_t*>(p->layers[layer].start);
181     uint16_t fragbits = ntohs(h->ip_off);
182     uint16_t origbits = fragbits;
183     const NormMode mode = get_norm_mode(p);
184 
185     if ( Norm_IsEnabled(c, NORM_IP4_TRIM) && (layer == 1) )
186     {
187         uint32_t len = p->layers[0].length + ntohs(h->ip_len);
188 
189         if ( (len < p->pkth->pktlen) &&
190             ((len >= ETH_MIN_LEN) || (p->pkth->pktlen > ETH_MIN_LEN)) )
191         {
192             if ( mode == NORM_MODE_ON )
193             {
194                 (const_cast<DAQ_PktHdr_t*>(p->pkth))->pktlen =
195                     (len < ETH_MIN_LEN) ? ETH_MIN_LEN : len;
196 
197                 p->packet_flags |= PKT_RESIZED;
198                 changes++;
199             }
200             normStats[PC_IP4_TRIM][mode]++;
201         }
202     }
203     if ( Norm_IsEnabled(c, NORM_IP4_TOS) )
204     {
205         if ( h->ip_tos )
206         {
207             if ( mode == NORM_MODE_ON )
208             {
209                 h->ip_tos = 0;
210                 changes++;
211             }
212             normStats[PC_IP4_TOS][mode]++;
213         }
214     }
215 #if 0
216     if ( Norm_IsEnabled(c, NORM_IP4_ID) )
217     {
218         // TBD implement IP ID normalization / randomization
219     }
220 #endif
221     if ( Norm_IsEnabled(c, NORM_IP4_DF) )
222     {
223         if ( fragbits & IP4_FLAG_DF )
224         {
225             if ( mode == NORM_MODE_ON )
226             {
227                 fragbits &= ~IP4_FLAG_DF;
228                 changes++;
229             }
230             normStats[PC_IP4_DF][mode]++;
231         }
232     }
233     if ( Norm_IsEnabled(c, NORM_IP4_RF) )
234     {
235         if ( fragbits & IP4_FLAG_RF )
236         {
237             if ( mode == NORM_MODE_ON )
238             {
239                 fragbits &= ~IP4_FLAG_RF;
240                 changes++;
241             }
242             normStats[PC_IP4_RF][mode]++;
243         }
244     }
245     if ( fragbits != origbits )
246     {
247         h->ip_off = htons(fragbits);
248     }
249     if ( Norm_IsEnabled(c, NORM_IP4_TTL) )
250     {
251         if ( h->ip_ttl < p->context->conf->min_ttl() )
252         {
253             if ( mode == NORM_MODE_ON )
254             {
255                 h->ip_ttl = p->context->conf->new_ttl();
256                 p->ptrs.decode_flags &= ~DECODE_ERR_BAD_TTL;
257                 changes++;
258             }
259             normStats[PC_IP4_TTL][mode]++;
260         }
261     }
262     if ( p->layers[layer].length > ip::IP4_HEADER_LEN )
263     {
264         if ( mode == NORM_MODE_ON )
265         {
266             uint8_t* opts = const_cast<uint8_t*>(p->layers[layer].start) + ip::IP4_HEADER_LEN;
267             uint8_t len = p->layers[layer].length - ip::IP4_HEADER_LEN;
268             // expect len > 0 because IHL yields a multiple of 4
269             memset(opts, static_cast<uint8_t>(ip::IPOptionCodes::NOP), len);
270             changes++;
271         }
272         normStats[PC_IP4_OPTS][mode]++;
273     }
274     return changes;
275 }
276 
277 //-----------------------------------------------------------------------
278 
Norm_ICMP4(NormalizerConfig *,Packet * p,uint8_t layer,int changes)279 static int Norm_ICMP4(
280     NormalizerConfig*, Packet* p, uint8_t layer, int changes)
281 {
282     ICMPHdr* h = reinterpret_cast<ICMPHdr*>(const_cast<uint8_t*>(p->layers[layer].start));
283     const NormMode mode = get_norm_mode(p);
284 
285     if ( (h->type == ICMP_ECHO || h->type == ICMP_ECHOREPLY) &&
286         (h->code != icmp::IcmpCode::ECHO_CODE) )
287     {
288         if ( mode == NORM_MODE_ON )
289         {
290             h->code = icmp::IcmpCode::ECHO_CODE;
291             changes++;
292         }
293         normStats[PC_ICMP4_ECHO][mode]++;
294     }
295     return changes;
296 }
297 
298 //-----------------------------------------------------------------------
299 
Norm_IP6(NormalizerConfig * c,Packet * p,uint8_t layer,int changes)300 static int Norm_IP6(
301     NormalizerConfig* c, Packet* p, uint8_t layer, int changes)
302 {
303     if ( Norm_IsEnabled(c, NORM_IP6_TTL) )
304     {
305         ip::IP6Hdr* h =
306             reinterpret_cast<ip::IP6Hdr*>(const_cast<uint8_t*>(p->layers[layer].start));
307 
308         if ( h->ip6_hoplim < p->context->conf->min_ttl() )
309         {
310             const NormMode mode = get_norm_mode(p);
311 
312             if ( mode == NORM_MODE_ON )
313             {
314                 h->ip6_hoplim = p->context->conf->new_ttl();
315                 p->ptrs.decode_flags &= ~DECODE_ERR_BAD_TTL;
316                 changes++;
317             }
318             normStats[PC_IP6_TTL][mode]++;
319         }
320     }
321     return changes;
322 }
323 
324 //-----------------------------------------------------------------------
325 
Norm_ICMP6(NormalizerConfig *,Packet * p,uint8_t layer,int changes)326 static int Norm_ICMP6(
327     NormalizerConfig*, Packet* p, uint8_t layer, int changes)
328 {
329     ICMPHdr* h = reinterpret_cast<ICMPHdr*>(const_cast<uint8_t*>(p->layers[layer].start));
330 
331     if ( ((uint16_t)h->type == icmp::Icmp6Types::ECHO_REQUEST ||
332         (uint16_t)h->type == icmp::Icmp6Types::ECHO_REPLY) &&
333         (h->code != 0) )
334     {
335         const NormMode mode = get_norm_mode(p);
336 
337         if ( mode == NORM_MODE_ON )
338         {
339             h->code = static_cast<icmp::IcmpCode>(0);
340             changes++;
341         }
342         normStats[PC_ICMP6_ECHO][mode]++;
343     }
344     return changes;
345 }
346 
347 //-----------------------------------------------------------------------
348 // we assume here that the decoder has not pushed ip6 option extension
349 // headers unless the basic sizing is correct (size = N*8 octets, N>0).
350 
351 struct ExtOpt
352 {
353     uint8_t next;
354     uint8_t xlen;
355     uint8_t type;
356     uint8_t olen;
357 };
358 
359 #define IP6_OPT_PAD_N 1
360 
Norm_IP6_Opts(NormalizerConfig *,Packet * p,uint8_t layer,int changes)361 static int Norm_IP6_Opts(
362     NormalizerConfig*, Packet* p, uint8_t layer, int changes)
363 {
364     NormMode mode = get_norm_mode(p);
365 
366     if ( mode == NORM_MODE_ON )
367     {
368         uint8_t* b = const_cast<uint8_t*>(p->layers[layer].start);
369         ExtOpt* x = reinterpret_cast<ExtOpt*>(b);
370 
371         // whatever was here, turn it into one PADN option
372         x->type = IP6_OPT_PAD_N;
373         x->olen = (x->xlen * 8) + 8 - sizeof(*x);
374         memset(b+sizeof(*x), 0, x->olen);
375 
376         changes++;
377     }
378     normStats[PC_IP6_OPTS][mode]++;
379     return changes;
380 }
381 
382 //-----------------------------------------------------------------------
383 
384 #if 0
385 static int Norm_UDP(Packet* p, uint8_t layer, int changes)
386 {
387     return 0;
388 }
389 
390 #endif
391 
392 //-----------------------------------------------------------------------
393 
NopDaOpt(uint8_t * opt,uint8_t len)394 static inline void NopDaOpt(uint8_t* opt, uint8_t len)
395 {
396     memset(opt, (uint8_t)tcp::TcpOptCode::NOP, len);
397 }
398 
399 #define TS_ECR_OFFSET 6
400 #define TS_ECR_LENGTH 4
401 
Norm_TCPOptions(NormalizerConfig * config,const NormMode mode,uint8_t * opts,size_t len,const tcp::TCPHdr * h,uint8_t validated_len,int changes)402 static inline int Norm_TCPOptions(NormalizerConfig* config, const NormMode mode,
403     uint8_t* opts, size_t len, const tcp::TCPHdr* h, uint8_t validated_len, int changes)
404 {
405     size_t i = 0;
406 
407     while ( (i < len) &&
408         (opts[i] != (uint8_t)tcp::TcpOptCode::EOL) &&
409         (i < validated_len) )
410     {
411         uint8_t olen = ( opts[i] <= 1 ) ? 1 : opts[i+1];
412 
413         // we know that the first numOpts options have valid lengths
414         // so we should not need to check individual or total option lengths.
415         // however, we keep this as a sanity check.
416         if ( i + olen > len)
417             break;
418 
419         switch ( static_cast<tcp::TcpOptCode>(opts[i]) )
420         {
421         case tcp::TcpOptCode::NOP:
422             break;
423 
424         case tcp::TcpOptCode::MAXSEG:
425         case tcp::TcpOptCode::WSCALE:
426             if ( !(h->th_flags & TH_SYN) )
427             {
428                 if ( mode == NORM_MODE_ON )
429                 {
430                     NopDaOpt(opts+i, olen);
431                     changes++;
432                 }
433                 normStats[PC_TCP_SYN_OPT][mode]++;
434             }
435             break;
436 
437         case tcp::TcpOptCode::TIMESTAMP:
438             if ( !(h->th_flags & TH_ACK) &&
439                 // use memcmp because opts have arbitrary alignment
440                 memcmp(opts+i+TS_ECR_OFFSET, MAX_EOL_PAD, TS_ECR_LENGTH) )
441             {
442                 if ( mode == NORM_MODE_ON )
443                 {
444                     // TSecr should be zero unless ACK is set
445                     memset(opts+i+TS_ECR_OFFSET, 0, TS_ECR_LENGTH);
446                     changes++;
447                 }
448                 normStats[PC_TCP_TS_ECR][mode]++;
449             }
450             break;
451 
452         default:
453             if ( !Norm_TcpIsOptional(config, opts[i]) )
454             {
455                 if ( mode == NORM_MODE_ON )
456                 {
457                     NopDaOpt(opts+i, olen);
458                     changes++;
459                 }
460                 normStats[PC_TCP_OPT][mode]++;
461             }
462         }
463         i += olen;
464     }
465     if ( ++i < len && memcmp(opts+i, MAX_EOL_PAD, len-i) )
466     {
467         if ( mode == NORM_MODE_ON )
468         {
469             memset(opts+i, 0, len-i);
470             changes++;
471         }
472         normStats[PC_TCP_PAD][mode]++;
473     }
474     return changes;
475 }
476 
Norm_TCPPadding(NormalizerConfig *,const NormMode mode,uint8_t * opts,size_t len,uint8_t validated_len,int changes)477 static inline int Norm_TCPPadding(NormalizerConfig*, const NormMode mode,
478     uint8_t* opts, size_t len, uint8_t validated_len, int changes)
479 {
480     size_t i = 0;
481 
482     while ( (i < len) &&
483         (opts[i] != (uint8_t)tcp::TcpOptCode::EOL) &&
484         (i < validated_len) )
485     {
486         i += ( opts[i] <= 1 ) ? 1 : opts[i+1];
487     }
488     if ( ++i < len && memcmp(opts+i, MAX_EOL_PAD, len-i) )
489     {
490         if ( mode == NORM_MODE_ON )
491         {
492             memset(opts+i, 0, len-i);
493             changes++;
494         }
495         normStats[PC_TCP_PAD][mode]++;
496     }
497     return changes;
498 }
499 
Norm_TCP(NormalizerConfig * c,Packet * p,uint8_t layer,int changes)500 static int Norm_TCP(
501     NormalizerConfig* c, Packet* p, uint8_t layer, int changes)
502 {
503     tcp::TCPHdr* h = reinterpret_cast<tcp::TCPHdr*>(const_cast<uint8_t*>(p->layers[layer].start));
504     const NormMode mode = get_norm_mode(p);
505 
506     if ( Norm_IsEnabled(c, NORM_TCP_RSV) )
507     {
508         if ( h->th_offx2 & TH_RSV )
509         {
510             if ( mode == NORM_MODE_ON )
511             {
512                 h->th_offx2 &= ~TH_RSV;
513                 changes++;
514             }
515             normStats[PC_TCP_RSV][mode]++;
516         }
517     }
518     if ( Norm_IsEnabled(c, NORM_TCP_ECN_PKT) )
519     {
520         if ( h->th_flags & (TH_CWR|TH_ECE) )
521         {
522             if ( mode == NORM_MODE_ON )
523             {
524                 h->th_flags &= ~(TH_CWR|TH_ECE);
525                 changes++;
526             }
527             normStats[PC_TCP_ECN_PKT][mode]++;
528         }
529         if ( h->th_offx2 & TH_NS )
530         {
531             if ( mode == NORM_MODE_ON )
532             {
533                 h->th_offx2 &= ~TH_NS;
534                 changes++;
535             }
536             normStats[PC_TCP_NS][mode]++;
537         }
538     }
539     if ( h->th_urp )
540     {
541         if ( !(h->th_flags & TH_URG) )
542         {
543             if ( Norm_IsEnabled(c, NORM_TCP_REQ_URG) )
544             {
545                 if ( mode == NORM_MODE_ON )
546                 {
547                     h->th_urp = 0;
548                     changes++;
549                 }
550                 normStats[PC_TCP_REQ_URG][mode]++;
551             }
552         }
553         else if ( !p->dsize )
554         {
555             if ( Norm_IsEnabled(c, NORM_TCP_REQ_PAY) )
556             {
557                 if ( mode == NORM_MODE_ON )
558                 {
559                     h->th_flags &= ~TH_URG;
560                     h->th_urp = 0;
561                     changes++;
562                 }
563                 normStats[PC_TCP_REQ_PAY][mode]++;
564             }
565         }
566         else if ( h->urp() > p->dsize )
567         {
568             if ( Norm_IsEnabled(c, NORM_TCP_URP) )
569             {
570                 if ( mode == NORM_MODE_ON )
571                 {
572                     h->set_urp(p->dsize);
573                     changes++;
574                 }
575                 normStats[PC_TCP_URP][mode]++;
576             }
577         }
578     }
579     else if ( Norm_IsEnabled(c, NORM_TCP_REQ_URP) )
580     {
581         if ( h->th_flags & TH_URG )
582         {
583             if ( mode == NORM_MODE_ON )
584             {
585                 h->th_flags &= ~TH_URG;
586                 changes++;
587             }
588             normStats[PC_TCP_REQ_URP][mode]++;
589         }
590     }
591 
592     uint8_t tcp_options_len = h->options_len();
593 
594     if ( tcp_options_len > 0 )
595     {
596         const Layer& lyr = p->layers[layer];
597         uint8_t* opts = const_cast<uint8_t*>(lyr.start) + tcp::TCP_MIN_HEADER_LEN;
598         // lyr.length only includes valid tcp options
599         uint8_t valid_opts_len = lyr.length - tcp::TCP_MIN_HEADER_LEN;
600 
601         if ( Norm_IsEnabled(c, NORM_TCP_OPT) )
602         {
603             changes = Norm_TCPOptions(c, mode, opts,
604                 tcp_options_len, h, valid_opts_len, changes);
605         }
606         else if ( Norm_IsEnabled(c, NORM_TCP_PAD) )
607         {
608             changes = Norm_TCPPadding(c, mode, opts,
609                 tcp_options_len, valid_opts_len, changes);
610         }
611     }
612     return changes;
613 }
614 
615 //-----------------------------------------------------------------------
616 
Norm_GetPegs()617 const PegInfo* Norm_GetPegs()
618 { return norm_names; }
619 
Norm_GetCounts(unsigned & c)620 NormPegs Norm_GetCounts(unsigned& c)
621 {
622     c = PC_MAX;
623     return normStats;
624 }
625 
626 //-----------------------------------------------------------------------
627 
Norm_SetConfig(NormalizerConfig * nc)628 int Norm_SetConfig(NormalizerConfig* nc)
629 {
630     if ( !nc->normalizer_flags )
631     {
632         return 0;
633     }
634     if ( Norm_IsEnabled(nc, (NormFlags)NORM_IP4_ANY) )
635     {
636         nc->normalizers[PacketManager::proto_idx(ProtocolId::ETHERTYPE_IPV4)] = Norm_IP4;
637     }
638     if ( Norm_IsEnabled(nc, NORM_ICMP4) )
639     {
640         nc->normalizers[PacketManager::proto_idx(ProtocolId::ICMPV4)] = Norm_ICMP4;
641     }
642     if ( Norm_IsEnabled(nc, (NormFlags)NORM_IP6_ANY) )
643     {
644         nc->normalizers[PacketManager::proto_idx(ProtocolId::IPV6)] = Norm_IP6;
645         nc->normalizers[PacketManager::proto_idx(ProtocolId::HOPOPTS)] = Norm_IP6_Opts;
646         nc->normalizers[PacketManager::proto_idx(ProtocolId::DSTOPTS)] = Norm_IP6_Opts;
647     }
648     if ( Norm_IsEnabled(nc, NORM_ICMP6) )
649     {
650         nc->normalizers[PacketManager::proto_idx(ProtocolId::ICMPV6)] = Norm_ICMP6;
651     }
652     if ( Norm_IsEnabled(nc, (NormFlags)NORM_TCP_ANY) )
653     {
654         nc->normalizers[PacketManager::proto_idx(ProtocolId::TCP)] = Norm_TCP;
655     }
656     return 0;
657 }
658 
659