mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 15:27:29 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== netfilter/ipvs fixes for net The following patchset contains fixes for netfilter/ipvs. This round of fixes is larger than usual at this stage, specifically because of the nf_tables bridge reject fixes that I would like to see in 3.18. The patches are: 1) Fix a null-pointer dereference that may occur when logging errors. This problem was introduced by4a4739d56b
("ipvs: Pull out crosses_local_route_boundary logic") in v3.17-rc5. 2) Update hook mask in nft_reject_bridge so we can also filter out packets from there. This fixes36d2af5
("netfilter: nf_tables: allow to filter from prerouting and postrouting"), which needs this chunk to work. 3) Two patches to refactor common code to forge the IPv4 and IPv6 reject packets from the bridge. These are required by the nf_tables reject bridge fix. 4) Fix nft_reject_bridge by avoiding the use of the IP stack to reject packets from the bridge. The idea is to forge the reject packets and inject them to the original port via br_deliver() which is now exported for that purpose. 5) Restrict nft_reject_bridge to bridge prerouting and input hooks. the original skbuff may cloned after prerouting when the bridge stack needs to flood it to several bridge ports, it is too late to reject the traffic. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e3a88f9c4f
8 changed files with 498 additions and 122 deletions
|
@ -12,20 +12,131 @@
|
|||
#include <net/ip6_fib.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <linux/netfilter_ipv6.h>
|
||||
#include <net/netfilter/ipv6/nf_reject.h>
|
||||
|
||||
const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb,
|
||||
struct tcphdr *otcph,
|
||||
unsigned int *otcplen, int hook)
|
||||
{
|
||||
const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
|
||||
u8 proto;
|
||||
__be16 frag_off;
|
||||
int tcphoff;
|
||||
|
||||
proto = oip6h->nexthdr;
|
||||
tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
|
||||
&proto, &frag_off);
|
||||
|
||||
if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
|
||||
pr_debug("Cannot get TCP header.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*otcplen = oldskb->len - tcphoff;
|
||||
|
||||
/* IP header checks: fragment, too short. */
|
||||
if (proto != IPPROTO_TCP || *otcplen < sizeof(struct tcphdr)) {
|
||||
pr_debug("proto(%d) != IPPROTO_TCP or too short (len = %d)\n",
|
||||
proto, *otcplen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
otcph = skb_header_pointer(oldskb, tcphoff, sizeof(struct tcphdr),
|
||||
otcph);
|
||||
if (otcph == NULL)
|
||||
return NULL;
|
||||
|
||||
/* No RST for RST. */
|
||||
if (otcph->rst) {
|
||||
pr_debug("RST is set\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check checksum. */
|
||||
if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) {
|
||||
pr_debug("TCP checksum is invalid\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return otcph;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_get);
|
||||
|
||||
struct ipv6hdr *nf_reject_ip6hdr_put(struct sk_buff *nskb,
|
||||
const struct sk_buff *oldskb,
|
||||
__be16 protocol, int hoplimit)
|
||||
{
|
||||
struct ipv6hdr *ip6h;
|
||||
const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
|
||||
#define DEFAULT_TOS_VALUE 0x0U
|
||||
const __u8 tclass = DEFAULT_TOS_VALUE;
|
||||
|
||||
skb_put(nskb, sizeof(struct ipv6hdr));
|
||||
skb_reset_network_header(nskb);
|
||||
ip6h = ipv6_hdr(nskb);
|
||||
ip6_flow_hdr(ip6h, tclass, 0);
|
||||
ip6h->hop_limit = hoplimit;
|
||||
ip6h->nexthdr = protocol;
|
||||
ip6h->saddr = oip6h->daddr;
|
||||
ip6h->daddr = oip6h->saddr;
|
||||
|
||||
nskb->protocol = htons(ETH_P_IPV6);
|
||||
|
||||
return ip6h;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_reject_ip6hdr_put);
|
||||
|
||||
void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
|
||||
const struct sk_buff *oldskb,
|
||||
const struct tcphdr *oth, unsigned int otcplen)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
int needs_ack;
|
||||
|
||||
skb_reset_transport_header(nskb);
|
||||
tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
|
||||
/* Truncate to length (no data) */
|
||||
tcph->doff = sizeof(struct tcphdr)/4;
|
||||
tcph->source = oth->dest;
|
||||
tcph->dest = oth->source;
|
||||
|
||||
if (oth->ack) {
|
||||
needs_ack = 0;
|
||||
tcph->seq = oth->ack_seq;
|
||||
tcph->ack_seq = 0;
|
||||
} else {
|
||||
needs_ack = 1;
|
||||
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
|
||||
otcplen - (oth->doff<<2));
|
||||
tcph->seq = 0;
|
||||
}
|
||||
|
||||
/* Reset flags */
|
||||
((u_int8_t *)tcph)[13] = 0;
|
||||
tcph->rst = 1;
|
||||
tcph->ack = needs_ack;
|
||||
tcph->window = 0;
|
||||
tcph->urg_ptr = 0;
|
||||
tcph->check = 0;
|
||||
|
||||
/* Adjust TCP checksum */
|
||||
tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
|
||||
&ipv6_hdr(nskb)->daddr,
|
||||
sizeof(struct tcphdr), IPPROTO_TCP,
|
||||
csum_partial(tcph,
|
||||
sizeof(struct tcphdr), 0));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_put);
|
||||
|
||||
void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
struct tcphdr otcph, *tcph;
|
||||
struct tcphdr _otcph;
|
||||
const struct tcphdr *otcph;
|
||||
unsigned int otcplen, hh_len;
|
||||
int tcphoff, needs_ack;
|
||||
const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
|
||||
struct ipv6hdr *ip6h;
|
||||
#define DEFAULT_TOS_VALUE 0x0U
|
||||
const __u8 tclass = DEFAULT_TOS_VALUE;
|
||||
struct dst_entry *dst = NULL;
|
||||
u8 proto;
|
||||
__be16 frag_off;
|
||||
struct flowi6 fl6;
|
||||
|
||||
if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
|
||||
|
@ -34,45 +145,16 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
|
|||
return;
|
||||
}
|
||||
|
||||
proto = oip6h->nexthdr;
|
||||
tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);
|
||||
|
||||
if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
|
||||
pr_debug("Cannot get TCP header.\n");
|
||||
otcph = nf_reject_ip6_tcphdr_get(oldskb, &_otcph, &otcplen, hook);
|
||||
if (!otcph)
|
||||
return;
|
||||
}
|
||||
|
||||
otcplen = oldskb->len - tcphoff;
|
||||
|
||||
/* IP header checks: fragment, too short. */
|
||||
if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
|
||||
pr_debug("proto(%d) != IPPROTO_TCP, "
|
||||
"or too short. otcplen = %d\n",
|
||||
proto, otcplen);
|
||||
return;
|
||||
}
|
||||
|
||||
if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
|
||||
BUG();
|
||||
|
||||
/* No RST for RST. */
|
||||
if (otcph.rst) {
|
||||
pr_debug("RST is set\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check checksum. */
|
||||
if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) {
|
||||
pr_debug("TCP checksum is invalid\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&fl6, 0, sizeof(fl6));
|
||||
fl6.flowi6_proto = IPPROTO_TCP;
|
||||
fl6.saddr = oip6h->daddr;
|
||||
fl6.daddr = oip6h->saddr;
|
||||
fl6.fl6_sport = otcph.dest;
|
||||
fl6.fl6_dport = otcph.source;
|
||||
fl6.fl6_sport = otcph->dest;
|
||||
fl6.fl6_dport = otcph->source;
|
||||
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
|
||||
dst = ip6_route_output(net, NULL, &fl6);
|
||||
if (dst == NULL || dst->error) {
|
||||
|
@ -97,48 +179,9 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
|
|||
skb_dst_set(nskb, dst);
|
||||
|
||||
skb_reserve(nskb, hh_len + dst->header_len);
|
||||
|
||||
skb_put(nskb, sizeof(struct ipv6hdr));
|
||||
skb_reset_network_header(nskb);
|
||||
ip6h = ipv6_hdr(nskb);
|
||||
ip6_flow_hdr(ip6h, tclass, 0);
|
||||
ip6h->hop_limit = ip6_dst_hoplimit(dst);
|
||||
ip6h->nexthdr = IPPROTO_TCP;
|
||||
ip6h->saddr = oip6h->daddr;
|
||||
ip6h->daddr = oip6h->saddr;
|
||||
|
||||
skb_reset_transport_header(nskb);
|
||||
tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
|
||||
/* Truncate to length (no data) */
|
||||
tcph->doff = sizeof(struct tcphdr)/4;
|
||||
tcph->source = otcph.dest;
|
||||
tcph->dest = otcph.source;
|
||||
|
||||
if (otcph.ack) {
|
||||
needs_ack = 0;
|
||||
tcph->seq = otcph.ack_seq;
|
||||
tcph->ack_seq = 0;
|
||||
} else {
|
||||
needs_ack = 1;
|
||||
tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
|
||||
+ otcplen - (otcph.doff<<2));
|
||||
tcph->seq = 0;
|
||||
}
|
||||
|
||||
/* Reset flags */
|
||||
((u_int8_t *)tcph)[13] = 0;
|
||||
tcph->rst = 1;
|
||||
tcph->ack = needs_ack;
|
||||
tcph->window = 0;
|
||||
tcph->urg_ptr = 0;
|
||||
tcph->check = 0;
|
||||
|
||||
/* Adjust TCP checksum */
|
||||
tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
|
||||
&ipv6_hdr(nskb)->daddr,
|
||||
sizeof(struct tcphdr), IPPROTO_TCP,
|
||||
csum_partial(tcph,
|
||||
sizeof(struct tcphdr), 0));
|
||||
ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
|
||||
ip6_dst_hoplimit(dst));
|
||||
nf_reject_ip6_tcphdr_put(nskb, oldskb, otcph, otcplen);
|
||||
|
||||
nf_ct_attach(nskb, oldskb);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue