1 /* $Id$ */
2 /****************************************************************************
3  *
4  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
5  * Copyright (C) 2005-2013 Sourcefire, Inc.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License Version 2 as
9  * published by the Free Software Foundation.  You may not use, modify or
10  * distribute this program under any other version of the GNU General
11  * Public License.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  *
22  ****************************************************************************/
23 
24 #ifdef NORMALIZER
25 
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 
30 #include <string.h>
31 #ifdef HAVE_DUMBNET_H
32 #include <dumbnet.h>
33 #else
34 #include <dnet.h>
35 #endif
36 
37 #include "normalize.h"
38 #include "perf.h"
39 #include "sfdaq.h"
40 
41 typedef enum {
42     PC_IP4_TRIM,
43     PC_IP4_TOS,
44     PC_IP4_DF,
45     PC_IP4_RF,
46     PC_IP4_TTL,
47     PC_IP4_OPTS,
48     PC_ICMP4_ECHO,
49     PC_IP6_TTL,
50     PC_IP6_OPTS,
51     PC_ICMP6_ECHO,
52     PC_TCP_SYN_OPT,
53     PC_TCP_OPT,
54     PC_TCP_PAD,
55     PC_TCP_RSV,
56     PC_TCP_NS,
57     PC_TCP_URP,
58     PC_TCP_ECN_PKT,
59     PC_TCP_TS_ECR,
60     PC_TCP_REQ_URG,
61     PC_TCP_REQ_PAY,
62     PC_TCP_REQ_URP,
63     PC_MAX
64 } PegCounts;
65 
66 static const char* pegName[PC_MAX] = {
67     "ip4::trim",
68     "ip4::tos",
69     "ip4::df",
70     "ip4::rf",
71     "ip4::ttl",
72     "ip4::opts",
73     "icmp4::echo",
74     "ip6::ttl",
75     "ip6::opts",
76     "icmp6::echo",
77     "tcp::syn_opt",
78     "tcp::opt",
79     "tcp::pad",
80     "tcp::rsv",
81     "tcp::ns",
82     "tcp::urp",
83     "tcp::ecn_pkt",
84     "tcp::ts_ecr",
85     "tcp::req_urg",
86     "tcp::req_pay",
87     "tcp::req_urp",
88 };
89 
90 static PegCount normStats[PC_MAX][NORM_MODE_MAX];
91 
92 //static int Norm_Eth(Packet*, uint8_t layer, int changes);
93 static int Norm_IP4(NormalizerContext*, Packet*, uint8_t layer, int changes);
94 static int Norm_ICMP4(NormalizerContext*, Packet*, uint8_t layer, int changes);
95 static int Norm_IP6(NormalizerContext*, Packet*, uint8_t layer, int changes);
96 static int Norm_ICMP6(NormalizerContext*, Packet*, uint8_t layer, int changes);
97 static int Norm_IP6_Opts(NormalizerContext*, Packet*, uint8_t layer, int changes);
98 //static int Norm_UDP(NormalizerContext*, Packet*, uint8_t layer, int changes);
99 static int Norm_TCP(NormalizerContext*, Packet*, uint8_t layer, int changes);
100 
101 static const uint8_t MAX_EOL_PAD[TCP_OPTLENMAX] = {
102     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
104 };
105 
106 // go from inner to outer
Norm_Packet(NormalizerContext * c,Packet * p)107 int Norm_Packet (NormalizerContext* c, Packet* p)
108 {
109     uint8_t lyr = p->next_layer;
110     int changes = 0;
111 
112     while ( lyr > 0 )
113     {
114         PROTO_ID proto = p->layers[--lyr].proto;
115         Normalizer n = c->normalizers[proto];
116         if ( n ) changes = n(c, p, lyr, changes);
117     }
118 
119     if ( changes > 0 )
120     {
121         p->packet_flags |= PKT_MODIFIED;
122         return 1;
123     }
124     if ( p->packet_flags & PKT_RESIZED )
125     {
126         return 1;
127     }
128     return 0;
129 }
130 
131 //-----------------------------------------------------------------------
132 // in the following code, we mostly use the actual packet data and the
133 // packet layers[].  use of other decoded packet members is largely
134 // avoided to ensure that we don't get tripped up by nested protocols.
135 // TCP options count and length are a notable exception.
136 //
137 // also note that checksums are not calculated here.  they are only
138 // calculated once after all normalizations are done (here, stream5)
139 // and any replacements are made.
140 //-----------------------------------------------------------------------
141 
142 #if 0
143 static int Norm_Eth (Packet * p, uint8_t layer, int changes)
144 {
145     return 0;
146 }
147 #endif
148 
149 //-----------------------------------------------------------------------
150 
151 #define IP4_FLAG_RF 0x8000
152 #define IP4_FLAG_DF 0x4000
153 #define IP4_FLAG_MF 0x2000
154 
155 // TBD support configurable minimum length / obtain from DAQ
156 // ether header + min payload (excludes FCS, which makes it 64 total)
157 #define ETH_MIN_LEN 60
158 
getNormMode(NormalizerContext * c)159 static inline int getNormMode (NormalizerContext* c)
160 {
161     return c->normMode;
162 }
163 
Norm_IP4(NormalizerContext * c,Packet * p,uint8_t layer,int changes)164 static int Norm_IP4 (NormalizerContext* c, Packet * p, uint8_t layer, int changes)
165 {
166     IPHdr* h = (IPHdr*)(p->layers[layer].start);
167     uint16_t fragbits = ntohs(h->ip_off);
168     uint16_t origbits = fragbits;
169     NormMode mode = getNormMode(c);
170 
171     if ( Norm_IsEnabled(c, NORM_IP4_TRIM) && (layer == 1) )
172     {
173         uint32_t len = p->layers[0].length + ntohs(h->ip_len);
174 
175         if ( (len < p->pkth->pktlen) &&
176            ( (len >= ETH_MIN_LEN) || (p->pkth->pktlen > ETH_MIN_LEN) )
177         ) {
178             if ( mode == NORM_MODE_ON )
179             {
180                 ((DAQ_PktHdr_t*)p->pkth)->pktlen = (len < ETH_MIN_LEN) ? ETH_MIN_LEN : len;
181                 p->packet_flags |= PKT_RESIZED;
182                 changes++;
183             }
184             normStats[PC_IP4_TRIM][mode]++;
185             sfBase.iPegs[PERF_COUNT_IP4_TRIM][mode]++;
186         }
187     }
188     if ( Norm_IsEnabled(c, NORM_IP4_TOS) )
189     {
190         if ( h->ip_tos )
191         {
192             if ( mode == NORM_MODE_ON )
193             {
194                 h->ip_tos = 0;
195                 changes++;
196             }
197             normStats[PC_IP4_TOS][mode]++;
198             sfBase.iPegs[PERF_COUNT_IP4_TOS][mode]++;
199         }
200     }
201 #if 0
202     if ( Norm_IsEnabled(c, NORM_IP4_ID) )
203     {
204         // TBD implement IP ID normalization / randomization
205     }
206 #endif
207     if ( Norm_IsEnabled(c, NORM_IP4_DF) )
208     {
209         if ( fragbits & IP4_FLAG_DF )
210         {
211             if ( mode == NORM_MODE_ON )
212             {
213                 fragbits &= ~IP4_FLAG_DF;
214                 changes++;
215             }
216             normStats[PC_IP4_DF][mode]++;
217             sfBase.iPegs[PERF_COUNT_IP4_DF][mode]++;
218         }
219     }
220     if ( Norm_IsEnabled(c, NORM_IP4_RF) )
221     {
222         if ( fragbits & IP4_FLAG_RF )
223         {
224             if ( mode == NORM_MODE_ON )
225             {
226                 fragbits &= ~IP4_FLAG_RF;
227                 changes++;
228             }
229             normStats[PC_IP4_RF][mode]++;
230             sfBase.iPegs[PERF_COUNT_IP4_RF][mode]++;
231         }
232     }
233     if ( fragbits != origbits )
234     {
235         h->ip_off = htons(fragbits);
236     }
237     if ( Norm_IsEnabled(c, NORM_IP4_TTL) )
238     {
239         if ( h->ip_ttl < ScMinTTL() )
240         {
241             if ( mode == NORM_MODE_ON )
242             {
243                 h->ip_ttl = ScNewTTL();
244                 p->error_flags &= ~PKT_ERR_BAD_TTL;
245                 changes++;
246             }
247             normStats[PC_IP4_TTL][mode]++;
248             sfBase.iPegs[PERF_COUNT_IP4_TTL][mode]++;
249         }
250     }
251     if ( p->layers[layer].length > IP_HEADER_LEN )
252     {
253         if ( mode == NORM_MODE_ON )
254         {
255             uint8_t* opts = p->layers[layer].start + IP_HEADER_LEN;
256             uint8_t len = p->layers[layer].length - IP_HEADER_LEN;
257             // expect len > 0 because IHL yields a multiple of 4
258             memset(opts, IPOPT_NOP, len);
259             changes++;
260         }
261         normStats[PC_IP4_OPTS][mode]++;
262         sfBase.iPegs[PERF_COUNT_IP4_OPTS][mode]++;
263     }
264     return changes;
265 }
266 
267 //-----------------------------------------------------------------------
268 
Norm_ICMP4(NormalizerContext * c,Packet * p,uint8_t layer,int changes)269 static int Norm_ICMP4 (NormalizerContext* c, Packet * p, uint8_t layer, int changes)
270 {
271     ICMPHdr* h = (ICMPHdr*)(p->layers[layer].start);
272     NormMode mode = getNormMode(c);
273 
274     if ( (h->type == ICMP_ECHO || h->type == ICMP_ECHOREPLY) &&
275          (h->code != 0) )
276     {
277         if ( mode == NORM_MODE_ON )
278         {
279             h->code = 0;
280             changes++;
281         }
282         normStats[PC_ICMP4_ECHO][mode]++;
283         sfBase.iPegs[PERF_COUNT_ICMP4_ECHO][mode]++;
284     }
285     return changes;
286 }
287 
288 //-----------------------------------------------------------------------
289 
Norm_IP6(NormalizerContext * c,Packet * p,uint8_t layer,int changes)290 static int Norm_IP6 (NormalizerContext* c, Packet * p, uint8_t layer, int changes)
291 {
292     IP6RawHdr* h = (IP6RawHdr*)(p->layers[layer].start);
293     NormMode mode = getNormMode(c);
294 
295     if ( Norm_IsEnabled(c, NORM_IP6_TTL) )
296     {
297         if ( h->ip6hops < ScMinTTL() )
298         {
299             if ( mode == NORM_MODE_ON )
300             {
301                 h->ip6hops = ScNewTTL();
302                 p->error_flags &= ~PKT_ERR_BAD_TTL;
303                 changes++;
304             }
305             normStats[PC_IP6_TTL][mode]++;
306             sfBase.iPegs[PERF_COUNT_IP6_TTL][mode]++;
307         }
308     }
309     return changes;
310 }
311 
312 //-----------------------------------------------------------------------
313 
Norm_ICMP6(NormalizerContext * c,Packet * p,uint8_t layer,int changes)314 static int Norm_ICMP6 (NormalizerContext* c, Packet * p, uint8_t layer, int changes)
315 {
316     ICMPHdr* h = (ICMPHdr*)(p->layers[layer].start);
317     NormMode mode = getNormMode(c);
318 
319     if ( (h->type == ICMP6_ECHO || h->type == ICMP6_REPLY) &&
320          (h->code != 0) )
321     {
322         if ( mode == NORM_MODE_ON )
323         {
324             h->code = 0;
325             changes++;
326         }
327         normStats[PC_ICMP6_ECHO][mode]++;
328         sfBase.iPegs[PERF_COUNT_ICMP6_ECHO][mode]++;
329     }
330     return changes;
331 }
332 
333 //-----------------------------------------------------------------------
334 // we assume here that the decoder has not pushed ip6 option extension
335 // headers unless the basic sizing is correct (size = N*8 octetes, N>0).
336 
337 typedef struct
338 {
339     uint8_t next;
340     uint8_t xlen;
341     uint8_t type;
342     uint8_t olen;
343 } ExtOpt;
344 
345 #define IP6_OPT_PAD_N 1
346 
Norm_IP6_Opts(NormalizerContext * c,Packet * p,uint8_t layer,int changes)347 static int Norm_IP6_Opts (NormalizerContext* c, Packet * p, uint8_t layer, int changes)
348 {
349     NormMode mode = getNormMode(c);
350 
351     if ( mode == NORM_MODE_ON )
352     {
353         uint8_t* b = p->layers[layer].start;
354         ExtOpt* x = (ExtOpt*)b;
355 
356         // whatever was here, turn it into one PADN option
357         x->type = IP6_OPT_PAD_N;
358         x->olen = (x->xlen * 8) + 8 - sizeof(*x);
359         memset(b+sizeof(*x), 0, x->olen);
360 
361         changes++;
362     }
363     normStats[PC_IP6_OPTS][mode]++;
364     sfBase.iPegs[PERF_COUNT_IP6_OPTS][mode]++;
365 
366     return changes;
367 }
368 
369 //-----------------------------------------------------------------------
370 
371 #if 0
372 static int Norm_UDP (Packet * p, uint8_t layer, int changes)
373 {
374     return 0;
375 }
376 #endif
377 
378 //-----------------------------------------------------------------------
379 
NopDaOpt(uint8_t * opt,uint8_t len)380 static inline void NopDaOpt (uint8_t* opt, uint8_t len)
381 {
382     memset(opt, TCPOPT_NOP, len);
383 }
384 
385 #define TS_ECR_OFFSET 6
386 #define TS_ECR_LENGTH 4
387 
Norm_TCPOptions(NormalizerContext * context,uint8_t * opts,size_t len,const TCPHdr * h,uint8_t numOpts,int changes)388 static inline int Norm_TCPOptions (NormalizerContext* context, uint8_t* opts, size_t len, const TCPHdr* h, uint8_t numOpts, int changes)
389 {
390     size_t i = 0;
391     uint8_t c = 0;
392     NormMode mode = getNormMode(context);
393 
394     while ( (i < len) && (opts[i] != TCPOPT_EOL) &&
395         (c++ < numOpts) )
396     {
397         uint8_t olen = ( opts[i] <= 1 ) ? 1 : opts[i+1];
398 
399         // we know that the first numOpts options have valid lengths
400         // so we should not need to check individual or total option lengths.
401         // however, we keep this as a sanity check.
402         if ( i + olen > len)
403             break;
404 
405         switch ( opts[i] )
406         {
407         case TCPOPT_NOP:
408             break;
409 
410         case TCPOPT_MAXSEG:
411         case TCPOPT_WSCALE:
412             if ( !(h->th_flags & TH_SYN) )
413             {
414                 if ( mode == NORM_MODE_ON )
415                 {
416                     NopDaOpt(opts+i, olen);
417                     changes++;
418                 }
419                 normStats[PC_TCP_SYN_OPT][mode]++;
420                 sfBase.iPegs[PERF_COUNT_TCP_SYN_OPT][mode]++;
421             }
422             break;
423 
424         case TCPOPT_TIMESTAMP:
425             if ( !(h->th_flags & TH_ACK) &&
426                 // use memcmp because opts have arbitrary alignment
427                 memcmp(opts+i+TS_ECR_OFFSET, MAX_EOL_PAD, TS_ECR_LENGTH) )
428             {
429                 if ( mode == NORM_MODE_ON )
430                 {
431                     // TSecr should be zero unless ACK is set
432                     memset(opts+i+TS_ECR_OFFSET, 0, TS_ECR_LENGTH);
433                     changes++;
434                 }
435                 normStats[PC_TCP_TS_ECR][mode]++;
436                 sfBase.iPegs[PERF_COUNT_TCP_TS_ECR][mode]++;
437             }
438             break;
439 
440         default:
441             if ( !Norm_TcpIsOptional(context, opts[i]) )
442             {
443                 if ( mode == NORM_MODE_ON )
444                 {
445                     NopDaOpt(opts+i, olen);
446                     changes++;
447                 }
448                 normStats[PC_TCP_OPT][mode]++;
449                 sfBase.iPegs[PERF_COUNT_TCP_OPT][mode]++;
450             }
451         }
452         i += olen;
453     }
454     if ( ++i < len && memcmp(opts+i, MAX_EOL_PAD, len-i) )
455     {
456         if ( mode == NORM_MODE_ON )
457         {
458             memset(opts+i, 0, len-i);
459             changes++;
460         }
461         normStats[PC_TCP_PAD][mode]++;
462         sfBase.iPegs[PERF_COUNT_TCP_PAD][mode]++;
463     }
464     return changes;
465 }
466 
Norm_TCPPadding(NormalizerContext * context,uint8_t * opts,size_t len,uint8_t numOpts,int changes)467 static inline int Norm_TCPPadding (NormalizerContext* context, uint8_t* opts, size_t len, uint8_t numOpts, int changes)
468 {
469     size_t i = 0;
470     uint8_t c = 0;
471     NormMode mode = getNormMode(context);
472 
473     while ( (i < len) && (opts[i] != TCPOPT_EOL) && (c++ < numOpts) )
474     {
475         i += ( opts[i] <= 1 ) ? 1 : opts[i+1];
476     }
477     if ( ++i < len && memcmp(opts+i, MAX_EOL_PAD, len-i) )
478     {
479         if ( mode == NORM_MODE_ON )
480         {
481             memset(opts+i, 0, len-i);
482             changes++;
483         }
484         normStats[PC_TCP_PAD][mode]++;
485         sfBase.iPegs[PERF_COUNT_TCP_PAD][mode]++;
486     }
487     return changes;
488 }
489 
Norm_TCP(NormalizerContext * c,Packet * p,uint8_t layer,int changes)490 static int Norm_TCP (NormalizerContext* c, Packet * p, uint8_t layer, int changes)
491 {
492     NormMode mode = getNormMode(c);
493     TCPHdr* h = (TCPHdr*)(p->layers[layer].start);
494 
495     if ( Norm_IsEnabled(c, NORM_TCP_RSV) )
496     {
497         if ( h->th_offx2 & TH_RSV )
498         {
499             if ( mode == NORM_MODE_ON )
500             {
501                 h->th_offx2 &= ~TH_RSV;
502                 changes++;
503             }
504             normStats[PC_TCP_RSV][mode]++;
505             sfBase.iPegs[PERF_COUNT_TCP_RSV][mode]++;
506         }
507     }
508     if ( Norm_IsEnabled(c, NORM_TCP_ECN_PKT) )
509     {
510         if ( h->th_flags & (TH_CWR|TH_ECE) )
511         {
512             if ( mode == NORM_MODE_ON )
513             {
514                 h->th_flags &= ~(TH_CWR|TH_ECE);
515                 changes++;
516             }
517             normStats[PC_TCP_ECN_PKT][mode]++;
518             sfBase.iPegs[PERF_COUNT_TCP_ECN_PKT][mode]++;
519         }
520         if ( h->th_offx2 & TH_NS )
521         {
522             if ( mode == NORM_MODE_ON )
523             {
524                 h->th_offx2 &= ~TH_NS;
525                 changes++;
526             }
527             normStats[PC_TCP_NS][mode]++;
528             sfBase.iPegs[PERF_COUNT_TCP_NS][mode]++;
529         }
530     }
531     if ( h->th_urp )
532     {
533         if ( !(h->th_flags & TH_URG) )
534         {
535             if ( Norm_IsEnabled(c, NORM_TCP_REQ_URG) )
536             {
537                 if ( mode == NORM_MODE_ON )
538                 {
539                     h->th_urp = 0;
540                     changes++;
541                 }
542                 normStats[PC_TCP_REQ_URG][mode]++;
543                 sfBase.iPegs[PERF_COUNT_TCP_REQ_URG][mode]++;
544             }
545         }
546         else if ( !p->dsize )
547         {
548             if ( Norm_IsEnabled(c, NORM_TCP_REQ_PAY) )
549             {
550                 if ( mode == NORM_MODE_ON )
551                 {
552                     h->th_flags &= ~TH_URG;
553                     h->th_urp = 0;
554                     changes++;
555                 }
556                 normStats[PC_TCP_REQ_PAY][mode]++;
557                 sfBase.iPegs[PERF_COUNT_TCP_REQ_PAY][mode]++;
558             }
559         }
560         else if ( (ntohs(h->th_urp) > p->dsize) )
561         {
562             if ( Norm_IsEnabled(c, NORM_TCP_URP) )
563             {
564                 if ( mode == NORM_MODE_ON )
565                 {
566                     h->th_urp = ntohs(p->dsize);
567                     changes++;
568                 }
569                 normStats[PC_TCP_URP][mode]++;
570                 sfBase.iPegs[PERF_COUNT_TCP_URP][mode]++;
571             }
572         }
573     }
574     else if ( Norm_IsEnabled(c, NORM_TCP_REQ_URP) &&
575         h->th_flags & TH_URG )
576     {
577         if ( mode == NORM_MODE_ON )
578         {
579             h->th_flags &= ~TH_URG;
580             changes++;
581         }
582         normStats[PC_TCP_REQ_URP][mode]++;
583         sfBase.iPegs[PERF_COUNT_TCP_REQ_URP][mode]++;
584     }
585     if ( p->tcp_options_len > 0 )
586     {
587         uint8_t* opts = p->layers[layer].start + TCP_HEADER_LEN;
588 
589         if ( Norm_IsEnabled(c, NORM_TCP_OPT) )
590         {
591             changes = Norm_TCPOptions(c, opts, p->tcp_options_len,
592                 h, p->tcp_option_count, changes);
593         }
594         else if ( Norm_IsEnabled(c, NORM_TCP_PAD) )
595         {
596             changes = Norm_TCPPadding(c, opts, p->tcp_options_len,
597                 p->tcp_option_count, changes);
598         }
599     }
600     return changes;
601 }
602 
603 //-----------------------------------------------------------------------
604 
Norm_PrintStats(void)605 void Norm_PrintStats (void)
606 {
607     int i;
608     LogMessage("Normalizer statistics:\n");
609 
610     for ( i = 0; i < PC_MAX; i++ )
611     {
612         // for now, 23 aligns with frag3
613         LogMessage("%23s: " STDu64 "\n", pegName[i], normStats[i][NORM_MODE_ON]);
614         LogMessage("Would %17s: " STDu64 "\n", pegName[i], normStats[i][NORM_MODE_WOULDA]);
615     }
616 }
617 
Norm_ResetStats(void)618 void Norm_ResetStats (void)
619 {
620     memset(normStats, 0, sizeof(normStats));
621 }
622 
623 //-----------------------------------------------------------------------
624 
Norm_SetConfig(NormalizerContext * nc)625 int Norm_SetConfig (NormalizerContext* nc)
626 {
627     if ( !DAQ_CanReplace() )
628     {
629         LogMessage("WARNING: normalizations disabled because DAQ"
630             " can't replace packets.\n");
631         nc->normalizer_flags = 0x0;
632         return -1;
633     }
634     if ( !nc->normalizer_flags )
635     {
636         return 0;
637     }
638     if ( Norm_IsEnabled(nc, NORM_IP4) )
639     {
640         nc->normalizers[PROTO_IP4] = Norm_IP4;
641     }
642     if ( Norm_IsEnabled(nc, NORM_IP4_TRIM) )
643     {
644         if ( !DAQ_CanInject() )
645         {
646             LogMessage("WARNING: normalize_ip4: trim disabled since DAQ "
647                 "can't inject packets.\n");
648             Norm_Disable(nc, NORM_IP4_TRIM);
649         }
650     }
651     if ( Norm_IsEnabled(nc, NORM_ICMP4) )
652     {
653         nc->normalizers[PROTO_ICMP4] = Norm_ICMP4;
654     }
655     if ( Norm_IsEnabled(nc, NORM_IP6) )
656     {
657         nc->normalizers[PROTO_IP6] = Norm_IP6;
658         nc->normalizers[PROTO_IP6_HOP_OPTS] = Norm_IP6_Opts;
659         nc->normalizers[PROTO_IP6_DST_OPTS] = Norm_IP6_Opts;
660     }
661     if ( Norm_IsEnabled(nc, NORM_ICMP6) )
662     {
663         nc->normalizers[PROTO_ICMP6] = Norm_ICMP6;
664     }
665     if ( Norm_IsEnabled(nc, NORM_TCP) )
666     {
667         nc->normalizers[PROTO_TCP] = Norm_TCP;
668     }
669     return 0;
670 }
671 #endif  // NORMALIZER
672 
673