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 ...@@ -21,20 +21,20 @@ struct firewall_ops
{ {
struct firewall_ops *next; struct firewall_ops *next;
int (*fw_forward)(struct firewall_ops *this, int pf, 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); struct sk_buff **pskb);
int (*fw_input)(struct firewall_ops *this, int pf, 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); struct sk_buff **pskb);
int (*fw_output)(struct firewall_ops *this, int pf, 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); struct sk_buff **pskb);
/* These may be NULL. */ /* These may be NULL. */
int (*fw_acct_in)(struct firewall_ops *this, int pf, 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); struct sk_buff **pskb);
int (*fw_acct_out)(struct firewall_ops *this, int pf, 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); struct sk_buff **pskb);
}; };
......
...@@ -250,7 +250,7 @@ extern int ip_masq_ctl(int, void *, int); ...@@ -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_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); struct ip_fw *, int, int);
#endif /* KERNEL */ #endif /* KERNEL */
#endif /* _IP_FW_H */ #endif /* _IP_FW_H */
...@@ -51,31 +51,17 @@ fw_in(unsigned int hooknum, ...@@ -51,31 +51,17 @@ fw_in(unsigned int hooknum,
int ret = FW_BLOCK; int ret = FW_BLOCK;
u_int16_t redirpt; 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 */ /* Assume worse case: any hook could change packet */
(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
if ((*pskb)->ip_summed == CHECKSUM_HW) if ((*pskb)->ip_summed == CHECKSUM_HW)
(*pskb)->ip_summed = CHECKSUM_NONE; (*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) { switch (hooknum) {
case NF_IP_PRE_ROUTING: case NF_IP_PRE_ROUTING:
if (fwops->fw_acct_in) if (fwops->fw_acct_in)
fwops->fw_acct_in(fwops, PF_INET, fwops->fw_acct_in(fwops, PF_INET,
(struct net_device *)in, (struct net_device *)in,
(*pskb)->nh.raw, &redirpt, pskb); &redirpt, pskb);
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
*pskb = ip_ct_gather_frags(*pskb); *pskb = ip_ct_gather_frags(*pskb);
...@@ -85,7 +71,7 @@ fw_in(unsigned int hooknum, ...@@ -85,7 +71,7 @@ fw_in(unsigned int hooknum,
} }
ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in, ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
(*pskb)->nh.raw, &redirpt, pskb); &redirpt, pskb);
break; break;
case NF_IP_FORWARD: case NF_IP_FORWARD:
...@@ -95,18 +81,18 @@ fw_in(unsigned int hooknum, ...@@ -95,18 +81,18 @@ fw_in(unsigned int hooknum,
ret = FW_ACCEPT; ret = FW_ACCEPT;
else ret = fwops->fw_forward(fwops, PF_INET, else ret = fwops->fw_forward(fwops, PF_INET,
(struct net_device *)out, (struct net_device *)out,
(*pskb)->nh.raw, &redirpt, pskb); &redirpt, pskb);
break; break;
case NF_IP_POST_ROUTING: case NF_IP_POST_ROUTING:
ret = fwops->fw_output(fwops, PF_INET, ret = fwops->fw_output(fwops, PF_INET,
(struct net_device *)out, (struct net_device *)out,
(*pskb)->nh.raw, &redirpt, pskb); &redirpt, pskb);
if (ret == FW_ACCEPT || ret == FW_SKIP) { if (ret == FW_ACCEPT || ret == FW_SKIP) {
if (fwops->fw_acct_out) if (fwops->fw_acct_out)
fwops->fw_acct_out(fwops, PF_INET, fwops->fw_acct_out(fwops, PF_INET,
(struct net_device *)out, (struct net_device *)out,
(*pskb)->nh.raw, &redirpt, &redirpt,
pskb); pskb);
/* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */ /* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
...@@ -169,10 +155,6 @@ static unsigned int fw_confirm(unsigned int hooknum, ...@@ -169,10 +155,6 @@ static unsigned int fw_confirm(unsigned int hooknum,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) 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); 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