Jeff A. Earickson wrote:
> ...
> Carson,
>
> Thank you, thank you. Your rules worked as-is and my delayed email
> started
> moving. I had been using my stateful rules for a long time with one wire
> just fine. With the addition of a second wire and IP-multipathing in an
> active-passive failover mode, the wheels fell off. I ran snoop on both
> interfaces and I could see a split of traffic between the wires, so the
> second wire wasn't as silent as I would have expected. I figured that it
> might have something to do with that, or kernel patch 118833-36, or
> mpathd
> changes, or the ipfilter patch, or God know what.
>
> So how come mpathd and keep state don't play together? Is this a
> known issue?
It is IPMP and "keep state".
Unless you use ndd to define an IPMP interface group there, it
is not possible to use stateful filtering as "keep state" tries to bind
the connection to specific NICs but IPMP sends them out over
either one.
You could also try this:
pass in quick on -,- out-via -,- proto tcp from any to any port = 25
flags S keep state
pass out quick on -,- out-via -,- proto tcp from any to any port = 25
flags S keep state
although now that I read the source, there is one "bug" that will
stop this from working...the attached patch fixes that.
Darren
Index: ip_state.c
===================================================================
RCS file: /devel/CVS/IP-Filter/ip_state.c,v
retrieving revision 2.186.2.52
diff -c -r2.186.2.52 ip_state.c
*** ip_state.c 2 Feb 2007 22:50:32 -0000 2.186.2.52
--- ip_state.c 5 Mar 2007 15:20:29 -0000
***************
*** 171,176 ****
--- 171,177 ----
ips_iptq,
ips_icmptq,
ips_icmpacktq,
+ ips_deletetq,
*ips_utqe = NULL;
#ifdef IPFILTER_LOG
int ipstate_logging = 1;
***************
*** 276,282 ****
ips_iptq.ifq_head = NULL;
ips_iptq.ifq_tail = &ips_iptq.ifq_head;
MUTEX_INIT(&ips_iptq.ifq_lock, "ipftq ip tab");
! ips_iptq.ifq_next = NULL;
RWLOCK_INIT(&ipf_state, "ipf IP state rwlock");
MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex");
--- 277,289 ----
ips_iptq.ifq_head = NULL;
ips_iptq.ifq_tail = &ips_iptq.ifq_head;
MUTEX_INIT(&ips_iptq.ifq_lock, "ipftq ip tab");
! ips_iptq.ifq_next = &ips_deletetq;
! ips_deletetq.ifq_ttl = (u_long)1;
! ips_deletetq.ifq_ref = 1;
! ips_deletetq.ifq_head = NULL;
! ips_deletetq.ifq_tail = &ips_deletetq.ifq_head;
! MUTEX_INIT(&ips_deletetq.ifq_lock, "state delete queue");
! ips_deletetq.ifq_next = NULL;
RWLOCK_INIT(&ipf_state, "ipf IP state rwlock");
MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex");
***************
*** 327,332 ****
--- 334,340 ----
MUTEX_DESTROY(&ips_udpacktq.ifq_lock);
MUTEX_DESTROY(&ips_icmpacktq.ifq_lock);
MUTEX_DESTROY(&ips_iptq.ifq_lock);
+ MUTEX_DESTROY(&ips_deletetq.ifq_lock);
}
if (ips_table != NULL) {
***************
*** 1175,1183 ****
is->is_tag = FR_NOLOGTAG;
}
- is->is_ifp[out << 1] = fin->fin_ifp;
if (fin->fin_ifp != NULL) {
! COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]);
}
/*
--- 1183,1204 ----
is->is_tag = FR_NOLOGTAG;
}
if (fin->fin_ifp != NULL) {
! /*
! * If the filter rule has an interface name then copy it
! * in (and its "pointer") rather than the one from the packet.
! * This ensures that we preserve any "special" names that
! * might be present in the filter rule that cannot be
! * resolved to an interface pointer.
! */
! if ((fr != NULL) && (fr->fr_ifnames[0][0] != '\0')) {
! is->is_ifp[out << 1] = fr->fr_ifas[0];
! strncpy(is->is_ifname[out << 1], fr->fr_ifnames[0],
! sizeof(fr->fr_ifnames[0]));
! } else {
! is->is_ifp[out << 1] = fin->fin_ifp;
! COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]);
! }
}
/*
***************
*** 1394,1399 ****
--- 1415,1436 ----
tdata = &is->is_tcp.ts_data[source];
MUTEX_ENTER(&is->is_lock);
+
+ /*
+ * If a SYN packet is received for a connection that is on the way out
+ * but hasn't yet departed then advance this session along the way.
+ */
+ if ((tcp->th_flags & TH_OPENING) == TH_SYN) {
+ if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) &&
+ (is->is_state[1] > IPF_TCPS_ESTABLISHED)) {
+ is->is_state[!source] = IPF_TCPS_CLOSED;
+ fr_movequeue(&is->is_sti, is->is_sti.tqe_ifq,
+ &ips_deletetq);
+ MUTEX_ENTER(&is->is_lock);
+ return 0;
+ }
+ }
+
if (fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags)) {
#ifdef IPFILTER_SCAN
if (is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER)) {
***************
*** 1444,1451 ****
}
ret = 1;
! } else
fin->fin_flx |= FI_OOW;
MUTEX_EXIT(&is->is_lock);
return ret;
}
--- 1481,1489 ----
}
ret = 1;
! } else {
fin->fin_flx |= FI_OOW;
+ }
MUTEX_EXIT(&is->is_lock);
return ret;
}
***************
*** 2352,2357 ****
--- 2390,2402 ----
hvm = DOUBLE_HASH(hv);
for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
+ /*
+ * If a connection is about to be deleted, no packets
+ * are allowed to match it.
+ */
+ if (is->is_sti.tqe_ifq == &ips_deletetq)
+ continue;
+
if ((is->is_p != pr) || (is->is_v != v))
continue;
is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);