aixoss / ipfilter

IPFilter for AIX
Other
3 stars 1 forks source link

Fragmented packets are dropped by the firewall #4

Open akhilesh2410 opened 6 years ago

akhilesh2410 commented 6 years ago

I have seen that fragmented packets are dropped by the ipfilter firewall. First packet makes entry in state table and subsequent packets also able to find state table entry but are dropped by the firewall. This issue seen for IN/OUT direction fragmented packets.

Further looking at the code i found that code in fil.c line : 2502 looks suspicious to me ,which mark the packet flag as BLOCK ,because for fragmented packet FI_FRAGBODY flag will be set and it will not be added into state table.

And mark the packet as bad packet by increment fr_bads.

-bash-4.3# ipf -V ipf: IP Filter: v4.1.13 (480) Kernel: IP Filter: v4.1.13 Running: yes Log Flags: 0 = none set Default: pass all, Logging: available Active list: 0 Feature mask: 0x87 -bash-4.3#

akhilesh2410 commented 6 years ago

Below code in ip_frag.c needs to be added to resolve this issue: In Function frentry_t *fr_knownfrag(fin, passp): Line number 641:

  if ((pass & FR_KEEPSTATE) != 0)
    pass &= ~(FR_KEEPSTATE);
  if ((pass & FI_STATE) != 0)
    pass &= ~(FI_STATE);

Thanks, Akhilesh Verma

ishyiko commented 2 years ago
diff --git a/kernext/fil.c b/kernext/fil.c
index 0d529e6..25c0f5b 100644
--- a/kernext/fil.c
+++ b/kernext/fil.c
@@ -1363,7 +1363,10 @@ fr_info_t *fin;
    if (off != 0) {
        fi->fi_flx |= FI_FRAG;
        off &= IP_OFFMASK;
-       if (off != 0) {
+       //check if we have IP_MF bit set in offset, if yes then only,
+       //go to loop and validate it with given condition
+       // else that would be the last fragment and should not be validated
+       if ((off & ~IP_OFFMASK) != 0) {
            fin->fin_flx |= FI_FRAGBODY;
            off <<= 3;
            if ((off + fin->fin_dlen > 65535) || 
diff --git a/kernext/ip_frag.c b/kernext/ip_frag.c
index a6168ff..d5e9c18 100644
--- a/kernext/ip_frag.c
+++ b/kernext/ip_frag.c
@@ -639,6 +639,10 @@ u_32_t *passp;
            pass = fr->fr_flags;
            if ((pass & FR_LOGFIRST) != 0)
                pass &= ~(FR_LOGFIRST|FR_LOG);
+           if ((pass & FR_KEEPSTATE) != 0)
+               pass &= ~(FR_KEEPSTATE);
+           if ((pass & FI_STATE) != 0)
+               pass &= ~(FI_STATE);
            *passp = pass;
        }
    }