ok, I think I've found the smoking gun here.

The TCP options for SYN packets were being put in the wrong
TCP option state structure, so only one side was ever being set
correctly.

I've attached two different patches here.  The first is just a fix.

The second tries to change the way td_maxend is used to be
a little better.

Hopefully this will be much better for you!

Darren

Index: ip_state.c
===================================================================
RCS file: /devel/CVS/IP-Filter/ip_state.c,v
retrieving revision 2.186.2.50
diff -c -r2.186.2.50 ip_state.c
*** ip_state.c  18 Dec 2006 15:53:40 -0000      2.186.2.50
--- ip_state.c  22 Dec 2006 17:04:39 -0000
***************
*** 1425,1445 ****
                if (flags == (TH_SYN|TH_ACK)) {
                        is->is_s0[source] = ntohl(tcp->th_ack);
                        is->is_s0[!source] = ntohl(tcp->th_seq) + 1;
!                       if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2)) &&
!                           (tdata->td_winflags & TCP_WSCALE_SEEN)) {
                                if (fr_tcpoptions(fin, tcp, fdata) == -1)
                                        fin->fin_flx |= FI_BAD;
-                               if (!(fdata->td_winflags & TCP_WSCALE_SEEN)) {
-                                       fdata->td_winscale = 0;
-                                       tdata->td_winscale = 0;
-                               }
                        }
                        if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
                                fr_checknewisn(fin, is);
                } else if (flags == TH_SYN) {
                        is->is_s0[source] = ntohl(tcp->th_seq) + 1;
                        if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
!                               if (fr_tcpoptions(fin, tcp, tdata) == -1)
                                        fin->fin_flx |= FI_BAD;
                        }
  
--- 1425,1440 ----
                if (flags == (TH_SYN|TH_ACK)) {
                        is->is_s0[source] = ntohl(tcp->th_ack);
                        is->is_s0[!source] = ntohl(tcp->th_seq) + 1;
!                       if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
                                if (fr_tcpoptions(fin, tcp, fdata) == -1)
                                        fin->fin_flx |= FI_BAD;
                        }
                        if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
                                fr_checknewisn(fin, is);
                } else if (flags == TH_SYN) {
                        is->is_s0[source] = ntohl(tcp->th_seq) + 1;
                        if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
!                               if (fr_tcpoptions(fin, tcp, fdata) == -1)
                                        fin->fin_flx |= FI_BAD;
                        }
  
***************
*** 1546,1562 ****
         * the receiver also does window scaling)
         */
        if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) {
!               if (tdata->td_winflags & TCP_WSCALE_SEEN) {
!                       fdata->td_winflags &= ~TCP_WSCALE_FIRST;
!                       fdata->td_maxwin = win;
!               } else {
!                       fdata->td_winscale = 0;
!                       fdata->td_winflags &= ~(TCP_WSCALE_FIRST|
!                                               TCP_WSCALE_SEEN);
!                       tdata->td_winscale = 0;
!                       tdata->td_winflags &= ~(TCP_WSCALE_FIRST|
!                                               TCP_WSCALE_SEEN);
!                 }
        }
  
        end = seq + dsize;
--- 1541,1548 ----
         * the receiver also does window scaling)
         */
        if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) {
!               fdata->td_winflags &= ~TCP_WSCALE_FIRST;
!               fdata->td_maxwin = win;
        }
  
        end = seq + dsize;
***************
*** 1592,1597 ****
--- 1578,1585 ----
                }
        }
  
+       /* TRACE(fdata, tdata, seq, end, ack, ackskew, win, maxwin) */
+ 
  #define       SEQ_GE(a,b)     ((int)((a) - (b)) >= 0)
  #define       SEQ_GT(a,b)     ((int)((a) - (b)) > 0)
        inseq = 0;
***************
*** 1599,1605 ****
            (SEQ_GE(seq, fdata->td_end - maxwin)) &&
  /* XXX what about big packets */
  #define MAXACKWINDOW 66000
!           (-ackskew <= (MAXACKWINDOW << fdata->td_winscale)) &&
            ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) {
                inseq = 1;
        /*
--- 1587,1593 ----
            (SEQ_GE(seq, fdata->td_end - maxwin)) &&
  /* XXX what about big packets */
  #define MAXACKWINDOW 66000
!           (-ackskew <= (MAXACKWINDOW)) &&
            ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) {
                inseq = 1;
        /*
***************
*** 1672,1677 ****
--- 1660,1672 ----
                        tdata->td_maxend = ack + win;
                return 1;
        }
+ 
+ printf("fdata:maxend %u end %u winflags %x winscale %d\n",
+ fdata->td_maxend, fdata->td_end, fdata->td_winflags, fdata->td_winscale);
+ printf("tdata:maxend %u end %u winflags %x winscale %d\n",
+ tdata->td_maxend, tdata->td_end, tdata->td_winflags, tdata->td_winscale);
+ printf("win %u end %u seq %u ack %u ackskew %d maxwin %d dsize %d flags %x\n",
+ ntohs(tcp->th_win), end, seq, ack, ackskew, maxwin, dsize, tcpflags);
        return 0;
  }
  
Index: ip_state.c
===================================================================
RCS file: /devel/CVS/IP-Filter/ip_state.c,v
retrieving revision 2.186.2.50
diff -c -r2.186.2.50 ip_state.c
*** ip_state.c  18 Dec 2006 15:53:40 -0000      2.186.2.50
--- ip_state.c  22 Dec 2006 17:17:03 -0000
***************
*** 1425,1445 ****
                if (flags == (TH_SYN|TH_ACK)) {
                        is->is_s0[source] = ntohl(tcp->th_ack);
                        is->is_s0[!source] = ntohl(tcp->th_seq) + 1;
!                       if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2)) &&
!                           (tdata->td_winflags & TCP_WSCALE_SEEN)) {
                                if (fr_tcpoptions(fin, tcp, fdata) == -1)
                                        fin->fin_flx |= FI_BAD;
-                               if (!(fdata->td_winflags & TCP_WSCALE_SEEN)) {
-                                       fdata->td_winscale = 0;
-                                       tdata->td_winscale = 0;
-                               }
                        }
                        if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
                                fr_checknewisn(fin, is);
                } else if (flags == TH_SYN) {
                        is->is_s0[source] = ntohl(tcp->th_seq) + 1;
                        if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
!                               if (fr_tcpoptions(fin, tcp, tdata) == -1)
                                        fin->fin_flx |= FI_BAD;
                        }
  
--- 1425,1440 ----
                if (flags == (TH_SYN|TH_ACK)) {
                        is->is_s0[source] = ntohl(tcp->th_ack);
                        is->is_s0[!source] = ntohl(tcp->th_seq) + 1;
!                       if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
                                if (fr_tcpoptions(fin, tcp, fdata) == -1)
                                        fin->fin_flx |= FI_BAD;
                        }
                        if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
                                fr_checknewisn(fin, is);
                } else if (flags == TH_SYN) {
                        is->is_s0[source] = ntohl(tcp->th_seq) + 1;
                        if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
!                               if (fr_tcpoptions(fin, tcp, fdata) == -1)
                                        fin->fin_flx |= FI_BAD;
                        }
  
***************
*** 1495,1507 ****
  /* Function:    fr_tcpinwindow                                              */
  /* Returns:     int - 1 == packet inside TCP "window", 0 == not inside.     */
  /* Parameters:  fin(I)   - pointer to packet information                    */
! /*              fdata(I) - pointer to tcp state informatio (forward)        */
! /*              tdata(I) - pointer to tcp state informatio (reverse)        */
  /*              tcp(I)   - pointer to TCP packet header                     */
  /*                                                                          */
  /* Given a packet has matched addresses and ports, check to see if it is    */
  /* within the TCP data window.  In a show of generosity, allow packets that */
  /* are within the window space behind the current sequence # as well.       */
  /* ------------------------------------------------------------------------ */
  int fr_tcpinwindow(fin, fdata, tdata, tcp, flags)
  fr_info_t *fin;
--- 1490,1506 ----
  /* Function:    fr_tcpinwindow                                              */
  /* Returns:     int - 1 == packet inside TCP "window", 0 == not inside.     */
  /* Parameters:  fin(I)   - pointer to packet information                    */
! /*              fdata(I) - pointer to tcp state information (forward)       */
! /*              tdata(I) - pointer to tcp state information (reverse)       */
  /*              tcp(I)   - pointer to TCP packet header                     */
  /*                                                                          */
  /* Given a packet has matched addresses and ports, check to see if it is    */
  /* within the TCP data window.  In a show of generosity, allow packets that */
  /* are within the window space behind the current sequence # as well.       */
+ /*                                                                          */
+ /* td_end    - largest sequence # (for last byte sent) by a sender          */
+ /* td_maxend - max. sequence # that can be sent.  This is only updated by   */
+ /* the largest ack number seen.                                             */
  /* ------------------------------------------------------------------------ */
  int fr_tcpinwindow(fin, fdata, tdata, tcp, flags)
  fr_info_t *fin;
***************
*** 1511,1517 ****
  {
        tcp_seq seq, ack, end;
        int ackskew, tcpflags;
!       u_32_t win, maxwin;
        int dsize, inseq;
  
        /*
--- 1510,1516 ----
  {
        tcp_seq seq, ack, end;
        int ackskew, tcpflags;
!       u_32_t win, maxwin, maxend;
        int dsize, inseq;
  
        /*
***************
*** 1546,1562 ****
         * the receiver also does window scaling)
         */
        if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) {
!               if (tdata->td_winflags & TCP_WSCALE_SEEN) {
!                       fdata->td_winflags &= ~TCP_WSCALE_FIRST;
!                       fdata->td_maxwin = win;
!               } else {
!                       fdata->td_winscale = 0;
!                       fdata->td_winflags &= ~(TCP_WSCALE_FIRST|
!                                               TCP_WSCALE_SEEN);
!                       tdata->td_winscale = 0;
!                       tdata->td_winflags &= ~(TCP_WSCALE_FIRST|
!                                               TCP_WSCALE_SEEN);
!                 }
        }
  
        end = seq + dsize;
--- 1545,1552 ----
         * the receiver also does window scaling)
         */
        if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) {
!               fdata->td_winflags &= ~TCP_WSCALE_FIRST;
!               fdata->td_maxwin = win;
        }
  
        end = seq + dsize;
