Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next The following patchset contains Netfilter updates for net-next: 1) Use array_size() in ebtables, from Gustavo A. R. Silva. 2) Attach IPS_ASSURED to internal UDP stream state, reported by Maciej Zenczykowski. 3) Add NFT_META_IFTYPE to match on the interface type either from ingress or egress. 4) Generalize pktinfo->tprot_set to flags field. 5) Allow to match on inner headers / payload data. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
894d084434
|
@ -21,13 +21,19 @@ struct module;
|
|||
|
||||
#define NFT_JUMP_STACK_SIZE 16
|
||||
|
||||
enum {
|
||||
NFT_PKTINFO_L4PROTO = (1 << 0),
|
||||
NFT_PKTINFO_INNER = (1 << 1),
|
||||
};
|
||||
|
||||
struct nft_pktinfo {
|
||||
struct sk_buff *skb;
|
||||
const struct nf_hook_state *state;
|
||||
bool tprot_set;
|
||||
u8 flags;
|
||||
u8 tprot;
|
||||
u16 fragoff;
|
||||
unsigned int thoff;
|
||||
unsigned int inneroff;
|
||||
};
|
||||
|
||||
static inline struct sock *nft_sk(const struct nft_pktinfo *pkt)
|
||||
|
@ -75,7 +81,7 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
|
|||
|
||||
static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt)
|
||||
{
|
||||
pkt->tprot_set = false;
|
||||
pkt->flags = 0;
|
||||
pkt->tprot = 0;
|
||||
pkt->thoff = 0;
|
||||
pkt->fragoff = 0;
|
||||
|
|
|
@ -10,7 +10,7 @@ static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt)
|
|||
struct iphdr *ip;
|
||||
|
||||
ip = ip_hdr(pkt->skb);
|
||||
pkt->tprot_set = true;
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = ip->protocol;
|
||||
pkt->thoff = ip_hdrlen(pkt->skb);
|
||||
pkt->fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
||||
|
@ -36,7 +36,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt)
|
|||
else if (len < thoff)
|
||||
return -1;
|
||||
|
||||
pkt->tprot_set = true;
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = iph->protocol;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
|
@ -71,7 +71,7 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt)
|
|||
goto inhdr_error;
|
||||
}
|
||||
|
||||
pkt->tprot_set = true;
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = iph->protocol;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
|
@ -82,4 +82,5 @@ inhdr_error:
|
|||
__IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INHDRERRORS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,7 @@ static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt)
|
|||
return;
|
||||
}
|
||||
|
||||
pkt->tprot_set = true;
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
|
@ -50,7 +50,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt)
|
|||
if (protohdr < 0)
|
||||
return -1;
|
||||
|
||||
pkt->tprot_set = true;
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
|
@ -96,7 +96,7 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt)
|
|||
if (protohdr < 0)
|
||||
goto inhdr_error;
|
||||
|
||||
pkt->tprot_set = true;
|
||||
pkt->flags = NFT_PKTINFO_L4PROTO;
|
||||
pkt->tprot = protohdr;
|
||||
pkt->thoff = thoff;
|
||||
pkt->fragoff = frag_off;
|
||||
|
|
|
@ -753,11 +753,13 @@ enum nft_dynset_attributes {
|
|||
* @NFT_PAYLOAD_LL_HEADER: link layer header
|
||||
* @NFT_PAYLOAD_NETWORK_HEADER: network header
|
||||
* @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
|
||||
* @NFT_PAYLOAD_INNER_HEADER: inner header / payload
|
||||
*/
|
||||
enum nft_payload_bases {
|
||||
NFT_PAYLOAD_LL_HEADER,
|
||||
NFT_PAYLOAD_NETWORK_HEADER,
|
||||
NFT_PAYLOAD_TRANSPORT_HEADER,
|
||||
NFT_PAYLOAD_INNER_HEADER,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -896,7 +898,8 @@ enum nft_meta_keys {
|
|||
NFT_META_OIF,
|
||||
NFT_META_IIFNAME,
|
||||
NFT_META_OIFNAME,
|
||||
NFT_META_IIFTYPE,
|
||||
NFT_META_IFTYPE,
|
||||
#define NFT_META_IIFTYPE NFT_META_IFTYPE
|
||||
NFT_META_OIFTYPE,
|
||||
NFT_META_SKUID,
|
||||
NFT_META_SKGID,
|
||||
|
@ -923,6 +926,7 @@ enum nft_meta_keys {
|
|||
NFT_META_TIME_HOUR,
|
||||
NFT_META_SDIF,
|
||||
NFT_META_SDIFNAME,
|
||||
__NFT_META_IIFTYPE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1073,7 +1073,7 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
|
|||
*/
|
||||
if (repl->num_counters &&
|
||||
copy_to_user(repl->counters, counterstmp,
|
||||
repl->num_counters * sizeof(struct ebt_counter))) {
|
||||
array_size(repl->num_counters, sizeof(struct ebt_counter)))) {
|
||||
/* Silent error, can't fail, new table is already in place */
|
||||
net_warn_ratelimited("ebtables: counters copy to user failed while replacing table\n");
|
||||
}
|
||||
|
@ -1401,7 +1401,8 @@ static int do_update_counters(struct net *net, const char *name,
|
|||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
if (copy_from_user(tmp, counters, num_counters * sizeof(*counters))) {
|
||||
if (copy_from_user(tmp, counters,
|
||||
array_size(num_counters, sizeof(*counters)))) {
|
||||
ret = -EFAULT;
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
@ -1534,7 +1535,7 @@ static int copy_counters_to_user(struct ebt_table *t,
|
|||
write_unlock_bh(&t->lock);
|
||||
|
||||
if (copy_to_user(user, counterstmp,
|
||||
nentries * sizeof(struct ebt_counter)))
|
||||
array_size(nentries, sizeof(struct ebt_counter))))
|
||||
ret = -EFAULT;
|
||||
vfree(counterstmp);
|
||||
return ret;
|
||||
|
|
|
@ -104,10 +104,13 @@ int nf_conntrack_udp_packet(struct nf_conn *ct,
|
|||
*/
|
||||
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
|
||||
unsigned long extra = timeouts[UDP_CT_UNREPLIED];
|
||||
bool stream = false;
|
||||
|
||||
/* Still active after two seconds? Extend timeout. */
|
||||
if (time_after(jiffies, ct->proto.udp.stream_ts))
|
||||
if (time_after(jiffies, ct->proto.udp.stream_ts)) {
|
||||
extra = timeouts[UDP_CT_REPLIED];
|
||||
stream = true;
|
||||
}
|
||||
|
||||
nf_ct_refresh_acct(ct, ctinfo, skb, extra);
|
||||
|
||||
|
@ -116,7 +119,7 @@ int nf_conntrack_udp_packet(struct nf_conn *ct,
|
|||
return NF_ACCEPT;
|
||||
|
||||
/* Also, more likely to be important, and not a probe */
|
||||
if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
|
||||
if (stream && !test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
|
||||
nf_conntrack_event_cache(IPCT_ASSURED, ct);
|
||||
} else {
|
||||
nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[UDP_CT_UNREPLIED]);
|
||||
|
|
|
@ -79,7 +79,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
|
|||
if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
|
||||
ptr = skb_network_header(skb);
|
||||
else {
|
||||
if (!pkt->tprot_set)
|
||||
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
|
||||
return false;
|
||||
ptr = skb_network_header(skb) + nft_thoff(pkt);
|
||||
}
|
||||
|
|
|
@ -113,13 +113,13 @@ static int nf_trace_fill_pkt_info(struct sk_buff *nlskb,
|
|||
int off = skb_network_offset(skb);
|
||||
unsigned int len, nh_end;
|
||||
|
||||
nh_end = pkt->tprot_set ? nft_thoff(pkt) : skb->len;
|
||||
nh_end = pkt->flags & NFT_PKTINFO_L4PROTO ? nft_thoff(pkt) : skb->len;
|
||||
len = min_t(unsigned int, nh_end - skb_network_offset(skb),
|
||||
NFT_TRACETYPE_NETWORK_HSIZE);
|
||||
if (trace_fill_header(nlskb, NFTA_TRACE_NETWORK_HEADER, skb, off, len))
|
||||
return -1;
|
||||
|
||||
if (pkt->tprot_set) {
|
||||
if (pkt->flags & NFT_PKTINFO_L4PROTO) {
|
||||
len = min_t(unsigned int, skb->len - nft_thoff(pkt),
|
||||
NFT_TRACETYPE_TRANSPORT_HSIZE);
|
||||
if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb,
|
||||
|
|
|
@ -244,7 +244,11 @@ static bool nft_meta_get_eval_ifname(enum nft_meta_keys key, u32 *dest,
|
|||
case NFT_META_OIF:
|
||||
nft_meta_store_ifindex(dest, nft_out(pkt));
|
||||
break;
|
||||
case NFT_META_IIFTYPE:
|
||||
case NFT_META_IFTYPE:
|
||||
if (!nft_meta_store_iftype(dest, pkt->skb->dev))
|
||||
return false;
|
||||
break;
|
||||
case __NFT_META_IIFTYPE:
|
||||
if (!nft_meta_store_iftype(dest, nft_in(pkt)))
|
||||
return false;
|
||||
break;
|
||||
|
@ -329,7 +333,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
|
|||
nft_reg_store8(dest, nft_pf(pkt));
|
||||
break;
|
||||
case NFT_META_L4PROTO:
|
||||
if (!pkt->tprot_set)
|
||||
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
|
||||
goto err;
|
||||
nft_reg_store8(dest, pkt->tprot);
|
||||
break;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/icmpv6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/sctp/checksum.h>
|
||||
|
||||
static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off,
|
||||
|
@ -79,6 +80,45 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
|
|||
return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0;
|
||||
}
|
||||
|
||||
static int __nft_payload_inner_offset(struct nft_pktinfo *pkt)
|
||||
{
|
||||
unsigned int thoff = nft_thoff(pkt);
|
||||
|
||||
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
|
||||
return -1;
|
||||
|
||||
switch (pkt->tprot) {
|
||||
case IPPROTO_UDP:
|
||||
pkt->inneroff = thoff + sizeof(struct udphdr);
|
||||
break;
|
||||
case IPPROTO_TCP: {
|
||||
struct tcphdr *th, _tcph;
|
||||
|
||||
th = skb_header_pointer(pkt->skb, thoff, sizeof(_tcph), &_tcph);
|
||||
if (!th)
|
||||
return -1;
|
||||
|
||||
pkt->inneroff = thoff + __tcp_hdrlen(th);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
pkt->flags |= NFT_PKTINFO_INNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_payload_inner_offset(const struct nft_pktinfo *pkt)
|
||||
{
|
||||
if (!(pkt->flags & NFT_PKTINFO_INNER) &&
|
||||
__nft_payload_inner_offset((struct nft_pktinfo *)pkt) < 0)
|
||||
return -1;
|
||||
|
||||
return pkt->inneroff;
|
||||
}
|
||||
|
||||
void nft_payload_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
|
@ -108,10 +148,15 @@ void nft_payload_eval(const struct nft_expr *expr,
|
|||
offset = skb_network_offset(skb);
|
||||
break;
|
||||
case NFT_PAYLOAD_TRANSPORT_HEADER:
|
||||
if (!pkt->tprot_set)
|
||||
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
|
||||
goto err;
|
||||
offset = nft_thoff(pkt);
|
||||
break;
|
||||
case NFT_PAYLOAD_INNER_HEADER:
|
||||
offset = nft_payload_inner_offset(pkt);
|
||||
if (offset < 0)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
@ -610,10 +655,15 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
|
|||
offset = skb_network_offset(skb);
|
||||
break;
|
||||
case NFT_PAYLOAD_TRANSPORT_HEADER:
|
||||
if (!pkt->tprot_set)
|
||||
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
|
||||
goto err;
|
||||
offset = nft_thoff(pkt);
|
||||
break;
|
||||
case NFT_PAYLOAD_INNER_HEADER:
|
||||
offset = nft_payload_inner_offset(pkt);
|
||||
if (offset < 0)
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
@ -622,7 +672,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
|
|||
offset += priv->offset;
|
||||
|
||||
if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
|
||||
(priv->base != NFT_PAYLOAD_TRANSPORT_HEADER ||
|
||||
((priv->base != NFT_PAYLOAD_TRANSPORT_HEADER &&
|
||||
priv->base != NFT_PAYLOAD_INNER_HEADER) ||
|
||||
skb->ip_summed != CHECKSUM_PARTIAL)) {
|
||||
fsum = skb_checksum(skb, offset, priv->len, 0);
|
||||
tsum = csum_partial(src, priv->len, 0);
|
||||
|
@ -741,6 +792,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
|
|||
case NFT_PAYLOAD_LL_HEADER:
|
||||
case NFT_PAYLOAD_NETWORK_HEADER:
|
||||
case NFT_PAYLOAD_TRANSPORT_HEADER:
|
||||
case NFT_PAYLOAD_INNER_HEADER:
|
||||
break;
|
||||
default:
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
@ -759,7 +811,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
|
|||
len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
|
||||
|
||||
if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
|
||||
base != NFT_PAYLOAD_LL_HEADER)
|
||||
base != NFT_PAYLOAD_LL_HEADER && base != NFT_PAYLOAD_INNER_HEADER)
|
||||
return &nft_payload_fast_ops;
|
||||
else
|
||||
return &nft_payload_ops;
|
||||
|
|
Loading…
Reference in New Issue