X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fnetfilter%2Fnf_conntrack_proto_tcp.c;h=6492ed66fb3c6cb033d9db835cc0eac006ce8fa3;hb=489447380a2921ec0e9154f773c44ab3167ede4b;hp=83d90dd624f05638fd0aac1e99e6583c4eeb69e2;hpb=b8cbfa692485bf7568eda3d2f37545a76efb7c93;p=linux-2.6 diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 83d90dd624..6492ed66fb 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -93,21 +93,21 @@ static const char *tcp_conntrack_names[] = { #define HOURS * 60 MINS #define DAYS * 24 HOURS -unsigned long nf_ct_tcp_timeout_syn_sent = 2 MINS; -unsigned long nf_ct_tcp_timeout_syn_recv = 60 SECS; -unsigned long nf_ct_tcp_timeout_established = 5 DAYS; -unsigned long nf_ct_tcp_timeout_fin_wait = 2 MINS; -unsigned long nf_ct_tcp_timeout_close_wait = 60 SECS; -unsigned long nf_ct_tcp_timeout_last_ack = 30 SECS; -unsigned long nf_ct_tcp_timeout_time_wait = 2 MINS; -unsigned long nf_ct_tcp_timeout_close = 10 SECS; +unsigned int nf_ct_tcp_timeout_syn_sent = 2 MINS; +unsigned int nf_ct_tcp_timeout_syn_recv = 60 SECS; +unsigned int nf_ct_tcp_timeout_established = 5 DAYS; +unsigned int nf_ct_tcp_timeout_fin_wait = 2 MINS; +unsigned int nf_ct_tcp_timeout_close_wait = 60 SECS; +unsigned int nf_ct_tcp_timeout_last_ack = 30 SECS; +unsigned int nf_ct_tcp_timeout_time_wait = 2 MINS; +unsigned int nf_ct_tcp_timeout_close = 10 SECS; /* RFC1122 says the R2 limit should be at least 100 seconds. Linux uses 15 packets as limit, which corresponds to ~13-30min depending on RTO. */ -unsigned long nf_ct_tcp_timeout_max_retrans = 5 MINS; +unsigned int nf_ct_tcp_timeout_max_retrans = 5 MINS; -static unsigned long * tcp_timeouts[] +static unsigned int * tcp_timeouts[] = { NULL, /* TCP_CONNTRACK_NONE */ &nf_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ &nf_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ @@ -280,9 +280,9 @@ static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { * sCL -> sCL */ /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ -/*ack*/ { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, +/*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, /* - * sSS -> sIV Might be a half-open connection. + * sSS -> sIG Might be a half-open connection. * sSR -> sSR Might answer late resent SYN. * sES -> sES :-) * sFW -> sCW Normal close request answered by ACK. @@ -779,6 +779,7 @@ static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] = { [TH_SYN] = 1, [TH_SYN|TH_ACK] = 1, + [TH_SYN|TH_PUSH] = 1, [TH_SYN|TH_ACK|TH_PUSH] = 1, [TH_RST] = 1, [TH_RST|TH_ACK] = 1, @@ -863,7 +864,9 @@ static int csum6(const struct sk_buff *skb, unsigned int dataoff) { return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, skb->len - dataoff, IPPROTO_TCP, - skb->ip_summed == CHECKSUM_HW ? skb->csum + skb->ip_summed == CHECKSUM_HW + ? csum_sub(skb->csum, + skb_checksum(skb, 0, dataoff, 0)) : skb_checksum(skb, dataoff, skb->len - dataoff, 0)); } @@ -911,8 +914,12 @@ static int tcp_packet(struct nf_conn *conntrack, switch (new_state) { case TCP_CONNTRACK_IGNORE: - /* Either SYN in ORIGINAL - * or SYN/ACK in REPLY. */ + /* Ignored packets: + * + * a) SYN in ORIGINAL + * b) SYN/ACK in REPLY + * c) ACK in reply direction after initial SYN in original. + */ if (index == TCP_SYNACK_SET && conntrack->proto.tcp.last_index == TCP_SYN_SET && conntrack->proto.tcp.last_dir != dir @@ -969,19 +976,32 @@ static int tcp_packet(struct nf_conn *conntrack, conntrack->timeout.function((unsigned long) conntrack); return -NF_REPEAT; + } else { + write_unlock_bh(&tcp_lock); + if (LOG_INVALID(IPPROTO_TCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, + NULL, "nf_ct_tcp: invalid SYN"); + return -NF_ACCEPT; } case TCP_CONNTRACK_CLOSE: if (index == TCP_RST_SET - && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) - && conntrack->proto.tcp.last_index == TCP_SYN_SET + && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) + && conntrack->proto.tcp.last_index == TCP_SYN_SET) + || (!test_bit(IPS_ASSURED_BIT, &conntrack->status) + && conntrack->proto.tcp.last_index == TCP_ACK_SET)) && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { - /* RST sent to invalid SYN we had let trough - * SYN was in window then, tear down connection. + /* RST sent to invalid SYN or ACK we had let through + * at a) and c) above: + * + * a) SYN was in window then + * c) we hold a half-open connection. + * + * Delete our connection entry. * We skip window checking, because packet might ACK - * segments we ignored in the SYN. */ + * segments we ignored. */ goto in_window; } - /* Just fall trough */ + /* Just fall through */ default: /* Keep compilers happy. */ break; @@ -1129,6 +1149,63 @@ static int tcp_new(struct nf_conn *conntrack, receiver->td_scale); return 1; } + +#if defined(CONFIG_NF_CT_NETLINK) || \ + defined(CONFIG_NF_CT_NETLINK_MODULE) + +#include +#include + +static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, + const struct nf_conn *ct) +{ + struct nfattr *nest_parms; + + read_lock_bh(&tcp_lock); + nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP); + NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), + &ct->proto.tcp.state); + read_unlock_bh(&tcp_lock); + + NFA_NEST_END(skb, nest_parms); + + return 0; + +nfattr_failure: + read_unlock_bh(&tcp_lock); + return -1; +} + +static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = { + [CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t), +}; + +static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct) +{ + struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1]; + struct nfattr *tb[CTA_PROTOINFO_TCP_MAX]; + + /* updates could not contain anything about the private + * protocol info, in that case skip the parsing */ + if (!attr) + return 0; + + nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr); + + if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) + return -EINVAL; + + if (!tb[CTA_PROTOINFO_TCP_STATE-1]) + return -EINVAL; + + write_lock_bh(&tcp_lock); + ct->proto.tcp.state = + *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]); + write_unlock_bh(&tcp_lock); + + return 0; +} +#endif struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = { @@ -1142,6 +1219,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = .packet = tcp_packet, .new = tcp_new, .error = tcp_error4, +#if defined(CONFIG_NF_CT_NETLINK) || \ + defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nfattr = tcp_to_nfattr, + .from_nfattr = nfattr_to_tcp, + .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, + .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, +#endif }; struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = @@ -1156,6 +1240,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = .packet = tcp_packet, .new = tcp_new, .error = tcp_error6, +#if defined(CONFIG_NF_CT_NETLINK) || \ + defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nfattr = tcp_to_nfattr, + .from_nfattr = nfattr_to_tcp, + .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, + .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, +#endif }; EXPORT_SYMBOL(nf_conntrack_protocol_tcp4);