***************
*** 1569,1575 ****
                 */
                fdata->td_end = end - 1;
                fdata->td_maxwin = 1;
!               fdata->td_maxend = end + win;
        }
  
        if (!(tcpflags & TH_ACK)) {  /* Pretend an ack was sent */
--- 1559,1565 ----
                 */
                fdata->td_end = end - 1;
                fdata->td_maxwin = 1;
!               fdata->td_maxend = end;
        }
  
        if (!(tcpflags & TH_ACK)) {  /* Pretend an ack was sent */
***************
*** 1582,1587 ****
--- 1572,1578 ----
  
        maxwin = tdata->td_maxwin;
        ackskew = tdata->td_end - ack;
+       maxend = fdata->td_maxend + maxwin;
  
        /*
         * Strict sequencing only allows in-order delivery.
***************
*** 1592,1605 ****
                }
        }
  
  #define       SEQ_GE(a,b)     ((int)((a) - (b)) >= 0)
  #define       SEQ_GT(a,b)     ((int)((a) - (b)) > 0)
        inseq = 0;
!       if ((SEQ_GE(fdata->td_maxend, end)) &&
            (SEQ_GE(seq, fdata->td_end - maxwin)) &&
  /* XXX what about big packets */
  #define MAXACKWINDOW 66000
!           (-ackskew <= (MAXACKWINDOW << fdata->td_winscale)) &&
            ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) {
                inseq = 1;
        /*
--- 1583,1598 ----
                }
        }
  
+       /* TRACE(fdata, tdata, seq, end, ack, ackskew, win, maxwin) */
+ 
  #define       SEQ_GE(a,b)     ((int)((a) - (b)) >= 0)
  #define       SEQ_GT(a,b)     ((int)((a) - (b)) > 0)
        inseq = 0;
!       if ((SEQ_GE(maxend, end)) &&
            (SEQ_GE(seq, fdata->td_end - maxwin)) &&
  /* XXX what about big packets */
  #define MAXACKWINDOW 66000
!           (-ackskew <= (MAXACKWINDOW)) &&
            ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) {
                inseq = 1;
        /*
***************
*** 1668,1677 ****
                        fdata->td_maxwin = win;
                if (SEQ_GT(end, fdata->td_end))
                        fdata->td_end = end;
!               if (SEQ_GE(ack + win, tdata->td_maxend))
!                       tdata->td_maxend = ack + win;
                return 1;
        }
        return 0;
  }
  
--- 1661,1677 ----
                        fdata->td_maxwin = win;
                if (SEQ_GT(end, fdata->td_end))
                        fdata->td_end = end;
!               if (SEQ_GE(ack, tdata->td_maxend))
!                       tdata->td_maxend = ack;
                return 1;
        }
+ 
+ printf("fdata:maxend %u end %u winflags %x winscale %d\n",
+ fdata->td_maxend, fdata->td_end, fdata->td_winflags, fdata->td_winscale);
+ printf("tdata:maxend %u end %u winflags %x winscale %d\n",
+ tdata->td_maxend, tdata->td_end, tdata->td_winflags, tdata->td_winscale);
+ printf("win %u end %u seq %u ack %u ackskew %d maxwin %d dsize %d flags %x\n",
+ ntohs(tcp->th_win), end, seq, ack, ackskew, maxwin, dsize, tcpflags);
        return 0;
  }
  
***************
*** 2841,2846 ****
--- 2841,2852 ----
  int why;
  {
  
+       extern ipstate_t *printstate __P((ipstate_t *, int, u_long));
+ 
+ #if !defined(_KERNEL)
+       printstate(is, 0, 0);
+ #endif
+ 
        ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0);
  
        /*

Reply via email to