When tcp_output() receives an error upon sending a packet it reverts parts
of its internal state to ignore the failed send and try again a bit later. If the error is EPERM the packet got blocked by the local firewall and the revert may cause the session to get stuck and retry indefinitely. This way we treat it like a packet loss and let the retransmit timer and timeouts do their work over time. The correct behavior is to drop a connection that gets an EPERM error. However this _may_ introduce some POLA problems and a two commit approach was chosen. Discussed with: glebius PR: kern/25986 PR: kern/102653
This commit is contained in:
parent
7699548f1b
commit
2c30ec0a1f
@ -1137,9 +1137,18 @@ tcp_output(struct tcpcb *tp)
|
||||
/*
|
||||
* We know that the packet was lost, so back out the
|
||||
* sequence number advance, if any.
|
||||
*
|
||||
* If the error is EPERM the packet got blocked by the
|
||||
* local firewall. Normally we should terminate the
|
||||
* connection but the blocking may have been spurious
|
||||
* due to a firewall reconfiguration cycle. So we treat
|
||||
* it like a packet loss and let the retransmit timer and
|
||||
* timeouts do their work over time.
|
||||
* XXX: It is a POLA question whether calling tcp_drop right
|
||||
* away would be the really correct behavior instead.
|
||||
*/
|
||||
if ((tp->t_flags & TF_FORCEDATA) == 0 ||
|
||||
!callout_active(tp->tt_persist)) {
|
||||
if (error != EPERM && ((tp->t_flags & TF_FORCEDATA) == 0 ||
|
||||
!callout_active(tp->tt_persist))) {
|
||||
/*
|
||||
* No need to check for TH_FIN here because
|
||||
* the TF_SENTFIN flag handles that case.
|
||||
@ -1155,6 +1164,10 @@ tcp_output(struct tcpcb *tp)
|
||||
tp->snd_nxt -= len;
|
||||
}
|
||||
}
|
||||
if (error == EPERM) {
|
||||
tp->t_softerror = error;
|
||||
return (error);
|
||||
}
|
||||
|
||||
out:
|
||||
SOCKBUF_UNLOCK_ASSERT(&so->so_snd); /* Check gotos. */
|
||||
|
Loading…
Reference in New Issue
Block a user