Commit 6ec6f76e authored by David S. Miller's avatar David S. Miller

[NETFILTER]: Teach ip_fw_compat and modules to handle non-linear SKBs.

Much help provided by Rusty Russell in fixing device leak
and TOS modification handling bugs.
parent a3bc528c
......@@ -21,20 +21,20 @@ struct firewall_ops
{
struct firewall_ops *next;
int (*fw_forward)(struct firewall_ops *this, int pf,
struct net_device *dev, void *phdr, void *arg,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
int (*fw_input)(struct firewall_ops *this, int pf,
struct net_device *dev, void *phdr, void *arg,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
int (*fw_output)(struct firewall_ops *this, int pf,
struct net_device *dev, void *phdr, void *arg,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
/* These may be NULL. */
int (*fw_acct_in)(struct firewall_ops *this, int pf,
struct net_device *dev, void *phdr, void *arg,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
int (*fw_acct_out)(struct firewall_ops *this, int pf,
struct net_device *dev, void *phdr, void *arg,
struct net_device *dev, void *arg,
struct sk_buff **pskb);
};
......
......@@ -250,7 +250,7 @@ extern int ip_masq_ctl(int, void *, int);
extern int ip_fw_masq_timeouts(void *user, int len);
extern int ip_fw_chk(struct iphdr *, struct net_device *, __u16 *,
extern int ip_fw_chk(struct sk_buff **, struct net_device *, __u16 *,
struct ip_fw *, int, int);
#endif /* KERNEL */
#endif /* _IP_FW_H */
......@@ -51,31 +51,17 @@ fw_in(unsigned int hooknum,
int ret = FW_BLOCK;
u_int16_t redirpt;
/* FIXME: Push down to extensions --RR */
if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
return NF_DROP;
/* Assume worse case: any hook could change packet */
(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
if ((*pskb)->ip_summed == CHECKSUM_HW)
(*pskb)->ip_summed = CHECKSUM_NONE;
/* Firewall rules can alter TOS: raw socket (tcpdump) may have
clone of incoming skb: don't disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
}
switch (hooknum) {
case NF_IP_PRE_ROUTING:
if (fwops->fw_acct_in)
fwops->fw_acct_in(fwops, PF_INET,
(struct net_device *)in,
(*pskb)->nh.raw, &redirpt, pskb);
&redirpt, pskb);
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
*pskb = ip_ct_gather_frags(*pskb);
......@@ -85,7 +71,7 @@ fw_in(unsigned int hooknum,
}
ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
(*pskb)->nh.raw, &redirpt, pskb);
&redirpt, pskb);
break;
case NF_IP_FORWARD:
......@@ -95,18 +81,18 @@ fw_in(unsigned int hooknum,
ret = FW_ACCEPT;
else ret = fwops->fw_forward(fwops, PF_INET,
(struct net_device *)out,
(*pskb)->nh.raw, &redirpt, pskb);
&redirpt, pskb);
break;
case NF_IP_POST_ROUTING:
ret = fwops->fw_output(fwops, PF_INET,
(struct net_device *)out,
(*pskb)->nh.raw, &redirpt, pskb);
&redirpt, pskb);
if (ret == FW_ACCEPT || ret == FW_SKIP) {
if (fwops->fw_acct_out)
fwops->fw_acct_out(fwops, PF_INET,
(struct net_device *)out,
(*pskb)->nh.raw, &redirpt,
&redirpt,
pskb);
/* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
......@@ -169,10 +155,6 @@ static unsigned int fw_confirm(unsigned int hooknum,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* FIXME: Push down to extensions --RR */
if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
return NF_DROP;
return ip_conntrack_confirm(*pskb);
}
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment