patch-2.3.99-pre2 linux/net/ipv4/netfilter/ip_fw_compat.c

Next file: linux/net/ipv4/netfilter/ip_fw_compat_masq.c
Previous file: linux/net/ipv4/netfilter/ip_conntrack_standalone.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre1/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c
@@ -0,0 +1,238 @@
+/* Compatibility framework for ipchains and ipfwadm support; designed
+   to look as much like the 2.2 infrastructure as possible. */
+struct notifier_block;
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <net/icmp.h>
+#include <linux/if.h>
+#include <linux/inetdevice.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <linux/netfilter_ipv4/compat_firewall.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+
+EXPORT_NO_SYMBOLS;
+
+static struct firewall_ops *fwops;
+
+/* From ip_fw_compat_redir.c */
+extern unsigned int
+do_redirect(struct sk_buff *skb,
+	    const struct net_device *dev,
+	    u_int16_t redirpt);
+
+extern void
+check_for_redirect(struct sk_buff *skb);
+
+extern void
+check_for_unredirect(struct sk_buff *skb);
+
+/* From ip_fw_compat_masq.c */
+extern unsigned int
+do_masquerade(struct sk_buff **pskb, const struct net_device *dev);
+
+extern unsigned int
+check_for_demasq(struct sk_buff **pskb);
+
+extern int __init masq_init(void);
+extern void masq_cleanup(void);
+
+/* They call these; we do what they want. */
+int register_firewall(int pf, struct firewall_ops *fw)
+{
+	if (pf != PF_INET) {
+		printk("Attempt to register non-IP firewall module.\n");
+		return -EINVAL;
+	}
+	if (fwops) {
+		printk("Attempt to register multiple firewall modules.\n");
+		return -EBUSY;
+	}
+
+	fwops = fw;
+	return 0;
+}
+
+int unregister_firewall(int pf, struct firewall_ops *fw)
+{
+	fwops = NULL;
+	return 0;
+}
+
+static unsigned int
+fw_in(unsigned int hooknum,
+      struct sk_buff **pskb,
+      const struct net_device *in,
+      const struct net_device *out,
+      int (*okfn)(struct sk_buff *))
+{
+	int ret = FW_BLOCK;
+	u_int16_t redirpt;
+
+	(*pskb)->nfcache |= NFC_UNKNOWN;
+	(*pskb)->ip_summed = CHECKSUM_NONE;
+
+	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);
+
+		if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+			*pskb = ip_ct_gather_frags(*pskb);
+
+			if (!*pskb)
+				return NF_STOLEN;
+		}
+
+		ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
+				      (*pskb)->nh.raw, &redirpt, pskb);
+		break;
+
+	case NF_IP_FORWARD:
+		/* Connection will only be set if it was
+                   demasqueraded: if so, skip forward chain. */
+		if ((*pskb)->nfct)
+			ret = FW_ACCEPT;
+		else ret = fwops->fw_forward(fwops, PF_INET,
+					     (struct net_device *)out,
+					     (*pskb)->nh.raw, &redirpt, pskb);
+		break;
+
+	case NF_IP_POST_ROUTING:
+		ret = fwops->fw_output(fwops, PF_INET,
+				       (struct net_device *)out,
+				       (*pskb)->nh.raw, &redirpt, pskb);
+		if (fwops->fw_acct_out && (ret == FW_ACCEPT || ret == FW_SKIP))
+			fwops->fw_acct_out(fwops, PF_INET,
+					   (struct net_device *)in,
+					   (*pskb)->nh.raw, &redirpt, pskb);
+		break;
+	}
+
+	switch (ret) {
+	case FW_REJECT: {
+		/* Alexey says:
+		 *
+		 * Generally, routing is THE FIRST thing to make, when
+		 * packet enters IP stack. Before packet is routed you
+		 * cannot call any service routines from IP stack.  */
+		struct iphdr *iph = (*pskb)->nh.iph;
+
+		if ((*pskb)->dst != NULL
+		    || ip_route_input(*pskb, iph->daddr, iph->saddr, iph->tos,
+				      (struct net_device *)in) == 0)
+			icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
+				  0);
+		return NF_DROP;
+	}
+
+	case FW_ACCEPT:
+	case FW_SKIP:
+		if (hooknum == NF_IP_PRE_ROUTING) {
+			check_for_demasq(pskb);
+			check_for_redirect(*pskb);
+		} else if (hooknum == NF_IP_POST_ROUTING)
+			check_for_unredirect(*pskb);
+
+		return NF_ACCEPT;
+
+	case FW_MASQUERADE:
+		if (hooknum == NF_IP_FORWARD)
+			return do_masquerade(pskb, out);
+		else return NF_ACCEPT;
+
+	case FW_REDIRECT:
+		if (hooknum == NF_IP_PRE_ROUTING)
+			return do_redirect(*pskb, in, redirpt);
+		else return NF_ACCEPT;
+
+	default:
+		/* FW_BLOCK */
+		return NF_DROP;
+	}
+}
+
+extern int ip_fw_ctl(int optval, void *user, unsigned int len);
+
+static int sock_fn(struct sock *sk, int optval, void *user, unsigned int len)
+{
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	return -ip_fw_ctl(optval, user, len);
+}
+
+static struct nf_hook_ops preroute_ops
+= { { NULL, NULL }, fw_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_FILTER };
+
+static struct nf_hook_ops postroute_ops
+= { { NULL, NULL }, fw_in, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_FILTER };
+
+static struct nf_hook_ops forward_ops
+= { { NULL, NULL }, fw_in, PF_INET, NF_IP_FORWARD, NF_IP_PRI_FILTER };
+
+static struct nf_sockopt_ops sock_ops
+= { { NULL, NULL }, PF_INET, 64, 64 + 1024 + 1, &sock_fn, 0, 0, NULL,
+    0, NULL };
+
+extern int ipfw_init_or_cleanup(int init);
+
+static int init_or_cleanup(int init)
+{
+	int ret = 0;
+
+	if (!init) goto cleanup;
+
+	ret = nf_register_sockopt(&sock_ops);
+
+	if (ret < 0)
+		goto cleanup_nothing;
+
+	ret = ipfw_init_or_cleanup(1);
+	if (ret < 0)
+		goto cleanup_sockopt;
+
+	ret = masq_init();
+	if (ret < 0)
+		goto cleanup_ipfw;
+
+	nf_register_hook(&preroute_ops);
+	nf_register_hook(&postroute_ops);
+	nf_register_hook(&forward_ops);
+
+	return ret;
+
+ cleanup:
+	nf_unregister_hook(&preroute_ops);
+	nf_unregister_hook(&postroute_ops);
+	nf_unregister_hook(&forward_ops);
+
+	masq_cleanup();
+
+ cleanup_ipfw:
+	ipfw_init_or_cleanup(0);
+
+ cleanup_sockopt:
+	nf_unregister_sockopt(&sock_ops);
+
+ cleanup_nothing:
+	return ret;
+}
+
+static int __init init(void)
+{
+	return init_or_cleanup(1);
+}
+
+static void __exit fini(void)
+{
+	init_or_cleanup(0);
+}
+
+module_init(init);
+module_exit(fini);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)