aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/ip_carp.c27
-rw-r--r--sys/netinet/tcp_hostcache.c6
-rw-r--r--sys/netinet/tcp_input.c2
-rw-r--r--sys/netinet/tcp_lro.c11
-rw-r--r--sys/netinet/tcp_subr.c42
-rw-r--r--sys/netinet/tcp_syncache.c81
-rw-r--r--sys/netinet/tcp_syncache.h6
-rw-r--r--sys/netinet/tcp_var.h1
8 files changed, 106 insertions, 70 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index d3d7957cf087..4f553b9aac5e 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1640,18 +1640,31 @@ carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr)
static void
carp_send_na(struct carp_softc *sc)
{
- static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
struct ifaddr *ifa;
- struct in6_addr *in6;
+ int flags;
+ /*
+ * Sending Unsolicited Neighbor Advertisements
+ *
+ * If the node is a router, we MUST set the Router flag to one.
+ * We set Override flag to one and send link-layer address option,
+ * thus neighboring nodes will install the new link-layer address.
+ */
+ flags = ND_NA_FLAG_OVERRIDE;
+ if (V_ip6_forwarding)
+ flags |= ND_NA_FLAG_ROUTER;
CARP_FOREACH_IFA(sc, ifa) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
-
- in6 = IFA_IN6(ifa);
- nd6_na_output(sc->sc_carpdev, &mcast, in6,
- ND_NA_FLAG_OVERRIDE, 1, NULL);
- DELAY(1000); /* XXX */
+ /*
+ * We use unspecified address as destination here to avoid
+ * scope initialization for each call.
+ * nd6_na_output() will use all nodes multicast address if
+ * destinaion address is unspecified.
+ */
+ nd6_na_output(sc->sc_carpdev, &in6addr_any, IFA_IN6(ifa),
+ flags, ND6_NA_OPT_LLA | ND6_NA_CARP_MASTER, NULL);
+ DELAY(1000); /* RetransTimer */
}
}
diff --git a/sys/netinet/tcp_hostcache.c b/sys/netinet/tcp_hostcache.c
index dbc966acc56b..df639876a85c 100644
--- a/sys/netinet/tcp_hostcache.c
+++ b/sys/netinet/tcp_hostcache.c
@@ -192,17 +192,17 @@ SYSCTL_INT(_net_inet_tcp_hostcache, OID_AUTO, purge, CTLFLAG_VNET | CTLFLAG_RW,
"Expire all entries on next purge run");
SYSCTL_PROC(_net_inet_tcp_hostcache, OID_AUTO, list,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE,
+ CTLFLAG_VNET | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE,
0, 0, sysctl_tcp_hc_list, "A",
"List of all hostcache entries");
SYSCTL_PROC(_net_inet_tcp_hostcache, OID_AUTO, histo,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE,
+ CTLFLAG_VNET | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE,
0, 0, sysctl_tcp_hc_histo, "A",
"Print a histogram of hostcache hashbucket utilization");
SYSCTL_PROC(_net_inet_tcp_hostcache, OID_AUTO, purgenow,
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+ CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
NULL, 0, sysctl_tcp_hc_purgenow, "I",
"Immediately purge all entries");
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index d5dc516c28aa..dd27ec77c1af 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -3412,7 +3412,7 @@ dropafterack:
return;
dropwithreset:
- tcp_dropwithreset(m, th, NULL, tlen);
+ tcp_dropwithreset(m, th, tp, tlen);
if (tp != NULL) {
INP_WUNLOCK(inp);
}
diff --git a/sys/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c
index 7512679bd4e9..64efa4bf060f 100644
--- a/sys/netinet/tcp_lro.c
+++ b/sys/netinet/tcp_lro.c
@@ -1428,17 +1428,6 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
{
int error;
- if (((m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) !=
- ((CSUM_DATA_VALID | CSUM_PSEUDO_HDR))) ||
- (m->m_pkthdr.csum_data != 0xffff)) {
- /*
- * The checksum either did not have hardware offload
- * or it was a bad checksum. We can't LRO such
- * a packet.
- */
- counter_u64_add(tcp_bad_csums, 1);
- return (TCP_LRO_CANNOT);
- }
/* get current time */
binuptime(&lc->lro_last_queue_time);
CURVNET_SET(lc->ifp->if_vnet);
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index cc83a21773a8..c817c79881d6 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -2148,14 +2148,16 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
}
/*
- * Send a challenge ack (no data, no SACK option), but not more than
- * V_tcp_ack_war_cnt per V_tcp_ack_war_time_window (per TCP connection).
+ * Check that no more than V_tcp_ack_war_cnt per V_tcp_ack_war_time_window
+ * are sent. *epoch_end is the end of the current epoch and is updated, if the
+ * current epoch ended in the past. *ack_cnt is the counter used during the
+ * current epoch. It might be reset and incremented.
+ * The function returns true if a challenge ACK should be sent.
*/
-void
-tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
+bool
+tcp_challenge_ack_check(sbintime_t *epoch_end, uint32_t *ack_cnt)
{
sbintime_t now;
- bool send_challenge_ack;
/*
* The sending of a challenge ACK could be triggered by a blind attacker
@@ -2164,29 +2166,39 @@ tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
* would have guessed wrongly.
*/
(void)badport_bandlim(BANDLIM_TCP_RST);
+
if (V_tcp_ack_war_time_window == 0 || V_tcp_ack_war_cnt == 0) {
/* ACK war protection is disabled. */
- send_challenge_ack = true;
+ return (true);
} else {
/* Start new epoch, if the previous one is already over. */
now = getsbinuptime();
- if (tp->t_challenge_ack_end < now) {
- tp->t_challenge_ack_cnt = 0;
- tp->t_challenge_ack_end = now +
- V_tcp_ack_war_time_window * SBT_1MS;
+ if (*epoch_end < now) {
+ *ack_cnt = 0;
+ *epoch_end = now + V_tcp_ack_war_time_window * SBT_1MS;
}
/*
* Send a challenge ACK, if less than tcp_ack_war_cnt have been
* sent in the current epoch.
*/
- if (tp->t_challenge_ack_cnt < V_tcp_ack_war_cnt) {
- send_challenge_ack = true;
- tp->t_challenge_ack_cnt++;
+ if (*ack_cnt < V_tcp_ack_war_cnt) {
+ (*ack_cnt)++;
+ return (true);
} else {
- send_challenge_ack = false;
+ return (false);
}
}
- if (send_challenge_ack) {
+}
+
+/*
+ * Send a challenge ack (no data, no SACK option), but not more than
+ * V_tcp_ack_war_cnt per V_tcp_ack_war_time_window (per TCP connection).
+ */
+void
+tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
+{
+ if (tcp_challenge_ack_check(&tp->t_challenge_ack_end,
+ &tp->t_challenge_ack_cnt)) {
tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt,
tp->snd_nxt, TH_ACK);
tp->last_ack_sent = tp->rcv_nxt;
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 1ee6c6e31f33..def6bc886617 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -122,6 +122,7 @@ static void syncache_drop(struct syncache *, struct syncache_head *);
static void syncache_free(struct syncache *);
static void syncache_insert(struct syncache *, struct syncache_head *);
static int syncache_respond(struct syncache *, const struct mbuf *, int);
+static void syncache_send_challenge_ack(struct syncache *, struct mbuf *);
static struct socket *syncache_socket(struct syncache *, struct socket *,
struct mbuf *m);
static void syncache_timeout(struct syncache *sc, struct syncache_head *sch,
@@ -694,13 +695,7 @@ syncache_chkrst(struct in_conninfo *inc, struct tcphdr *th, struct mbuf *m,
"sending challenge ACK\n",
s, __func__,
th->th_seq, sc->sc_irs + 1, sc->sc_wnd);
- if (syncache_respond(sc, m, TH_ACK) == 0) {
- TCPSTAT_INC(tcps_sndacks);
- TCPSTAT_INC(tcps_sndtotal);
- } else {
- syncache_drop(sc, sch);
- TCPSTAT_INC(tcps_sc_dropped);
- }
+ syncache_send_challenge_ack(sc, m);
}
} else {
if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
@@ -963,6 +958,10 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
if (sc->sc_rxmits > 1)
tp->snd_cwnd = 1;
+ /* Copy over the challenge ACK state. */
+ tp->t_challenge_ack_end = sc->sc_challenge_ack_end;
+ tp->t_challenge_ack_cnt = sc->sc_challenge_ack_cnt;
+
#ifdef TCP_OFFLOAD
/*
* Allow a TOE driver to install its hooks. Note that we hold the
@@ -1202,7 +1201,6 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
*/
if (sc->sc_flags & SCF_TIMESTAMP && to->to_flags & TOF_TS &&
TSTMP_LT(to->to_tsval, sc->sc_tsreflect)) {
- SCH_UNLOCK(sch);
if ((s = tcp_log_addrs(inc, th, NULL, NULL))) {
log(LOG_DEBUG,
"%s; %s: SEG.TSval %u < TS.Recent %u, "
@@ -1210,6 +1208,7 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
to->to_tsval, sc->sc_tsreflect);
free(s, M_TCPLOG);
}
+ SCH_UNLOCK(sch);
return (-1); /* Do not send RST */
}
@@ -1258,6 +1257,37 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
return (-1); /* Do not send RST */
}
}
+
+ /*
+ * SEG.SEQ validation:
+ * The SEG.SEQ must be in the window starting at our
+ * initial receive sequence number + 1.
+ */
+ if (SEQ_LEQ(th->th_seq, sc->sc_irs) ||
+ SEQ_GT(th->th_seq, sc->sc_irs + sc->sc_wnd)) {
+ if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
+ log(LOG_DEBUG, "%s; %s: SEQ %u != IRS+1 %u, "
+ "sending challenge ACK\n",
+ s, __func__, th->th_seq, sc->sc_irs + 1);
+ syncache_send_challenge_ack(sc, m);
+ SCH_UNLOCK(sch);
+ free(s, M_TCPLOG);
+ return (-1); /* Do not send RST */;
+ }
+
+ /*
+ * SEG.ACK validation:
+ * SEG.ACK must match our initial send sequence number + 1.
+ */
+ if (th->th_ack != sc->sc_iss + 1) {
+ if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
+ log(LOG_DEBUG, "%s; %s: ACK %u != ISS+1 %u, "
+ "segment rejected\n",
+ s, __func__, th->th_ack, sc->sc_iss + 1);
+ SCH_UNLOCK(sch);
+ goto failed;
+ }
+
TAILQ_REMOVE(&sch->sch_bucket, sc, sc_hash);
sch->sch_length--;
#ifdef TCP_OFFLOAD
@@ -1270,29 +1300,6 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
SCH_UNLOCK(sch);
}
- /*
- * Segment validation:
- * ACK must match our initial sequence number + 1 (the SYN|ACK).
- */
- if (th->th_ack != sc->sc_iss + 1) {
- if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
- log(LOG_DEBUG, "%s; %s: ACK %u != ISS+1 %u, segment "
- "rejected\n", s, __func__, th->th_ack, sc->sc_iss);
- goto failed;
- }
-
- /*
- * The SEQ must fall in the window starting at the received
- * initial receive sequence number + 1 (the SYN).
- */
- if (SEQ_LEQ(th->th_seq, sc->sc_irs) ||
- SEQ_GT(th->th_seq, sc->sc_irs + sc->sc_wnd)) {
- if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
- log(LOG_DEBUG, "%s; %s: SEQ %u != IRS+1 %u, segment "
- "rejected\n", s, __func__, th->th_seq, sc->sc_irs);
- goto failed;
- }
-
*lsop = syncache_socket(sc, *lsop, m);
if (__predict_false(*lsop == NULL)) {
@@ -2053,6 +2060,18 @@ syncache_respond(struct syncache *sc, const struct mbuf *m0, int flags)
return (error);
}
+static void
+syncache_send_challenge_ack(struct syncache *sc, struct mbuf *m)
+{
+ if (tcp_challenge_ack_check(&sc->sc_challenge_ack_end,
+ &sc->sc_challenge_ack_cnt)) {
+ if (syncache_respond(sc, m, TH_ACK) == 0) {
+ TCPSTAT_INC(tcps_sndacks);
+ TCPSTAT_INC(tcps_sndtotal);
+ }
+ }
+}
+
/*
* The purpose of syncookies is to handle spoofed SYN flooding DoS attacks
* that exceed the capacity of the syncache by avoiding the storage of any
diff --git a/sys/netinet/tcp_syncache.h b/sys/netinet/tcp_syncache.h
index 55e062e35a54..37f6ff3d6ca9 100644
--- a/sys/netinet/tcp_syncache.h
+++ b/sys/netinet/tcp_syncache.h
@@ -50,7 +50,7 @@ int syncache_pcblist(struct sysctl_req *);
struct syncache {
TAILQ_ENTRY(syncache) sc_hash;
- struct in_conninfo sc_inc; /* addresses */
+ struct in_conninfo sc_inc; /* addresses */
int sc_rxttime; /* retransmit time */
u_int16_t sc_rxmits; /* retransmit counter */
u_int16_t sc_port; /* remote UDP encaps port */
@@ -59,7 +59,7 @@ struct syncache {
u_int32_t sc_flowlabel; /* IPv6 flowlabel */
tcp_seq sc_irs; /* seq from peer */
tcp_seq sc_iss; /* our ISS */
- struct mbuf *sc_ipopts; /* source route */
+ struct mbuf *sc_ipopts; /* source route */
u_int16_t sc_peer_mss; /* peer's MSS */
u_int16_t sc_wnd; /* advertised window */
u_int8_t sc_ip_ttl; /* TTL / Hop Limit */
@@ -67,6 +67,8 @@ struct syncache {
u_int8_t sc_requested_s_scale:4,
sc_requested_r_scale:4;
u_int16_t sc_flags;
+ u_int32_t sc_challenge_ack_cnt; /* chall. ACKs sent in epoch */
+ sbintime_t sc_challenge_ack_end; /* End of chall. ack epoch */
#if defined(TCP_OFFLOAD)
struct toedev *sc_tod; /* entry added by this TOE */
void *sc_todctx; /* TOE driver context */
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 53856bae9a66..c3be95c80798 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1462,6 +1462,7 @@ int tcp_default_output(struct tcpcb *);
void tcp_state_change(struct tcpcb *, int);
void tcp_respond(struct tcpcb *, void *,
struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, uint16_t);
+bool tcp_challenge_ack_check(sbintime_t *, uint32_t *);
void tcp_send_challenge_ack(struct tcpcb *, struct tcphdr *, struct mbuf *);
bool tcp_twcheck(struct inpcb *, struct tcpopt *, struct tcphdr *,
struct mbuf *, int);