From: Rusty Russell We've been threatening to do this for ages: remove the backwards compatibility code. We can now combine ip_conntrack_core.c and ip_conntrack_standalone.c, likewise for the NAT code, but that will come later. Signed-off-by: Rusty Russell Signed-off-by: Andrew Morton --- /dev/null | 4799 ------------------------------------ 25-akpm/net/ipv4/netfilter/Kconfig | 27 25-akpm/net/ipv4/netfilter/Makefile | 18 3 files changed, 3 insertions(+), 4841 deletions(-) diff -L include/linux/netfilter_ipv4/compat_firewall.h -puN include/linux/netfilter_ipv4/compat_firewall.h~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/include/linux/netfilter_ipv4/compat_firewall.h +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,45 +0,0 @@ -/* Minor modifications to fit on compatibility framework: - Rusty.Russell@rustcorp.com.au -*/ - -#ifndef __LINUX_FIREWALL_H -#define __LINUX_FIREWALL_H - -/* - * Definitions for loadable firewall modules - */ - -#define FW_QUEUE 0 -#define FW_BLOCK 1 -#define FW_ACCEPT 2 -#define FW_REJECT (-1) -#define FW_REDIRECT 3 -#define FW_MASQUERADE 4 -#define FW_SKIP 5 - -struct firewall_ops -{ - struct firewall_ops *next; - int (*fw_forward)(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb); - int (*fw_input)(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb); - int (*fw_output)(struct firewall_ops *this, int pf, - 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 *arg, - struct sk_buff **pskb); - int (*fw_acct_out)(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb); -}; - -extern int register_firewall(int pf, struct firewall_ops *fw); -extern int unregister_firewall(int pf, struct firewall_ops *fw); - -extern int ip_fw_masq_timeouts(void *user, int len); -#endif /* __LINUX_FIREWALL_H */ diff -L include/linux/netfilter_ipv4/ipchains_core.h -puN include/linux/netfilter_ipv4/ipchains_core.h~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/include/linux/netfilter_ipv4/ipchains_core.h +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,189 +0,0 @@ -/* - * This code is heavily based on the code in ip_fw.h; see that file for - * copyrights and attributions. This code is basically GPL. - * - * 15-Feb-1997: Major changes to allow graphs for firewall rules. - * Paul Russell and - * Michael Neuling - * 2-Nov-1997: Changed types to __u16, etc. - * Removed IP_FW_F_TCPACK & IP_FW_F_BIDIR. - * Added inverse flags field. - * Removed multiple port specs. - */ - -/* - * Format of an IP firewall descriptor - * - * src, dst, src_mask, dst_mask are always stored in network byte order. - * flags are stored in host byte order (of course). - * Port numbers are stored in HOST byte order. - */ - -#ifndef _IP_FWCHAINS_H -#define _IP_FWCHAINS_H - -#ifdef __KERNEL__ -#include -#include -#include -#include -#include -#endif /* __KERNEL__ */ -#define IP_FW_MAX_LABEL_LENGTH 8 -typedef char ip_chainlabel[IP_FW_MAX_LABEL_LENGTH+1]; - -struct ip_fw -{ - struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ - struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ - __u32 fw_mark; /* ID to stamp on packet */ - __u16 fw_proto; /* Protocol, 0 = ANY */ - __u16 fw_flg; /* Flags word */ - __u16 fw_invflg; /* Inverse flags */ - __u16 fw_spts[2]; /* Source port range. */ - __u16 fw_dpts[2]; /* Destination port range. */ - __u16 fw_redirpt; /* Port to redirect to. */ - __u16 fw_outputsize; /* Max amount to output to - NETLINK */ - char fw_vianame[IFNAMSIZ]; /* name of interface "via" */ - __u8 fw_tosand, fw_tosxor; /* Revised packet priority */ -}; - -struct ip_fwuser -{ - struct ip_fw ipfw; - ip_chainlabel label; -}; - -/* Values for "fw_flg" field . */ -#define IP_FW_F_PRN 0x0001 /* Print packet if it matches */ -#define IP_FW_F_TCPSYN 0x0002 /* For tcp packets-check SYN only */ -#define IP_FW_F_FRAG 0x0004 /* Set if rule is a fragment rule */ -#define IP_FW_F_MARKABS 0x0008 /* Set the mark to fw_mark, not add. */ -#define IP_FW_F_WILDIF 0x0010 /* Need only match start of interface name. */ -#define IP_FW_F_NETLINK 0x0020 /* Redirect to netlink: 2.1.x only */ -#define IP_FW_F_MASK 0x003F /* All possible flag bits mask */ - -/* Values for "fw_invflg" field. */ -#define IP_FW_INV_SRCIP 0x0001 /* Invert the sense of fw_src. */ -#define IP_FW_INV_DSTIP 0x0002 /* Invert the sense of fw_dst. */ -#define IP_FW_INV_PROTO 0x0004 /* Invert the sense of fw_proto. */ -#define IP_FW_INV_SRCPT 0x0008 /* Invert the sense of source ports. */ -#define IP_FW_INV_DSTPT 0x0010 /* Invert the sense of destination ports. */ -#define IP_FW_INV_VIA 0x0020 /* Invert the sense of fw_vianame. */ -#define IP_FW_INV_SYN 0x0040 /* Invert the sense of IP_FW_F_TCPSYN. */ -#define IP_FW_INV_FRAG 0x0080 /* Invert the sense of IP_FW_F_FRAG. */ - -/* - * New IP firewall options for [gs]etsockopt at the RAW IP level. - * Unlike BSD Linux inherits IP options so you don't have to use - * a raw socket for this. Instead we check rights in the calls. */ - -#define IP_FW_BASE_CTL 64 /* base for firewall socket options */ - -#define IP_FW_APPEND (IP_FW_BASE_CTL) /* Takes ip_fwchange */ -#define IP_FW_REPLACE (IP_FW_BASE_CTL+1) /* Takes ip_fwnew */ -#define IP_FW_DELETE_NUM (IP_FW_BASE_CTL+2) /* Takes ip_fwdelnum */ -#define IP_FW_DELETE (IP_FW_BASE_CTL+3) /* Takes ip_fwchange */ -#define IP_FW_INSERT (IP_FW_BASE_CTL+4) /* Takes ip_fwnew */ -#define IP_FW_FLUSH (IP_FW_BASE_CTL+5) /* Takes ip_chainlabel */ -#define IP_FW_ZERO (IP_FW_BASE_CTL+6) /* Takes ip_chainlabel */ -#define IP_FW_CHECK (IP_FW_BASE_CTL+7) /* Takes ip_fwtest */ -#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+8) /* Takes 3 ints */ -#define IP_FW_CREATECHAIN (IP_FW_BASE_CTL+9) /* Takes ip_chainlabel */ -#define IP_FW_DELETECHAIN (IP_FW_BASE_CTL+10) /* Takes ip_chainlabel */ -#define IP_FW_POLICY (IP_FW_BASE_CTL+11) /* Takes ip_fwpolicy */ -/* Masquerade control, only 1 optname */ - -#define IP_FW_MASQ_CTL (IP_FW_BASE_CTL+12) /* General ip_masq ctl */ - -/* Builtin chain labels */ -#define IP_FW_LABEL_FORWARD "forward" -#define IP_FW_LABEL_INPUT "input" -#define IP_FW_LABEL_OUTPUT "output" - -/* Special targets */ -#define IP_FW_LABEL_MASQUERADE "MASQ" -#define IP_FW_LABEL_REDIRECT "REDIRECT" -#define IP_FW_LABEL_ACCEPT "ACCEPT" -#define IP_FW_LABEL_BLOCK "DENY" -#define IP_FW_LABEL_REJECT "REJECT" -#define IP_FW_LABEL_RETURN "RETURN" -#define IP_FW_LABEL_QUEUE "QUEUE" - -/* Files in /proc/net */ -#define IP_FW_PROC_CHAINS "ip_fwchains" -#define IP_FW_PROC_CHAIN_NAMES "ip_fwnames" - - -struct ip_fwpkt -{ - struct iphdr fwp_iph; /* IP header */ - union { - struct tcphdr fwp_tcph; /* TCP header or */ - struct udphdr fwp_udph; /* UDP header */ - struct icmphdr fwp_icmph; /* ICMP header */ - } fwp_protoh; - struct in_addr fwp_via; /* interface address */ - char fwp_vianame[IFNAMSIZ]; /* interface name */ -}; - -/* The argument to IP_FW_DELETE and IP_FW_APPEND */ -struct ip_fwchange -{ - struct ip_fwuser fwc_rule; - ip_chainlabel fwc_label; -}; - -/* The argument to IP_FW_CHECK. */ -struct ip_fwtest -{ - struct ip_fwpkt fwt_packet; /* Packet to be tested */ - ip_chainlabel fwt_label; /* Block to start test in */ -}; - -/* The argument to IP_FW_DELETE_NUM */ -struct ip_fwdelnum -{ - __u32 fwd_rulenum; - ip_chainlabel fwd_label; -}; - -/* The argument to IP_FW_REPLACE and IP_FW_INSERT */ -struct ip_fwnew -{ - __u32 fwn_rulenum; - struct ip_fwuser fwn_rule; - ip_chainlabel fwn_label; -}; - -/* The argument to IP_FW_POLICY */ -struct ip_fwpolicy -{ - ip_chainlabel fwp_policy; - ip_chainlabel fwp_label; -}; -/* - * timeouts for ip masquerading - */ - -extern int ip_fw_masq_timeouts(void *, int); - - -/* - * Main firewall chains definitions and global var's definitions. - */ - -#ifdef __KERNEL__ - -#include -#include -#include -extern void ip_fw_init(void) __init; -extern int ip_fw_ctl(int, void *, int); -#ifdef CONFIG_IP_MASQUERADE -extern int ip_masq_uctl(int, char *, int); -#endif -#endif /* KERNEL */ - -#endif /* _IP_FWCHAINS_H */ diff -L include/linux/netfilter_ipv4/ipfwadm_core.h -puN include/linux/netfilter_ipv4/ipfwadm_core.h~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/include/linux/netfilter_ipv4/ipfwadm_core.h +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,256 +0,0 @@ -#ifndef _IPFWADM_CORE_H -#define _IPFWADM_CORE_H -/* Minor modifications to fit on compatibility framework: - Rusty.Russell@rustcorp.com.au -*/ - -/* - * IP firewalling code. This is taken from 4.4BSD. Please note the - * copyright message below. As per the GPL it must be maintained - * and the licenses thus do not conflict. While this port is subject - * to the GPL I also place my modifications under the original - * license in recognition of the original copyright. - * - * Ported from BSD to Linux, - * Alan Cox 22/Nov/1994. - * Merged and included the FreeBSD-Current changes at Ugen's request - * (but hey it's a lot cleaner now). Ugen would prefer in some ways - * we waited for his final product but since Linux 1.2.0 is about to - * appear it's not practical - Read: It works, it's not clean but please - * don't consider it to be his standard of finished work. - * Alan. - * - * Fixes: - * Pauline Middelink : Added masquerading. - * Jos Vos : Separate input and output firewall - * chains, new "insert" and "append" - * commands to replace "add" commands, - * add ICMP header to struct ip_fwpkt. - * Jos Vos : Add support for matching device names. - * Willy Konynenberg : Add transparent proxying support. - * Jos Vos : Add options for input/output accounting. - * - * All the real work was done by ..... - */ - -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - */ - -/* - * Format of an IP firewall descriptor - * - * src, dst, src_mask, dst_mask are always stored in network byte order. - * flags and num_*_ports are stored in host byte order (of course). - * Port numbers are stored in HOST byte order. - */ - -#ifdef __KERNEL__ -#include -#include -#include -#include -#include -#endif - -struct ip_fw -{ - struct ip_fw *fw_next; /* Next firewall on chain */ - struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ - struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ - struct in_addr fw_via; /* IP address of interface "via" */ - struct net_device *fw_viadev; /* device of interface "via" */ - __u16 fw_flg; /* Flags word */ - __u16 fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */ - /* in ports array (dst ports follow */ - /* src ports; max of 10 ports in all; */ - /* count of 0 means match all ports) */ -#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */ - __u16 fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ - unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */ - __u8 fw_tosand, fw_tosxor; /* Revised packet priority */ - char fw_vianame[IFNAMSIZ]; /* name of interface "via" */ -}; - -/* - * Values for "flags" field . - */ - -#define IP_FW_F_ALL 0x0000 /* This is a universal packet firewall*/ -#define IP_FW_F_TCP 0x0001 /* This is a TCP packet firewall */ -#define IP_FW_F_UDP 0x0002 /* This is a UDP packet firewall */ -#define IP_FW_F_ICMP 0x0003 /* This is a ICMP packet firewall */ -#define IP_FW_F_KIND 0x0003 /* Mask to isolate firewall kind */ -#define IP_FW_F_ACCEPT 0x0004 /* This is an accept firewall (as * - * opposed to a deny firewall)* - * */ -#define IP_FW_F_SRNG 0x0008 /* The first two src ports are a min * - * and max range (stored in host byte * - * order). * - * */ -#define IP_FW_F_DRNG 0x0010 /* The first two dst ports are a min * - * and max range (stored in host byte * - * order). * - * (ports[0] <= port <= ports[1]) * - * */ -#define IP_FW_F_PRN 0x0020 /* In verbose mode print this firewall*/ -#define IP_FW_F_BIDIR 0x0040 /* For bidirectional firewalls */ -#define IP_FW_F_TCPSYN 0x0080 /* For tcp packets-check SYN only */ -#define IP_FW_F_ICMPRPL 0x0100 /* Send back icmp unreachable packet */ -#define IP_FW_F_MASQ 0x0200 /* Masquerading */ -#define IP_FW_F_TCPACK 0x0400 /* For tcp-packets match if ACK is set*/ -#define IP_FW_F_REDIR 0x0800 /* Redirect to local port fw_pts[n] */ -#define IP_FW_F_ACCTIN 0x1000 /* Account incoming packets only. */ -#define IP_FW_F_ACCTOUT 0x2000 /* Account outgoing packets only. */ - -#define IP_FW_F_MASK 0x3FFF /* All possible flag bits mask */ - -/* - * New IP firewall options for [gs]etsockopt at the RAW IP level. - * Unlike BSD Linux inherits IP options so you don't have to use - * a raw socket for this. Instead we check rights in the calls. - */ - -#define IP_FW_BASE_CTL 64 /* base for firewall socket options */ - -#define IP_FW_COMMAND 0x00FF /* mask for command without chain */ -#define IP_FW_TYPE 0x0300 /* mask for type (chain) */ -#define IP_FW_SHIFT 8 /* shift count for type (chain) */ - -#define IP_FW_FWD 0 -#define IP_FW_IN 1 -#define IP_FW_OUT 2 -#define IP_FW_ACCT 3 -#define IP_FW_CHAINS 4 /* total number of ip_fw chains */ -#define IP_FW_MASQ 5 - -#define IP_FW_INSERT (IP_FW_BASE_CTL) -#define IP_FW_APPEND (IP_FW_BASE_CTL+1) -#define IP_FW_DELETE (IP_FW_BASE_CTL+2) -#define IP_FW_FLUSH (IP_FW_BASE_CTL+3) -#define IP_FW_ZERO (IP_FW_BASE_CTL+4) -#define IP_FW_POLICY (IP_FW_BASE_CTL+5) -#define IP_FW_CHECK (IP_FW_BASE_CTL+6) -#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+7) - -#define IP_FW_INSERT_FWD (IP_FW_INSERT | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_APPEND_FWD (IP_FW_APPEND | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_DELETE_FWD (IP_FW_DELETE | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_FLUSH_FWD (IP_FW_FLUSH | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_ZERO_FWD (IP_FW_ZERO | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_POLICY_FWD (IP_FW_POLICY | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_CHECK_FWD (IP_FW_CHECK | (IP_FW_FWD << IP_FW_SHIFT)) - -#define IP_FW_INSERT_IN (IP_FW_INSERT | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_APPEND_IN (IP_FW_APPEND | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_DELETE_IN (IP_FW_DELETE | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_FLUSH_IN (IP_FW_FLUSH | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_ZERO_IN (IP_FW_ZERO | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_POLICY_IN (IP_FW_POLICY | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_CHECK_IN (IP_FW_CHECK | (IP_FW_IN << IP_FW_SHIFT)) - -#define IP_FW_INSERT_OUT (IP_FW_INSERT | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_APPEND_OUT (IP_FW_APPEND | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_DELETE_OUT (IP_FW_DELETE | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_FLUSH_OUT (IP_FW_FLUSH | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_ZERO_OUT (IP_FW_ZERO | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_POLICY_OUT (IP_FW_POLICY | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_CHECK_OUT (IP_FW_CHECK | (IP_FW_OUT << IP_FW_SHIFT)) - -#define IP_ACCT_INSERT (IP_FW_INSERT | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_APPEND (IP_FW_APPEND | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_DELETE (IP_FW_DELETE | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_FLUSH (IP_FW_FLUSH | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_ZERO (IP_FW_ZERO | (IP_FW_ACCT << IP_FW_SHIFT)) - -#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT)) - -#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT)) - -struct ip_fwpkt -{ - struct iphdr fwp_iph; /* IP header */ - union { - struct tcphdr fwp_tcph; /* TCP header or */ - struct udphdr fwp_udph; /* UDP header */ - struct icmphdr fwp_icmph; /* ICMP header */ - } fwp_protoh; - struct in_addr fwp_via; /* interface address */ - char fwp_vianame[IFNAMSIZ]; /* interface name */ -}; - -#define IP_FW_MASQCTL_MAX 256 -#define IP_MASQ_MOD_NMAX 32 - -struct ip_fw_masqctl -{ - int mctl_action; - union { - struct { - char name[IP_MASQ_MOD_NMAX]; - char data[1]; - } mod; - } u; -}; - -/* - * timeouts for ip masquerading - */ - -struct ip_fw_masq; - -/* - * Main firewall chains definitions and global var's definitions. - */ - -#ifdef __KERNEL__ - -/* Modes used in the ip_fw_chk() routine. */ -#define IP_FW_MODE_FW 0x00 /* kernel firewall check */ -#define IP_FW_MODE_ACCT_IN 0x01 /* accounting (incoming) */ -#define IP_FW_MODE_ACCT_OUT 0x02 /* accounting (outgoing) */ -#define IP_FW_MODE_CHK 0x04 /* check requested by user */ - -#include -#ifdef CONFIG_IP_FIREWALL -extern struct ip_fw *ip_fw_in_chain; -extern struct ip_fw *ip_fw_out_chain; -extern struct ip_fw *ip_fw_fwd_chain; -extern int ip_fw_in_policy; -extern int ip_fw_out_policy; -extern int ip_fw_fwd_policy; -extern int ip_fw_ctl(int, void *, int); -#endif -#ifdef CONFIG_IP_ACCT -extern struct ip_fw *ip_acct_chain; -extern int ip_acct_ctl(int, void *, int); -#endif -#ifdef CONFIG_IP_MASQUERADE -extern int ip_masq_ctl(int, void *, int); -#endif -#ifdef CONFIG_IP_MASQUERADE -extern int ip_masq_ctl(int, void *, int); -#endif - -extern int ip_fw_masq_timeouts(void *user, int len); - -extern int ip_fw_chk(struct sk_buff **, struct net_device *, __u16 *, - struct ip_fw *, int, int); -#endif /* KERNEL */ -#endif /* _IP_FW_H */ diff -L net/ipv4/netfilter/ipchains_core.c -puN net/ipv4/netfilter/ipchains_core.c~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/net/ipv4/netfilter/ipchains_core.c +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,1854 +0,0 @@ -#warning ipchains is obsolete, and will be removed soon. - -/* Minor modifications to fit on compatibility framework: - Rusty.Russell@rustcorp.com.au -*/ - -/* - * This code is heavily based on the code on the old ip_fw.c code; see below for - * copyrights and attributions of the old code. This code is basically GPL. - * - * 15-Aug-1997: Major changes to allow graphs for firewall rules. - * Paul Russell and - * Michael Neuling - * 24-Aug-1997: Generalised protocol handling (not just TCP/UDP/ICMP). - * Added explicit RETURN from chains. - * Removed TOS mangling (done in ipchains 1.0.1). - * Fixed read & reset bug by reworking proc handling. - * Paul Russell - * 28-Sep-1997: Added packet marking for net sched code. - * Removed fw_via comparisons: all done on device name now, - * similar to changes in ip_fw.c in DaveM's CVS970924 tree. - * Paul Russell - * 2-Nov-1997: Moved types across to __u16, etc. - * Added inverse flags. - * Fixed fragment bug (in args to port_match). - * Changed mark to only one flag (MARKABS). - * 21-Nov-1997: Added ability to test ICMP code. - * 19-Jan-1998: Added wildcard interfaces. - * 6-Feb-1998: Merged 2.0 and 2.1 versions. - * Initialised ip_masq for 2.0.x version. - * Added explicit NETLINK option for 2.1.x version. - * Added packet and byte counters for policy matches. - * 26-Feb-1998: Fixed race conditions, added SMP support. - * 18-Mar-1998: Fix SMP, fix race condition fix. - * 1-May-1998: Remove caching of device pointer. - * 12-May-1998: Allow tiny fragment case for TCP/UDP. - * 15-May-1998: Treat short packets as fragments, don't just block. - * 3-Jan-1999: Fixed serious procfs security hole -- users should never - * be allowed to view the chains! - * Marc Santoro - * 29-Jan-1999: Locally generated bogus IPs dealt with, rather than crash - * during dump_packet. --RR. - * 19-May-1999: Star Wars: The Phantom Menace opened. Rule num - * printed in log (modified from Michael Hasenstein's patch). - * Added SYN in log message. --RR - * 23-Jul-1999: Fixed small fragment security exposure opened on 15-May-1998. - * John McDonald - * Thomas Lopatic - */ - -/* - * - * The origina Linux port was done Alan Cox, with changes/fixes from - * Pauline Middlelink, Jos Vos, Thomas Quinot, Wouter Gadeyne, Juan - * Jose Ciarlante, Bernd Eckenfels, Keith Owens and others. - * - * Copyright from the original FreeBSD version follows: - * - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Rusty Russell "); -MODULE_DESCRIPTION("ipchains backwards compatibility layer"); - -/* Understanding locking in this code: (thanks to Alan Cox for using - * little words to explain this to me). -- PR - * - * In UP, there can be two packets traversing the chains: - * 1) A packet from the current userspace context - * 2) A packet off the bh handlers (timer or net). - * - * For SMP (kernel v2.1+), multiply this by # CPUs. - * - * [Note that this in not correct for 2.2 - because the socket code always - * uses lock_kernel() to serialize, and bottom halves (timers and net_bhs) - * only run on one CPU at a time. This will probably change for 2.3. - * It is still good to use spinlocks because that avoids the global cli() - * for updating the tables, which is rather costly in SMP kernels -AK] - * - * This means counters and backchains can get corrupted if no precautions - * are taken. - * - * To actually alter a chain on UP, we need only do a cli(), as this will - * stop a bh handler firing, as we are in the current userspace context - * (coming from a setsockopt()). - * - * On SMP, we need a write_lock_irqsave(), which is a simple cli() in - * UP. - * - * For backchains and counters, we use an array, indexed by - * [smp_processor_id()*2 + !in_interrupt()]; the array is of - * size [NR_CPUS*2]. For v2.0, NR_CPUS is effectively 1. So, - * confident of uniqueness, we modify counters even though we only - * have a read lock (to read the counters, you need a write lock, - * though). */ - -/* Why I didn't use straight locking... -- PR - * - * The backchains can be separated out of the ip_chains structure, and - * allocated as needed inside ip_fw_check(). - * - * The counters, however, can't. Trying to lock these means blocking - * interrupts every time we want to access them. This would suck HARD - * performance-wise. Not locking them leads to possible corruption, - * made worse on 32-bit machines (counters are 64-bit). */ - -/*#define DEBUG_IP_FIREWALL*/ -/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */ -/*#define DEBUG_IP_FIREWALL_USER*/ -/*#define DEBUG_IP_FIREWALL_LOCKING*/ - -#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) -static struct sock *ipfwsk; -#endif - -#ifdef CONFIG_SMP -#define SLOT_NUMBER() (smp_processor_id()*2 + !in_interrupt()) -#else /* !SMP */ -#define SLOT_NUMBER() (!in_interrupt()) -#endif /* CONFIG_SMP */ -#define NUM_SLOTS (NR_CPUS*2) - -#define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \ - + NUM_SLOTS*sizeof(struct ip_reent)) -#define SIZEOF_STRUCT_IP_FW_KERNEL (sizeof(struct ip_fwkernel) \ - + NUM_SLOTS*sizeof(struct ip_counters)) - -#ifdef DEBUG_IP_FIREWALL_LOCKING -static unsigned int fwc_rlocks, fwc_wlocks; -#define FWC_DEBUG_LOCK(d) \ -do { \ - FWC_DONT_HAVE_LOCK(d); \ - d |= (1 << SLOT_NUMBER()); \ -} while (0) - -#define FWC_DEBUG_UNLOCK(d) \ -do { \ - FWC_HAVE_LOCK(d); \ - d &= ~(1 << SLOT_NUMBER()); \ -} while (0) - -#define FWC_DONT_HAVE_LOCK(d) \ -do { \ - if ((d) & (1 << SLOT_NUMBER())) \ - printk("%s:%i: Got lock on %i already!\n", \ - __FILE__, __LINE__, SLOT_NUMBER()); \ -} while(0) - -#define FWC_HAVE_LOCK(d) \ -do { \ - if (!((d) & (1 << SLOT_NUMBER()))) \ - printk("%s:%i:No lock on %i!\n", \ - __FILE__, __LINE__, SLOT_NUMBER()); \ -} while (0) - -#else -#define FWC_DEBUG_LOCK(d) do { } while(0) -#define FWC_DEBUG_UNLOCK(d) do { } while(0) -#define FWC_DONT_HAVE_LOCK(d) do { } while(0) -#define FWC_HAVE_LOCK(d) do { } while(0) -#endif /*DEBUG_IP_FIRWALL_LOCKING*/ - -#define FWC_READ_LOCK(l) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock(l); } while (0) -#define FWC_WRITE_LOCK(l) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock(l); } while (0) -#define FWC_READ_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock_irqsave(l,f); } while (0) -#define FWC_WRITE_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock_irqsave(l,f); } while (0) -#define FWC_READ_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock(l); } while (0) -#define FWC_WRITE_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock(l); } while (0) -#define FWC_READ_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock_irqrestore(l,f); } while (0) -#define FWC_WRITE_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock_irqrestore(l,f); } while (0) - -struct ip_chain; - -struct ip_counters -{ - __u64 pcnt, bcnt; /* Packet and byte counters */ -}; - -struct ip_fwkernel -{ - struct ip_fw ipfw; - struct ip_fwkernel *next; /* where to go next if current - * rule doesn't match */ - struct ip_chain *branch; /* which branch to jump to if - * current rule matches */ - int simplebranch; /* Use this if branch == NULL */ - struct ip_counters counters[0]; /* Actually several of these */ -}; - -struct ip_reent -{ - struct ip_chain *prevchain; /* Pointer to referencing chain */ - struct ip_fwkernel *prevrule; /* Pointer to referencing rule */ - struct ip_counters counters; -}; - -struct ip_chain -{ - ip_chainlabel label; /* Defines the label for each block */ - struct ip_chain *next; /* Pointer to next block */ - struct ip_fwkernel *chain; /* Pointer to first rule in block */ - __u32 refcount; /* Number of refernces to block */ - int policy; /* Default rule for chain. Only * - * used in built in chains */ - struct ip_reent reent[0]; /* Actually several of these */ -}; - -/* - * Implement IP packet firewall - */ - -#ifdef DEBUG_IP_FIREWALL -#define dprintf(format, args...) printk(format , ## args) -#else -#define dprintf(format, args...) -#endif - -#ifdef DEBUG_IP_FIREWALL_USER -#define duprintf(format, args...) printk(format , ## args) -#else -#define duprintf(format, args...) -#endif - -/* Lock around ip_fw_chains linked list structure */ -rwlock_t ip_fw_lock = RW_LOCK_UNLOCKED; - -/* Head of linked list of fw rules */ -static struct ip_chain *ip_fw_chains; - -#define IP_FW_INPUT_CHAIN ip_fw_chains -#define IP_FW_FORWARD_CHAIN (ip_fw_chains->next) -#define IP_FW_OUTPUT_CHAIN (ip_fw_chains->next->next) - -/* Returns 1 if the port is matched by the range, 0 otherwise */ -extern inline int port_match(__u16 min, __u16 max, __u16 port, - int frag, int invert) -{ - if (frag) /* Fragments fail ANY port test. */ - return (min == 0 && max == 0xFFFF); - else return (port >= min && port <= max) ^ invert; -} - -/* Returns whether matches rule or not. */ -static int ip_rule_match(struct ip_fwkernel *f, - const char *ifname, - struct sk_buff **pskb, - char tcpsyn, - __u16 src_port, __u16 dst_port, - char isfrag) -{ - struct iphdr *ip = (*pskb)->nh.iph; - -#define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg)) - /* - * This is a bit simpler as we don't have to walk - * an interface chain as you do in BSD - same logic - * however. - */ - - if (FWINV((ip->saddr&f->ipfw.fw_smsk.s_addr) != f->ipfw.fw_src.s_addr, - IP_FW_INV_SRCIP) - || FWINV((ip->daddr&f->ipfw.fw_dmsk.s_addr)!=f->ipfw.fw_dst.s_addr, - IP_FW_INV_DSTIP)) { - dprintf("Source or dest mismatch.\n"); - - dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, - f->ipfw.fw_smsk.s_addr, f->ipfw.fw_src.s_addr, - f->ipfw.fw_invflg & IP_FW_INV_SRCIP ? " (INV)" : ""); - dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr, - f->ipfw.fw_dmsk.s_addr, f->ipfw.fw_dst.s_addr, - f->ipfw.fw_invflg & IP_FW_INV_DSTIP ? " (INV)" : ""); - return 0; - } - - /* - * Look for a VIA device match - */ - if (f->ipfw.fw_flg & IP_FW_F_WILDIF) { - if (FWINV(strncmp(ifname, f->ipfw.fw_vianame, - strlen(f->ipfw.fw_vianame)) != 0, - IP_FW_INV_VIA)) { - dprintf("Wildcard interface mismatch.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_VIA ? " (INV)" : ""); - return 0; /* Mismatch */ - } - } - else if (FWINV(strcmp(ifname, f->ipfw.fw_vianame) != 0, - IP_FW_INV_VIA)) { - dprintf("Interface name does not match.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_VIA - ? " (INV)" : ""); - return 0; /* Mismatch */ - } - - /* - * Ok the chain addresses match. - */ - - /* If we have a fragment rule but the packet is not a fragment - * the we return zero */ - if (FWINV((f->ipfw.fw_flg&IP_FW_F_FRAG) && !isfrag, IP_FW_INV_FRAG)) { - dprintf("Fragment rule but not fragment.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_FRAG ? " (INV)" : ""); - return 0; - } - - /* Fragment NEVER passes a SYN test, even an inverted one. */ - if (FWINV((f->ipfw.fw_flg&IP_FW_F_TCPSYN) && !tcpsyn, IP_FW_INV_SYN) - || (isfrag && (f->ipfw.fw_flg&IP_FW_F_TCPSYN))) { - dprintf("Rule requires SYN and packet has no SYN.%s\n", - f->ipfw.fw_invflg & IP_FW_INV_SYN ? " (INV)" : ""); - return 0; - } - - if (f->ipfw.fw_proto) { - /* - * Specific firewall - packet's protocol - * must match firewall's. - */ - - if (FWINV(ip->protocol!=f->ipfw.fw_proto, IP_FW_INV_PROTO)) { - dprintf("Packet protocol %hi does not match %hi.%s\n", - ip->protocol, f->ipfw.fw_proto, - f->ipfw.fw_invflg&IP_FW_INV_PROTO ? " (INV)":""); - return 0; - } - - /* For non TCP/UDP/ICMP, port range is max anyway. */ - if (!port_match(f->ipfw.fw_spts[0], - f->ipfw.fw_spts[1], - src_port, isfrag, - !!(f->ipfw.fw_invflg&IP_FW_INV_SRCPT)) - || !port_match(f->ipfw.fw_dpts[0], - f->ipfw.fw_dpts[1], - dst_port, isfrag, - !!(f->ipfw.fw_invflg - &IP_FW_INV_DSTPT))) { - dprintf("Port match failed.\n"); - return 0; - } - } - - dprintf("Match succeeded.\n"); - return 1; -} - -static const char *branchname(struct ip_chain *branch,int simplebranch) -{ - if (branch) - return branch->label; - switch (simplebranch) - { - case FW_BLOCK: return IP_FW_LABEL_BLOCK; - case FW_ACCEPT: return IP_FW_LABEL_ACCEPT; - case FW_REJECT: return IP_FW_LABEL_REJECT; - case FW_REDIRECT: return IP_FW_LABEL_REDIRECT; - case FW_MASQUERADE: return IP_FW_LABEL_MASQUERADE; - case FW_SKIP: return "-"; - case FW_SKIP+1: return IP_FW_LABEL_RETURN; - default: - return "UNKNOWN"; - } -} - -/* - * VERY ugly piece of code which actually - * makes kernel printf for matching packets... - */ -static void dump_packet(struct sk_buff **pskb, - const char *ifname, - struct ip_fwkernel *f, - const ip_chainlabel chainlabel, - __u16 src_port, - __u16 dst_port, - unsigned int count, - int syn) -{ - __u32 *opt = (__u32 *) ((*pskb)->nh.iph + 1); - int opti; - - if (f) { - printk(KERN_INFO "Packet log: %s ",chainlabel); - printk("%s ",branchname(f->branch,f->simplebranch)); - if (f->simplebranch==FW_REDIRECT) - printk("%d ",f->ipfw.fw_redirpt); - } - - printk("%s PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu" - " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", - ifname, (*pskb)->nh.iph->protocol, - NIPQUAD((*pskb)->nh.iph->saddr), - src_port, - NIPQUAD((*pskb)->nh.iph->daddr), - dst_port, - ntohs((*pskb)->nh.iph->tot_len), - (*pskb)->nh.iph->tos, - ntohs((*pskb)->nh.iph->id), - ntohs((*pskb)->nh.iph->frag_off), - (*pskb)->nh.iph->ttl); - - for (opti = 0; opti < ((*pskb)->nh.iph->ihl - sizeof(struct iphdr) / 4); opti++) - printk(" O=0x%8.8X", *opt++); - printk(" %s(#%d)\n", syn ? "SYN " : /* "PENANCE" */ "", count); -} - -/* function for checking chain labels for user space. */ -static int check_label(ip_chainlabel label) -{ - unsigned int i; - /* strlen must be < IP_FW_MAX_LABEL_LENGTH. */ - for (i = 0; i < IP_FW_MAX_LABEL_LENGTH + 1; i++) - if (label[i] == '\0') return 1; - - return 0; -} - -/* This function returns a pointer to the first chain with a label - * that matches the one given. */ -static struct ip_chain *find_label(ip_chainlabel label) -{ - struct ip_chain *tmp; - FWC_HAVE_LOCK(fwc_rlocks | fwc_wlocks); - for (tmp = ip_fw_chains; tmp; tmp = tmp->next) - if (strcmp(tmp->label,label) == 0) - break; - return tmp; -} - -/* This function returns a boolean which when true sets answer to one - of the FW_*. */ -static int find_special(ip_chainlabel label, int *answer) -{ - if (label[0] == '\0') { - *answer = FW_SKIP; /* => pass-through rule */ - return 1; - } else if (strcmp(label,IP_FW_LABEL_ACCEPT) == 0) { - *answer = FW_ACCEPT; - return 1; - } else if (strcmp(label,IP_FW_LABEL_BLOCK) == 0) { - *answer = FW_BLOCK; - return 1; - } else if (strcmp(label,IP_FW_LABEL_REJECT) == 0) { - *answer = FW_REJECT; - return 1; - } else if (strcmp(label,IP_FW_LABEL_REDIRECT) == 0) { - *answer = FW_REDIRECT; - return 1; - } else if (strcmp(label,IP_FW_LABEL_MASQUERADE) == 0) { - *answer = FW_MASQUERADE; - return 1; - } else if (strcmp(label, IP_FW_LABEL_RETURN) == 0) { - *answer = FW_SKIP+1; - return 1; - } else { - return 0; - } -} - -/* This function cleans up the prevchain and prevrule. If the verbose - * flag is set then he names of the chains will be printed as it - * cleans up. */ -static void cleanup(struct ip_chain *chain, - const int verbose, - unsigned int slot) -{ - struct ip_chain *tmpchain = chain->reent[slot].prevchain; - if (verbose) - printk(KERN_ERR "Chain backtrace: "); - while (tmpchain) { - if (verbose) - printk("%s<-",chain->label); - chain->reent[slot].prevchain = NULL; - chain = tmpchain; - tmpchain = chain->reent[slot].prevchain; - } - if (verbose) - printk("%s\n",chain->label); -} - -static inline int -ip_fw_domatch(struct ip_fwkernel *f, - const char *rif, - const ip_chainlabel label, - struct sk_buff **pskb, - unsigned int slot, - __u16 src_port, __u16 dst_port, - unsigned int count, - int tcpsyn, - unsigned char *tos) -{ - f->counters[slot].bcnt+=ntohs((*pskb)->nh.iph->tot_len); - f->counters[slot].pcnt++; - if (f->ipfw.fw_flg & IP_FW_F_PRN) { - dump_packet(pskb,rif,f,label,src_port,dst_port,count,tcpsyn); - } - - *tos = (*tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor; - -/* This functionality is useless in stock 2.0.x series, but we don't - * discard the mark thing altogether, to avoid breaking ipchains (and, - * more importantly, the ipfwadm wrapper) --PR */ - if (f->ipfw.fw_flg & IP_FW_F_MARKABS) { - (*pskb)->nfmark = f->ipfw.fw_mark; - } else { - (*pskb)->nfmark += f->ipfw.fw_mark; - } - if (f->ipfw.fw_flg & IP_FW_F_NETLINK) { -#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) - size_t len = min_t(unsigned int, f->ipfw.fw_outputsize, ntohs((*pskb)->nh.iph->tot_len)) - + sizeof(__u32) + sizeof((*pskb)->nfmark) + IFNAMSIZ; - struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC); - - duprintf("Sending packet out NETLINK (length = %u).\n", - (unsigned int)len); - if (outskb) { - /* Prepend length, mark & interface */ - skb_put(outskb, len); - *((__u32 *)outskb->data) = (__u32)len; - *((__u32 *)(outskb->data+sizeof(__u32))) = - (*pskb)->nfmark; - strcpy(outskb->data+sizeof(__u32)*2, rif); - skb_copy_bits(*pskb, - ((char *)(*pskb)->nh.iph - (char *)(*pskb)->data), - outskb->data+sizeof(__u32)*2+IFNAMSIZ, - len-(sizeof(__u32)*2+IFNAMSIZ)); - netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_ATOMIC); - } - else { -#endif - if (net_ratelimit()) - printk(KERN_WARNING "ip_fw: packet drop due to " - "netlink failure\n"); - return 0; -#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) - } -#endif - } - return 1; -} - -/* - * Returns one of the generic firewall policies, like FW_ACCEPT. - * - * The testing is either false for normal firewall mode or true for - * user checking mode (counters are not updated, TOS & mark not done). - */ -static int -ip_fw_check(const char *rif, - __u16 *redirport, - struct ip_chain *chain, - struct sk_buff **pskb, - unsigned int slot, - int testing) -{ - __u32 src, dst; - __u16 src_port = 0xFFFF, dst_port = 0xFFFF; - char tcpsyn=0; - __u16 offset; - unsigned char tos; - struct ip_fwkernel *f; - int ret = FW_SKIP+2; - unsigned int count; - - /* We handle fragments by dealing with the first fragment as - * if it was a normal packet. All other fragments are treated - * normally, except that they will NEVER match rules that ask - * things we don't know, ie. tcp syn flag or ports). If the - * rule is also a fragment-specific rule, non-fragments won't - * match it. */ - - offset = ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET; - - /* - * Don't allow a fragment of TCP 8 bytes in. Nobody - * normal causes this. Its a cracker trying to break - * in by doing a flag overwrite to pass the direction - * checks. - */ - if (offset == 1 && (*pskb)->nh.iph->protocol == IPPROTO_TCP) { - if (!testing && net_ratelimit()) { - printk("Suspect TCP fragment.\n"); - dump_packet(pskb,rif,NULL,NULL,0,0,0,0); - } - return FW_BLOCK; - } - - /* If we can't investigate ports, treat as fragment. It's - * either a trucated whole packet, or a truncated first - * fragment, or a TCP first fragment of length 8-15, in which - * case the above rule stops reassembly. - */ - if (offset == 0) { - unsigned int size_req; - switch ((*pskb)->nh.iph->protocol) { - case IPPROTO_TCP: - /* Don't care about things past flags word */ - size_req = 16; - break; - - case IPPROTO_UDP: - case IPPROTO_ICMP: - size_req = 8; - break; - - default: - size_req = 0; - } - - /* If it is a truncated first fragment then it can be - * used to rewrite port information, and thus should - * be blocked. - */ - if (ntohs((*pskb)->nh.iph->tot_len) < - ((*pskb)->nh.iph->ihl<<2)+size_req) { - if (!testing && net_ratelimit()) { - printk("Suspect short first fragment.\n"); - dump_packet(pskb,rif,NULL,NULL,0,0,0,0); - } - return FW_BLOCK; - } - } - - src = (*pskb)->nh.iph->saddr; - dst = (*pskb)->nh.iph->daddr; - tos = (*pskb)->nh.iph->tos; - - /* - * If we got interface from which packet came - * we can use the address directly. Linux 2.1 now uses address - * chains per device too, but unlike BSD we first check if the - * incoming packet matches a device address and the routing - * table before calling the firewall. - */ - - dprintf("Packet "); - switch ((*pskb)->nh.iph->protocol) { - case IPPROTO_TCP: - dprintf("TCP "); - if (!offset) { - struct tcphdr _tcph, *th; - - th = skb_header_pointer(*pskb, - (*pskb)->nh.iph->ihl*4, - sizeof(_tcph), &_tcph); - if (th == NULL) - return FW_BLOCK; - - src_port = ntohs(th->source); - dst_port = ntohs(th->dest); - - /* Connection initilisation can only - * be made when the syn bit is set and - * neither of the ack or reset is - * set. */ - if (th->syn && !(th->ack || th->rst)) - tcpsyn = 1; - } - break; - case IPPROTO_UDP: - dprintf("UDP "); - if (!offset) { - struct udphdr _udph, *uh; - - uh = skb_header_pointer(*pskb, - (*pskb)->nh.iph->ihl*4, - sizeof(_udph), &_udph); - if (uh == NULL) - return FW_BLOCK; - - src_port = ntohs(uh->source); - dst_port = ntohs(uh->dest); - } - break; - case IPPROTO_ICMP: - if (!offset) { - struct icmphdr _icmph, *ic; - - ic = skb_header_pointer(*pskb, - (*pskb)->nh.iph->ihl*4, - sizeof(_icmph), - &_icmph); - if (ic == NULL) - return FW_BLOCK; - - src_port = (__u16) ic->type; - dst_port = (__u16) ic->code; - } - dprintf("ICMP "); - break; - default: - dprintf("p=%d ", (*pskb)->nh.iph->protocol); - break; - } -#ifdef DEBUG_IP_FIREWALL - print_ip((*pskb)->nh.iph->saddr); - - if (offset) - dprintf(":fragment (%i) ", ((int)offset)<<2); - else if ((*pskb)->nh.iph->protocol == IPPROTO_TCP || - (*pskb)->nh.iph->protocol == IPPROTO_UDP || - (*pskb)->nh.iph->protocol == IPPROTO_ICMP) - dprintf(":%hu:%hu", src_port, dst_port); - dprintf("\n"); -#endif - - if (!testing) FWC_READ_LOCK(&ip_fw_lock); - else FWC_HAVE_LOCK(fwc_rlocks); - - f = chain->chain; - do { - count = 0; - for (; f; f = f->next) { - count++; - if (ip_rule_match(f, rif, pskb, - tcpsyn, src_port, dst_port, - offset)) { - if (!testing - && !ip_fw_domatch(f, rif, chain->label, - pskb, slot, - src_port, dst_port, - count, tcpsyn, &tos)) { - ret = FW_BLOCK; - cleanup(chain, 0, slot); - goto out; - } - break; - } - } - if (f) { - if (f->branch) { - /* Do sanity check to see if we have - * already set prevchain and if so we - * must be in a loop */ - if (f->branch->reent[slot].prevchain) { - if (!testing) { - printk(KERN_ERR - "IP firewall: " - "Loop detected " - "at `%s'.\n", - f->branch->label); - cleanup(chain, 1, slot); - ret = FW_BLOCK; - } else { - cleanup(chain, 0, slot); - ret = FW_SKIP+1; - } - } - else { - f->branch->reent[slot].prevchain - = chain; - f->branch->reent[slot].prevrule - = f->next; - chain = f->branch; - f = chain->chain; - } - } - else if (f->simplebranch == FW_SKIP) - f = f->next; - else if (f->simplebranch == FW_SKIP+1) { - /* Just like falling off the chain */ - goto fall_off_chain; - } else { - cleanup(chain, 0, slot); - ret = f->simplebranch; - } - } /* f == NULL */ - else { - fall_off_chain: - if (chain->reent[slot].prevchain) { - struct ip_chain *tmp = chain; - f = chain->reent[slot].prevrule; - chain = chain->reent[slot].prevchain; - tmp->reent[slot].prevchain = NULL; - } - else { - ret = chain->policy; - if (!testing) { - chain->reent[slot].counters.pcnt++; - chain->reent[slot].counters.bcnt - += ntohs((*pskb)->nh.iph->tot_len); - } - } - } - } while (ret == FW_SKIP+2); - - out: - if (!testing) FWC_READ_UNLOCK(&ip_fw_lock); - - /* Recalculate checksum if not going to reject, and TOS changed. */ - if ((*pskb)->nh.iph->tos != tos - && ret != FW_REJECT && ret != FW_BLOCK - && !testing) { - if (!skb_ip_make_writable(pskb, offsetof(struct iphdr, tos)+1)) - ret = FW_BLOCK; - else { - (*pskb)->nh.iph->tos = tos; - ip_send_check((*pskb)->nh.iph); - } - } - - if (ret == FW_REDIRECT && redirport) { - if ((*redirport = htons(f->ipfw.fw_redirpt)) == 0) { - /* Wildcard redirection. - * Note that redirport will become - * 0xFFFF for non-TCP/UDP packets. - */ - *redirport = htons(dst_port); - } - } - -#ifdef DEBUG_ALLOW_ALL - return (testing ? ret : FW_ACCEPT); -#else - return ret; -#endif -} - -/* Must have write lock & interrupts off for any of these */ - -/* This function sets all the byte counters in a chain to zero. The - * input is a pointer to the chain required for zeroing */ -static int zero_fw_chain(struct ip_chain *chainptr) -{ - struct ip_fwkernel *i; - - FWC_HAVE_LOCK(fwc_wlocks); - for (i = chainptr->chain; i; i = i->next) - memset(i->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS); - return 0; -} - -static int clear_fw_chain(struct ip_chain *chainptr) -{ - struct ip_fwkernel *i= chainptr->chain; - - FWC_HAVE_LOCK(fwc_wlocks); - chainptr->chain=NULL; - - while (i) { - struct ip_fwkernel *tmp = i->next; - if (i->branch) - i->branch->refcount--; - kfree(i); - i = tmp; - /* We will block in cleanup's unregister sockopt if unloaded, - so this is safe. */ - module_put(THIS_MODULE); - } - return 0; -} - -static int replace_in_chain(struct ip_chain *chainptr, - struct ip_fwkernel *frwl, - __u32 position) -{ - struct ip_fwkernel *f = chainptr->chain; - - FWC_HAVE_LOCK(fwc_wlocks); - - while (--position && f != NULL) f = f->next; - if (f == NULL) - return EINVAL; - - if (f->branch) f->branch->refcount--; - if (frwl->branch) frwl->branch->refcount++; - - frwl->next = f->next; - memcpy(f,frwl,sizeof(struct ip_fwkernel)); - kfree(frwl); - return 0; -} - -static int append_to_chain(struct ip_chain *chainptr, struct ip_fwkernel *rule) -{ - struct ip_fwkernel *i; - - FWC_HAVE_LOCK(fwc_wlocks); - - /* Are we unloading now? We will block on nf_unregister_sockopt */ - if (!try_module_get(THIS_MODULE)) - return ENOPROTOOPT; - - /* Special case if no rules already present */ - if (chainptr->chain == NULL) { - - /* If pointer writes are atomic then turning off - * interrupts is not necessary. */ - chainptr->chain = rule; - if (rule->branch) rule->branch->refcount++; - goto append_successful; - } - - /* Find the rule before the end of the chain */ - for (i = chainptr->chain; i->next; i = i->next); - i->next = rule; - if (rule->branch) rule->branch->refcount++; - -append_successful: - return 0; -} - -/* This function inserts a rule at the position of position in the - * chain refenced by chainptr. If position is 1 then this rule will - * become the new rule one. */ -static int insert_in_chain(struct ip_chain *chainptr, - struct ip_fwkernel *frwl, - __u32 position) -{ - struct ip_fwkernel *f = chainptr->chain; - - FWC_HAVE_LOCK(fwc_wlocks); - - /* Are we unloading now? We will block on nf_unregister_sockopt */ - if (!try_module_get(THIS_MODULE)) - return ENOPROTOOPT; - - /* special case if the position is number 1 */ - if (position == 1) { - frwl->next = chainptr->chain; - if (frwl->branch) frwl->branch->refcount++; - chainptr->chain = frwl; - goto insert_successful; - } - position--; - while (--position && f != NULL) f = f->next; - if (f == NULL) - return EINVAL; - if (frwl->branch) frwl->branch->refcount++; - frwl->next = f->next; - - f->next = frwl; - -insert_successful: - return 0; -} - -/* This function deletes the a rule from a given rulenum and chain. - * With rulenum = 1 is the first rule is deleted. */ - -static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum) -{ - struct ip_fwkernel *i=chainptr->chain,*tmp; - - FWC_HAVE_LOCK(fwc_wlocks); - - if (!chainptr->chain) - return ENOENT; - - /* Need a special case for the first rule */ - if (rulenum == 1) { - /* store temp to allow for freeing up of memory */ - tmp = chainptr->chain; - if (chainptr->chain->branch) chainptr->chain->branch->refcount--; - chainptr->chain = chainptr->chain->next; - kfree(tmp); /* free memory that is now unused */ - } else { - rulenum--; - while (--rulenum && i->next ) i = i->next; - if (!i->next) - return ENOENT; - tmp = i->next; - if (i->next->branch) - i->next->branch->refcount--; - i->next = i->next->next; - kfree(tmp); - } - - /* We will block in cleanup's unregister sockopt if unloaded, - so this is safe. */ - module_put(THIS_MODULE); - return 0; -} - - -/* This function deletes the a rule from a given rule and chain. - * The rule that is deleted is the first occursance of that rule. */ -static int del_rule_from_chain(struct ip_chain *chainptr, - struct ip_fwkernel *frwl) -{ - struct ip_fwkernel *ltmp,*ftmp = chainptr->chain ; - int was_found; - - FWC_HAVE_LOCK(fwc_wlocks); - - /* Sure, we should compare marks, but since the `ipfwadm' - * script uses it for an unholy hack... well, life is easier - * this way. We also mask it out of the flags word. --PR */ - for (ltmp=NULL, was_found=0; - !was_found && ftmp != NULL; - ltmp = ftmp,ftmp = ftmp->next) { - if (ftmp->ipfw.fw_src.s_addr!=frwl->ipfw.fw_src.s_addr - || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr - || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr - || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr -#if 0 - || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg -#else - || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS) - != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS)) -#endif - || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg - || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto -#if 0 - || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark -#endif - || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt - || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0] - || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1] - || ftmp->ipfw.fw_dpts[0]!=frwl->ipfw.fw_dpts[0] - || ftmp->ipfw.fw_dpts[1]!=frwl->ipfw.fw_dpts[1] - || ftmp->ipfw.fw_outputsize!=frwl->ipfw.fw_outputsize) { - duprintf("del_rule_from_chain: mismatch:" - "src:%u/%u dst:%u/%u smsk:%u/%u dmsk:%u/%u " - "flg:%hX/%hX invflg:%hX/%hX proto:%u/%u " - "mark:%u/%u " - "ports:%hu-%hu/%hu-%hu %hu-%hu/%hu-%hu " - "outputsize:%hu-%hu\n", - ftmp->ipfw.fw_src.s_addr, - frwl->ipfw.fw_src.s_addr, - ftmp->ipfw.fw_dst.s_addr, - frwl->ipfw.fw_dst.s_addr, - ftmp->ipfw.fw_smsk.s_addr, - frwl->ipfw.fw_smsk.s_addr, - ftmp->ipfw.fw_dmsk.s_addr, - frwl->ipfw.fw_dmsk.s_addr, - ftmp->ipfw.fw_flg, - frwl->ipfw.fw_flg, - ftmp->ipfw.fw_invflg, - frwl->ipfw.fw_invflg, - ftmp->ipfw.fw_proto, - frwl->ipfw.fw_proto, - ftmp->ipfw.fw_mark, - frwl->ipfw.fw_mark, - ftmp->ipfw.fw_spts[0], - frwl->ipfw.fw_spts[0], - ftmp->ipfw.fw_spts[1], - frwl->ipfw.fw_spts[1], - ftmp->ipfw.fw_dpts[0], - frwl->ipfw.fw_dpts[0], - ftmp->ipfw.fw_dpts[1], - frwl->ipfw.fw_dpts[1], - ftmp->ipfw.fw_outputsize, - frwl->ipfw.fw_outputsize); - continue; - } - - if (strncmp(ftmp->ipfw.fw_vianame, - frwl->ipfw.fw_vianame, - IFNAMSIZ)) { - duprintf("del_rule_from_chain: if mismatch: %s/%s\n", - ftmp->ipfw.fw_vianame, - frwl->ipfw.fw_vianame); - continue; - } - if (ftmp->branch != frwl->branch) { - duprintf("del_rule_from_chain: branch mismatch: " - "%s/%s\n", - ftmp->branch?ftmp->branch->label:"(null)", - frwl->branch?frwl->branch->label:"(null)"); - continue; - } - if (ftmp->branch == NULL - && ftmp->simplebranch != frwl->simplebranch) { - duprintf("del_rule_from_chain: simplebranch mismatch: " - "%i/%i\n", - ftmp->simplebranch, frwl->simplebranch); - continue; - } - was_found = 1; - if (ftmp->branch) - ftmp->branch->refcount--; - if (ltmp) - ltmp->next = ftmp->next; - else - chainptr->chain = ftmp->next; - kfree(ftmp); - /* We will block in cleanup's unregister sockopt if unloaded, - so this is safe. */ - module_put(THIS_MODULE); - break; - } - - if (was_found) - return 0; - else { - duprintf("del_rule_from_chain: no matching rule found\n"); - return EINVAL; - } -} - -/* This function takes the label of a chain and deletes the first - * chain with that name. No special cases required for the built in - * chains as they have their refcount initilised to 1 so that they are - * never deleted. */ -static int del_chain(ip_chainlabel label) -{ - struct ip_chain *tmp,*tmp2; - - FWC_HAVE_LOCK(fwc_wlocks); - /* Corner case: return EBUSY not ENOENT for first elem ("input") */ - if (strcmp(label, ip_fw_chains->label) == 0) - return EBUSY; - - for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) - if(strcmp(tmp->next->label,label) == 0) - break; - - tmp2 = tmp->next; - if (!tmp2) - return ENOENT; - - if (tmp2->refcount) - return EBUSY; - - if (tmp2->chain) - return ENOTEMPTY; - - tmp->next = tmp2->next; - kfree(tmp2); - - /* We will block in cleanup's unregister sockopt if unloaded, - so this is safe. */ - module_put(THIS_MODULE); - return 0; -} - -/* This is a function to initilise a chain. Built in rules start with - * refcount = 1 so that they cannot be deleted. User defined rules - * start with refcount = 0 so they can be deleted. */ -static struct ip_chain *ip_init_chain(ip_chainlabel name, - __u32 ref, - int policy) -{ - unsigned int i; - struct ip_chain *label - = kmalloc(SIZEOF_STRUCT_IP_CHAIN, GFP_KERNEL); - if (label == NULL) - panic("Can't kmalloc for firewall chains.\n"); - strcpy(label->label,name); - label->next = NULL; - label->chain = NULL; - label->refcount = ref; - label->policy = policy; - for (i = 0; i < NUM_SLOTS; i++) { - label->reent[i].counters.pcnt = label->reent[i].counters.bcnt - = 0; - label->reent[i].prevchain = NULL; - label->reent[i].prevrule = NULL; - } - - return label; -} - -/* This is a function for reating a new chain. The chains is not - * created if a chain of the same name already exists */ -static int create_chain(ip_chainlabel label) -{ - struct ip_chain *tmp; - - if (!check_label(label)) - return EINVAL; - - FWC_HAVE_LOCK(fwc_wlocks); - for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) - if (strcmp(tmp->label,label) == 0) - return EEXIST; - - if (strcmp(tmp->label,label) == 0) - return EEXIST; - - /* Are we unloading now? We will block on nf_unregister_sockopt */ - if (!try_module_get(THIS_MODULE)) - return ENOPROTOOPT; - - tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is - * zero since this is a - * user defined chain * - * and therefore can be - * deleted */ - return 0; -} - -/* This function simply changes the policy on one of the built in - * chains. checking must be done before this is call to ensure that - * chainptr is pointing to one of the three possible chains */ -static int change_policy(struct ip_chain *chainptr, int policy) -{ - FWC_HAVE_LOCK(fwc_wlocks); - chainptr->policy = policy; - return 0; -} - -/* This function takes an ip_fwuser and converts it to a ip_fwkernel. It also - * performs some checks in the structure. */ -static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno) -{ - struct ip_fwkernel *fwkern; - - if ( (fwuser->ipfw.fw_flg & ~IP_FW_F_MASK) != 0 ) { - duprintf("convert_ipfw: undefined flag bits set (flags=%x)\n", - fwuser->ipfw.fw_flg); - *errno = EINVAL; - return NULL; - } - -#ifdef DEBUG_IP_FIREWALL_USER - /* These are sanity checks that don't really matter. - * We can get rid of these once testing is complete. - */ - if ((fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) - && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) - || fwuser->ipfw.fw_proto != IPPROTO_TCP)) { - duprintf("convert_ipfw: TCP SYN flag set but proto != TCP!\n"); - *errno = EINVAL; - return NULL; - } - - if (strcmp(fwuser->label, IP_FW_LABEL_REDIRECT) != 0 - && fwuser->ipfw.fw_redirpt != 0) { - duprintf("convert_ipfw: Target not REDIR but redirpt != 0!\n"); - *errno = EINVAL; - return NULL; - } - - if ((!(fwuser->ipfw.fw_flg & IP_FW_F_FRAG) - && (fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG)) - || (!(fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) - && (fwuser->ipfw.fw_invflg & IP_FW_INV_SYN))) { - duprintf("convert_ipfw: Can't have INV flag if flag unset!\n"); - *errno = EINVAL; - return NULL; - } - - if (((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCPT) - && fwuser->ipfw.fw_spts[0] == 0 - && fwuser->ipfw.fw_spts[1] == 0xFFFF) - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTPT) - && fwuser->ipfw.fw_dpts[0] == 0 - && fwuser->ipfw.fw_dpts[1] == 0xFFFF) - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_VIA) - && (fwuser->ipfw.fw_vianame)[0] == '\0') - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCIP) - && fwuser->ipfw.fw_smsk.s_addr == 0) - || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTIP) - && fwuser->ipfw.fw_dmsk.s_addr == 0)) { - duprintf("convert_ipfw: INV flag makes rule unmatchable!\n"); - *errno = EINVAL; - return NULL; - } - - if ((fwuser->ipfw.fw_flg & IP_FW_F_FRAG) - && !(fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG) - && (fwuser->ipfw.fw_spts[0] != 0 - || fwuser->ipfw.fw_spts[1] != 0xFFFF - || fwuser->ipfw.fw_dpts[0] != 0 - || fwuser->ipfw.fw_dpts[1] != 0xFFFF - || (fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN))) { - duprintf("convert_ipfw: Can't test ports or SYN with frag!\n"); - *errno = EINVAL; - return NULL; - } -#endif - - if ((fwuser->ipfw.fw_spts[0] != 0 - || fwuser->ipfw.fw_spts[1] != 0xFFFF - || fwuser->ipfw.fw_dpts[0] != 0 - || fwuser->ipfw.fw_dpts[1] != 0xFFFF) - && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) - || (fwuser->ipfw.fw_proto != IPPROTO_TCP - && fwuser->ipfw.fw_proto != IPPROTO_UDP - && fwuser->ipfw.fw_proto != IPPROTO_ICMP))) { - duprintf("convert_ipfw: Can only test ports for TCP/UDP/ICMP!\n"); - *errno = EINVAL; - return NULL; - } - - fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_ATOMIC); - if (!fwkern) { - duprintf("convert_ipfw: kmalloc failed!\n"); - *errno = ENOMEM; - return NULL; - } - memcpy(&fwkern->ipfw,&fwuser->ipfw,sizeof(struct ip_fw)); - - if (!find_special(fwuser->label, &fwkern->simplebranch)) { - fwkern->branch = find_label(fwuser->label); - if (!fwkern->branch) { - duprintf("convert_ipfw: chain doesn't exist `%s'.\n", - fwuser->label); - kfree(fwkern); - *errno = ENOENT; - return NULL; - } else if (fwkern->branch == IP_FW_INPUT_CHAIN - || fwkern->branch == IP_FW_FORWARD_CHAIN - || fwkern->branch == IP_FW_OUTPUT_CHAIN) { - duprintf("convert_ipfw: Can't branch to builtin chain `%s'.\n", - fwuser->label); - kfree(fwkern); - *errno = ENOENT; - return NULL; - } - } else - fwkern->branch = NULL; - memset(fwkern->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS); - - /* Handle empty vianame by making it a wildcard */ - if ((fwkern->ipfw.fw_vianame)[0] == '\0') - fwkern->ipfw.fw_flg |= IP_FW_F_WILDIF; - - fwkern->next = NULL; - return fwkern; -} - -int ip_fw_ctl(int cmd, void *m, int len) -{ - int ret; - struct ip_chain *chain; - unsigned long flags; - - FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - - switch (cmd) { - case IP_FW_FLUSH: - if (len != sizeof(ip_chainlabel) || !check_label(m)) - ret = EINVAL; - else if ((chain = find_label(m)) == NULL) - ret = ENOENT; - else ret = clear_fw_chain(chain); - break; - - case IP_FW_ZERO: - if (len != sizeof(ip_chainlabel) || !check_label(m)) - ret = EINVAL; - else if ((chain = find_label(m)) == NULL) - ret = ENOENT; - else ret = zero_fw_chain(chain); - break; - - case IP_FW_CHECK: { - struct ip_fwtest *new = m; - struct iphdr *ip; - - /* Don't need write lock. */ - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - - if (len != sizeof(struct ip_fwtest) || !check_label(m)) - return EINVAL; - - /* Need readlock to do find_label */ - FWC_READ_LOCK(&ip_fw_lock); - - if ((chain = find_label(new->fwt_label)) == NULL) - ret = ENOENT; - else { - struct sk_buff *tmp_skb; - int hdrlen; - - hdrlen = sizeof(struct ip_fwpkt) - - sizeof(struct in_addr) - - IFNAMSIZ; - - ip = &(new->fwt_packet.fwp_iph); - - /* Fix this one up by hand, who knows how many - * tools will break if we start to barf on this. - */ - if (ntohs(ip->tot_len) > hdrlen) - ip->tot_len = htons(hdrlen); - - if (ip->ihl != sizeof(struct iphdr) / sizeof(u32)) { - duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n", - ip->ihl, - sizeof(struct iphdr) / sizeof(u32)); - ret = EINVAL; - } else if ((tmp_skb = alloc_skb(hdrlen, - GFP_ATOMIC)) == NULL) { - duprintf("ip_fw_ctl: tmp_skb alloc failure\n"); - ret = EFAULT; - } else { - skb_reserve(tmp_skb, hdrlen); - skb_push(tmp_skb, hdrlen); - memcpy(tmp_skb->data, ip, hdrlen); - tmp_skb->nh.raw = - (unsigned char *) tmp_skb->data; - ret = ip_fw_check(new->fwt_packet.fwp_vianame, - NULL, chain, - &tmp_skb, SLOT_NUMBER(), 1); - kfree_skb(tmp_skb); - switch (ret) { - case FW_ACCEPT: - ret = 0; break; - case FW_REDIRECT: - ret = ECONNABORTED; break; - case FW_MASQUERADE: - ret = ECONNRESET; break; - case FW_REJECT: - ret = ECONNREFUSED; break; - /* Hack to help diag; these only get - returned when testing. */ - case FW_SKIP+1: - ret = ELOOP; break; - case FW_SKIP: - ret = ENFILE; break; - default: /* FW_BLOCK */ - ret = ETIMEDOUT; break; - } - } - } - FWC_READ_UNLOCK(&ip_fw_lock); - return ret; - } - - case IP_FW_MASQ_TIMEOUTS: { - ret = ip_fw_masq_timeouts(m, len); - } - break; - - case IP_FW_REPLACE: { - struct ip_fwkernel *ip_fwkern; - struct ip_fwnew *new = m; - - if (len != sizeof(struct ip_fwnew) - || !check_label(new->fwn_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwn_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret)) - != NULL) - ret = replace_in_chain(chain, ip_fwkern, - new->fwn_rulenum); - } - break; - - case IP_FW_APPEND: { - struct ip_fwchange *new = m; - struct ip_fwkernel *ip_fwkern; - - if (len != sizeof(struct ip_fwchange) - || !check_label(new->fwc_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwc_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret)) - != NULL) - ret = append_to_chain(chain, ip_fwkern); - } - break; - - case IP_FW_INSERT: { - struct ip_fwkernel *ip_fwkern; - struct ip_fwnew *new = m; - - if (len != sizeof(struct ip_fwnew) - || !check_label(new->fwn_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwn_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret)) - != NULL) - ret = insert_in_chain(chain, ip_fwkern, - new->fwn_rulenum); - } - break; - - case IP_FW_DELETE: { - struct ip_fwchange *new = m; - struct ip_fwkernel *ip_fwkern; - - if (len != sizeof(struct ip_fwchange) - || !check_label(new->fwc_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwc_label)) == NULL) - ret = ENOENT; - else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret)) - != NULL) { - ret = del_rule_from_chain(chain, ip_fwkern); - kfree(ip_fwkern); - } - } - break; - - case IP_FW_DELETE_NUM: { - struct ip_fwdelnum *new = m; - - if (len != sizeof(struct ip_fwdelnum) - || !check_label(new->fwd_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwd_label)) == NULL) - ret = ENOENT; - else ret = del_num_from_chain(chain, new->fwd_rulenum); - } - break; - - case IP_FW_CREATECHAIN: { - if (len != sizeof(ip_chainlabel)) { - duprintf("create_chain: bad size %i\n", len); - ret = EINVAL; - } - else ret = create_chain(m); - } - break; - - case IP_FW_DELETECHAIN: { - if (len != sizeof(ip_chainlabel)) { - duprintf("delete_chain: bad size %i\n", len); - ret = EINVAL; - } - else ret = del_chain(m); - } - break; - - case IP_FW_POLICY: { - struct ip_fwpolicy *new = m; - - if (len != sizeof(struct ip_fwpolicy) - || !check_label(new->fwp_label)) - ret = EINVAL; - else if ((chain = find_label(new->fwp_label)) == NULL) - ret = ENOENT; - else if (chain != IP_FW_INPUT_CHAIN - && chain != IP_FW_FORWARD_CHAIN - && chain != IP_FW_OUTPUT_CHAIN) { - duprintf("change_policy: can't change policy on user" - " defined chain.\n"); - ret = EINVAL; - } - else { - int pol = FW_SKIP; - find_special(new->fwp_policy, &pol); - - switch(pol) { - case FW_MASQUERADE: - if (chain != IP_FW_FORWARD_CHAIN) { - ret = EINVAL; - break; - } - /* Fall thru... */ - case FW_BLOCK: - case FW_ACCEPT: - case FW_REJECT: - ret = change_policy(chain, pol); - break; - default: - duprintf("change_policy: bad policy `%s'\n", - new->fwp_policy); - ret = EINVAL; - } - } - break; - } - default: - duprintf("ip_fw_ctl: unknown request %d\n",cmd); - ret = ENOPROTOOPT; - } - - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - return ret; -} - -/* Returns bytes used - doesn't NUL terminate */ -static int dump_rule(char *buffer, - const char *chainlabel, - const struct ip_fwkernel *rule) -{ - int len; - unsigned int i; - __u64 packets = 0, bytes = 0; - - FWC_HAVE_LOCK(fwc_wlocks); - for (i = 0; i < NUM_SLOTS; i++) { - packets += rule->counters[i].pcnt; - bytes += rule->counters[i].bcnt; - } - - len=sprintf(buffer, - "%9s " /* Chain name */ - "%08X/%08X->%08X/%08X " /* Source & Destination IPs */ - "%.16s " /* Interface */ - "%X %X " /* fw_flg and fw_invflg fields */ - "%u " /* Protocol */ - "%-9u %-9u %-9u %-9u " /* Packet & byte counters */ - "%u-%u %u-%u " /* Source & Dest port ranges */ - "A%02X X%02X " /* TOS and and xor masks */ - "%08X " /* Redirection port */ - "%u " /* fw_mark field */ - "%u " /* output size */ - "%9s\n", /* Target */ - chainlabel, - ntohl(rule->ipfw.fw_src.s_addr), - ntohl(rule->ipfw.fw_smsk.s_addr), - ntohl(rule->ipfw.fw_dst.s_addr), - ntohl(rule->ipfw.fw_dmsk.s_addr), - (rule->ipfw.fw_vianame)[0] ? rule->ipfw.fw_vianame : "-", - rule->ipfw.fw_flg, - rule->ipfw.fw_invflg, - rule->ipfw.fw_proto, - (__u32)(packets >> 32), (__u32)packets, - (__u32)(bytes >> 32), (__u32)bytes, - rule->ipfw.fw_spts[0], rule->ipfw.fw_spts[1], - rule->ipfw.fw_dpts[0], rule->ipfw.fw_dpts[1], - rule->ipfw.fw_tosand, rule->ipfw.fw_tosxor, - rule->ipfw.fw_redirpt, - rule->ipfw.fw_mark, - rule->ipfw.fw_outputsize, - branchname(rule->branch,rule->simplebranch)); - - duprintf("dump_rule: %i bytes done.\n", len); - return len; -} - -/* File offset is actually in records, not bytes. */ -static int ip_chain_procinfo(char *buffer, char **start, - off_t offset, int length) -{ - struct ip_chain *i; - struct ip_fwkernel *j = ip_fw_chains->chain; - unsigned long flags; - int len = 0; - int last_len = 0; - off_t upto = 0; - - duprintf("Offset starts at %lu\n", offset); - duprintf("ip_fw_chains is 0x%0lX\n", (unsigned long int)ip_fw_chains); - - /* Need a write lock to lock out ``readers'' which update counters. */ - FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - - for (i = ip_fw_chains; i; i = i->next) { - for (j = i->chain; j; j = j->next) { - if (upto == offset) break; - duprintf("Skipping rule in chain `%s'\n", - i->label); - upto++; - } - if (upto == offset) break; - } - - /* Don't init j first time, or once i = NULL */ - for (; i; (void)((i = i->next) && (j = i->chain))) { - duprintf("Dumping chain `%s'\n", i->label); - for (; j; j = j->next, upto++, last_len = len) - { - len += dump_rule(buffer+len, i->label, j); - if (len > length) { - duprintf("Dumped to %i (past %i). " - "Moving back to %i.\n", - len, length, last_len); - len = last_len; - goto outside; - } - } - } -outside: - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - buffer[len] = '\0'; - - duprintf("ip_chain_procinfo: Length = %i (of %i). Offset = %li.\n", - len, length, upto); - /* `start' hack - see fs/proc/generic.c line ~165 */ - *start=(char *)((unsigned int)upto-offset); - return len; -} - -static int ip_chain_name_procinfo(char *buffer, char **start, - off_t offset, int length) -{ - struct ip_chain *i; - int len = 0,last_len = 0; - off_t pos = 0,begin = 0; - unsigned long flags; - - /* Need a write lock to lock out ``readers'' which update counters. */ - FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - - for (i = ip_fw_chains; i; i = i->next) - { - unsigned int j; - __u32 packetsHi = 0, packetsLo = 0, bytesHi = 0, bytesLo = 0; - - for (j = 0; j < NUM_SLOTS; j++) { - packetsLo += i->reent[j].counters.pcnt & 0xFFFFFFFF; - packetsHi += ((i->reent[j].counters.pcnt >> 32) - & 0xFFFFFFFF); - bytesLo += i->reent[j].counters.bcnt & 0xFFFFFFFF; - bytesHi += ((i->reent[j].counters.bcnt >> 32) - & 0xFFFFFFFF); - } - - /* print the label and the policy */ - len+=sprintf(buffer+len,"%s %s %i %u %u %u %u\n", - i->label,branchname(NULL, i->policy),i->refcount, - packetsHi, packetsLo, bytesHi, bytesLo); - pos=begin+len; - if(posoffset+length) { - len = last_len; - break; - } - - last_len = len; - } - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - - *start = buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} - -/* - * Interface to the generic firewall chains. - */ -int ipfw_input_check(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb) -{ - return ip_fw_check(dev->name, - arg, IP_FW_INPUT_CHAIN, pskb, SLOT_NUMBER(), 0); -} - -int ipfw_output_check(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb) -{ - /* Locally generated bogus packets by root. . */ - if ((*pskb)->len < sizeof(struct iphdr) || - (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) - return FW_ACCEPT; - return ip_fw_check(dev->name, - arg, IP_FW_OUTPUT_CHAIN, pskb, SLOT_NUMBER(), 0); -} - -int ipfw_forward_check(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb) -{ - return ip_fw_check(dev->name, - arg, IP_FW_FORWARD_CHAIN, pskb, SLOT_NUMBER(), 0); -} - -struct firewall_ops ipfw_ops = { - .fw_forward = ipfw_forward_check, - .fw_input = ipfw_input_check, - .fw_output = ipfw_output_check, -}; - -int ipfw_init_or_cleanup(int init) -{ - struct proc_dir_entry *proc; - int ret = 0; - unsigned long flags; - - if (!init) goto cleanup; - -#ifdef DEBUG_IP_FIREWALL_LOCKING - fwc_wlocks = fwc_rlocks = 0; -#endif - -#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) - ipfwsk = netlink_kernel_create(NETLINK_FIREWALL, NULL); - if (ipfwsk == NULL) - goto cleanup_nothing; -#endif - - ret = register_firewall(PF_INET, &ipfw_ops); - if (ret < 0) - goto cleanup_netlink; - - proc = proc_net_create(IP_FW_PROC_CHAINS, S_IFREG | S_IRUSR | S_IWUSR, - ip_chain_procinfo); - if (proc) proc->owner = THIS_MODULE; - proc = proc_net_create(IP_FW_PROC_CHAIN_NAMES, - S_IFREG | S_IRUSR | S_IWUSR, - ip_chain_name_procinfo); - if (proc) proc->owner = THIS_MODULE; - - IP_FW_INPUT_CHAIN = ip_init_chain(IP_FW_LABEL_INPUT, 1, FW_ACCEPT); - IP_FW_FORWARD_CHAIN = ip_init_chain(IP_FW_LABEL_FORWARD, 1, FW_ACCEPT); - IP_FW_OUTPUT_CHAIN = ip_init_chain(IP_FW_LABEL_OUTPUT, 1, FW_ACCEPT); - - return ret; - - cleanup: - unregister_firewall(PF_INET, &ipfw_ops); - - FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - while (ip_fw_chains) { - struct ip_chain *next = ip_fw_chains->next; - - clear_fw_chain(ip_fw_chains); - kfree(ip_fw_chains); - ip_fw_chains = next; - } - FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); - - proc_net_remove(IP_FW_PROC_CHAINS); - proc_net_remove(IP_FW_PROC_CHAIN_NAMES); - - cleanup_netlink: -#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) - sock_release(ipfwsk->sk_socket); - - cleanup_nothing: -#endif - return ret; -} diff -L net/ipv4/netfilter/ipfwadm_core.c -puN net/ipv4/netfilter/ipfwadm_core.c~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/net/ipv4/netfilter/ipfwadm_core.c +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,1464 +0,0 @@ -#warning ipfwadm is obsolete, and will be removed soon. - -/* Minor modifications to fit on compatibility framework: - Rusty.Russell@rustcorp.com.au -*/ - -#include -#define CONFIG_IP_FIREWALL -#define CONFIG_IP_FIREWALL_VERBOSE -#define CONFIG_IP_MASQUERADE -#define CONFIG_IP_ACCT -#define CONFIG_IP_TRANSPARENT_PROXY -#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) -#define CONFIG_IP_FIREWALL_NETLINK -#endif - -/* - * IP firewalling code. This is taken from 4.4BSD. Please note the - * copyright message below. As per the GPL it must be maintained - * and the licenses thus do not conflict. While this port is subject - * to the GPL I also place my modifications under the original - * license in recognition of the original copyright. - * -- Alan Cox. - * - * $Id: ipfwadm_core.c,v 1.11 2002/01/24 15:50:31 davem Exp $ - * - * Ported from BSD to Linux, - * Alan Cox 22/Nov/1994. - * Zeroing /proc and other additions - * Jos Vos 4/Feb/1995. - * Merged and included the FreeBSD-Current changes at Ugen's request - * (but hey it's a lot cleaner now). Ugen would prefer in some ways - * we waited for his final product but since Linux 1.2.0 is about to - * appear it's not practical - Read: It works, it's not clean but please - * don't consider it to be his standard of finished work. - * Alan Cox 12/Feb/1995 - * Porting bidirectional entries from BSD, fixing accounting issues, - * adding struct ip_fwpkt for checking packets with interface address - * Jos Vos 5/Mar/1995. - * Established connections (ACK check), ACK check on bidirectional rules, - * ICMP type check. - * Wilfred Mollenvanger 7/7/1995. - * TCP attack protection. - * Alan Cox 25/8/95, based on information from bugtraq. - * ICMP type printk, IP_FW_F_APPEND - * Bernd Eckenfels 1996-01-31 - * Split blocking chain into input and output chains, add new "insert" and - * "append" commands to replace semi-intelligent "add" command, let "delete". - * only delete the first matching entry, use 0xFFFF (0xFF) as ports (ICMP - * types) when counting packets being 2nd and further fragments. - * Jos Vos 8/2/1996. - * Add support for matching on device names. - * Jos Vos 15/2/1996. - * Transparent proxying support. - * Willy Konynenberg 10/5/96. - * Make separate accounting on incoming and outgoing packets possible. - * Jos Vos 18/5/1996. - * Added trap out of bad frames. - * Alan Cox 17/11/1996 - * - * - * Masquerading functionality - * - * Copyright (c) 1994 Pauline Middelink - * - * The pieces which added masquerading functionality are totally - * my responsibility and have nothing to with the original authors - * copyright or doing. - * - * Parts distributed under GPL. - * - * Fixes: - * Pauline Middelink : Added masquerading. - * Alan Cox : Fixed an error in the merge. - * Thomas Quinot : Fixed port spoofing. - * Alan Cox : Cleaned up retransmits in spoofing. - * Alan Cox : Cleaned up length setting. - * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands - * - * Juan Jose Ciarlante : Masquerading code moved to ip_masq.c - * Andi Kleen : Print frag_offsets and the ip flags properly. - * - * All the real work was done by ..... - * - */ - - -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("ipfwadm backwards compatibility layer"); - -/* - * Implement IP packet firewall - */ - -#ifdef DEBUG_IP_FIREWALL -#define dprintf1(a) printk(a) -#define dprintf2(a1,a2) printk(a1,a2) -#define dprintf3(a1,a2,a3) printk(a1,a2,a3) -#define dprintf4(a1,a2,a3,a4) printk(a1,a2,a3,a4) -#else -#define dprintf1(a) -#define dprintf2(a1,a2) -#define dprintf3(a1,a2,a3) -#define dprintf4(a1,a2,a3,a4) -#endif - -#define print_ip(a) printk("%u.%u.%u.%u", NIPQUAD(a)); - -#ifdef DEBUG_IP_FIREWALL -#define dprint_ip(a) print_ip(a) -#else -#define dprint_ip(a) -#endif - -static DECLARE_RWLOCK(ip_fw_lock); - -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) - -struct ip_fw *ip_fw_fwd_chain; -struct ip_fw *ip_fw_in_chain; -struct ip_fw *ip_fw_out_chain; -struct ip_fw *ip_acct_chain; -struct ip_fw *ip_masq_chain; - -static struct ip_fw **chains[] = - {&ip_fw_fwd_chain, &ip_fw_in_chain, &ip_fw_out_chain, &ip_acct_chain, - &ip_masq_chain - }; -#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */ - -#ifdef CONFIG_IP_FIREWALL -int ip_fw_fwd_policy=IP_FW_F_ACCEPT; -int ip_fw_in_policy=IP_FW_F_ACCEPT; -int ip_fw_out_policy=IP_FW_F_ACCEPT; - -static int *policies[] = - {&ip_fw_fwd_policy, &ip_fw_in_policy, &ip_fw_out_policy}; - -#endif - -#ifdef CONFIG_IP_FIREWALL_NETLINK -struct sock *ipfwsk; -#endif - -/* - * Returns 1 if the port is matched by the vector, 0 otherwise - */ - -extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag) -{ - if (!nports) - return 1; - if ( range_flag ) - { - if ( portptr[0] <= port && port <= portptr[1] ) - { - return( 1 ); - } - nports -= 2; - portptr += 2; - } - while ( nports-- > 0 ) - { - if ( *portptr++ == port ) - { - return( 1 ); - } - } - return(0); -} - -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) - -#ifdef CONFIG_IP_FIREWALL_VERBOSE - -/* - * VERY ugly piece of code which actually makes kernel printf for - * matching packets. - */ - -static char *chain_name(struct ip_fw *chain, int mode) -{ - switch (mode) { - case IP_FW_MODE_ACCT_IN: return "acct in"; - case IP_FW_MODE_ACCT_OUT: return "acct out"; - default: - if (chain == ip_fw_fwd_chain) - return "fw-fwd"; - else if (chain == ip_fw_in_chain) - return "fw-in"; - else - return "fw-out"; - } -} - -static char *rule_name(struct ip_fw *f, int mode, char *buf) -{ - if (mode == IP_FW_MODE_ACCT_IN || mode == IP_FW_MODE_ACCT_OUT) - return ""; - - if(f->fw_flg&IP_FW_F_ACCEPT) { - if(f->fw_flg&IP_FW_F_REDIR) { - sprintf(buf, "acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]); - return buf; - } else if(f->fw_flg&IP_FW_F_MASQ) - return "acc/masq "; - else - return "acc "; - } else if(f->fw_flg&IP_FW_F_ICMPRPL) { - return "rej "; - } else { - return "deny "; - } -} - -static void print_packet(struct sk_buff **pskb, - u16 src_port, u16 dst_port, u16 icmp_type, - char *chain, char *rule, char *devname) -{ - __u32 *opt = (__u32 *) ((*pskb)->nh.iph + 1); - int opti; - __u16 foff = ntohs((*pskb)->nh.iph->frag_off); - int protocol = (*pskb)->nh.iph->protocol; - - printk(KERN_INFO "IP %s %s%s", chain, rule, devname); - - switch (protocol) { - case IPPROTO_TCP: - printk(" TCP "); - break; - case IPPROTO_UDP: - printk(" UDP "); - break; - case IPPROTO_ICMP: - printk(" ICMP/%d ", icmp_type); - break; - default: - printk(" PROTO=%d ", protocol); - break; - }; - - print_ip((*pskb)->nh.iph->saddr); - if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) - printk(":%hu", src_port); - printk(" "); - print_ip((*pskb)->nh.iph->daddr); - if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) - printk(":%hu", dst_port); - printk(" L=%hu S=0x%2.2hX I=%hu FO=0x%4.4hX T=%hu", - ntohs((*pskb)->nh.iph->tot_len), - (*pskb)->nh.iph->tos, - ntohs((*pskb)->nh.iph->id), - foff & IP_OFFSET, - (*pskb)->nh.iph->ttl); - if (foff & IP_DF) - printk(" DF=1"); - if (foff & IP_MF) - printk(" MF=1"); - for (opti = 0; opti < ((*pskb)->nh.iph->ihl - sizeof(struct iphdr) / 4); opti++) - printk(" O=0x%8.8X", *opt++); - printk("\n"); -} -#endif - -/* - * Returns one of the generic firewall policies, like FW_ACCEPT. - * Also does accounting so you can feed it the accounting chain. - * - * The modes is either IP_FW_MODE_FW (normal firewall mode), - * IP_FW_MODE_ACCT_IN or IP_FW_MODE_ACCT_OUT (accounting mode, - * steps through the entire chain and handles fragments - * differently), or IP_FW_MODE_CHK (handles user-level check, - * counters are not updated). - */ - - -int ip_fw_chk(struct sk_buff **pskb, - struct net_device *rif, __u16 *redirport, - struct ip_fw *chain, int policy, int mode) -{ - struct ip_fw *f; - __u32 src, dst; - __u16 src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF; - unsigned short f_prt=0, prt; - char notcpsyn=0, notcpack=0, match; - unsigned short offset; - int answer; - unsigned char tosand, tosxor; - int protocol; - - /* - * If the chain is empty follow policy. The BSD one - * accepts anything giving you a time window while - * flushing and rebuilding the tables. - */ - - /* - * This way we handle fragmented packets. - * we ignore all fragments but the first one - * so the whole packet can't be reassembled. - * This way we relay on the full info which - * stored only in first packet. - * - * Note that this theoretically allows partial packet - * spoofing. Not very dangerous but paranoid people may - * wish to play with this. It also allows the so called - * "fragment bomb" denial of service attack on some types - * of system. - */ - - offset = ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET; - protocol = (*pskb)->nh.iph->protocol; - - /* - * Don't allow a fragment of TCP 8 bytes in. Nobody - * normal causes this. Its a cracker trying to break - * in by doing a flag overwrite to pass the direction - * checks. - */ - - if (offset == 1 && protocol == IPPROTO_TCP) - return FW_BLOCK; - - if (offset!=0 && !(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)) && - (protocol == IPPROTO_TCP || - protocol == IPPROTO_UDP || - protocol == IPPROTO_ICMP)) - return FW_ACCEPT; - - /* - * Header fragment for TCP is too small to check the bits. - */ - - if (protocol == IPPROTO_TCP && - ((*pskb)->nh.iph->ihl<<2)+16 > ntohs((*pskb)->nh.iph->tot_len)) - return FW_BLOCK; - - /* - * Too short. - * - * But only too short for a packet with ports... - */ - - else if ((ntohs((*pskb)->nh.iph->tot_len) < - 8 + ((*pskb)->nh.iph->ihl << 2)) && - (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP)) - return FW_BLOCK; - - src = (*pskb)->nh.iph->saddr; - dst = (*pskb)->nh.iph->daddr; - - /* - * If we got interface from which packet came - * we can use the address directly. This is unlike - * 4.4BSD derived systems that have an address chain - * per device. We have a device per address with dummy - * devices instead. - */ - - dprintf1("Packet "); - switch (protocol) { - case IPPROTO_TCP: - dprintf1("TCP "); - /* ports stay 0xFFFF if it is not the first fragment */ - if (!offset) { - struct tcphdr _tcph, *th; - - th = skb_header_pointer(*pskb, - (*pskb)->nh.iph->ihl*4, - sizeof(_tcph), &_tcph); - if (th == NULL) - return FW_BLOCK; - - src_port = ntohs(th->source); - dst_port = ntohs(th->dest); - - if(!th->ack && !th->rst) - /* We do NOT have ACK, value TRUE */ - notcpack = 1; - if(!th->syn || !notcpack) - /* We do NOT have SYN, value TRUE */ - notcpsyn = 1; - } - prt = IP_FW_F_TCP; - break; - case IPPROTO_UDP: - dprintf1("UDP "); - /* ports stay 0xFFFF if it is not the first fragment */ - if (!offset) { - struct udphdr _udph, *uh; - - uh = skb_header_pointer(*pskb, - (*pskb)->nh.iph->ihl*4, - sizeof(_udph), &_udph); - if (uh == NULL) - return FW_BLOCK; - - src_port = ntohs(uh->source); - dst_port = ntohs(uh->dest); - } - prt = IP_FW_F_UDP; - break; - case IPPROTO_ICMP: - /* icmp_type stays 255 if it is not the first fragment */ - if (!offset) { - struct icmphdr _icmph, *ic; - - ic = skb_header_pointer(*pskb, - (*pskb)->nh.iph->ihl*4, - sizeof(_icmph), - &_icmph); - if (ic == NULL) - return FW_BLOCK; - - icmp_type = (__u16) ic->type; - } - dprintf2("ICMP:%d ", icmp_type); - prt = IP_FW_F_ICMP; - break; - default: - dprintf2("p=%d ", protocol); - prt = IP_FW_F_ALL; - break; - } -#ifdef DEBUG_IP_FIREWALL - dprint_ip(src); - - if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) - /* This will print 65535 when it is not the first fragment! */ - dprintf2(":%d ", src_port); - dprint_ip(dst); - if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) - /* This will print 65535 when it is not the first fragment! */ - dprintf2(":%d ", dst_port); - dprintf1("\n"); -#endif - - if (mode == IP_FW_MODE_CHK) - READ_LOCK(&ip_fw_lock); - else - WRITE_LOCK(&ip_fw_lock); - - for (f = chain; f; f = f->fw_next) { - /* - * This is a bit simpler as we don't have to walk - * an interface chain as you do in BSD - same logic - * however. - */ - - /* - * Match can become 0x01 (a "normal" match was found), - * 0x02 (a reverse match was found), and 0x03 (the - * IP addresses match in both directions). - * Now we know in which direction(s) we should look - * for a match for the TCP/UDP ports. Both directions - * might match (e.g., when both addresses are on the - * same network for which an address/mask is given), but - * the ports might only match in one direction. - * This was obviously wrong in the original BSD code. - */ - match = 0x00; - - if ((src & f->fw_smsk.s_addr) == f->fw_src.s_addr && - (dst & f->fw_dmsk.s_addr) == f->fw_dst.s_addr) - /* normal direction */ - match |= 0x01; - - if ((f->fw_flg & IP_FW_F_BIDIR) && - (dst & f->fw_smsk.s_addr) == f->fw_src.s_addr && - (src & f->fw_dmsk.s_addr) == f->fw_dst.s_addr) - /* reverse direction */ - match |= 0x02; - - if (!match) - continue; - - /* - * Look for a VIA device match - */ - if (f->fw_viadev) { - if (rif != f->fw_viadev) - continue; /* Mismatch */ - } - - /* This looks stupid, because we scan almost static - list, searching for static key. However, this way seems - to be only reasonable way of handling fw_via rules - (btw bsd makes the same thing). - - It will not affect performance if you will follow - the following simple rules: - - - if interface is aliased, ALWAYS specify fw_viadev, - so that previous check will guarantee, that we will - not waste time when packet arrive on another interface. - - - avoid using fw_via.s_addr if fw_via.s_addr is owned - by an aliased interface. - - --ANK - */ - if (f->fw_via.s_addr && rif) { - struct in_ifaddr *ifa; - - if (rif->ip_ptr == NULL) - continue; /* Mismatch */ - - for (ifa = ((struct in_device*)(rif->ip_ptr))->ifa_list; - ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_local == f->fw_via.s_addr) - goto ifa_ok; - } - continue; /* Mismatch */ - - ifa_ok:; - } - - /* - * Ok the chain addresses match. - */ - -#ifdef CONFIG_IP_ACCT - /* - * See if we're in accounting mode and only want to - * count incoming or outgoing packets. - */ - - if (mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT) && - ((mode == IP_FW_MODE_ACCT_IN && f->fw_flg&IP_FW_F_ACCTOUT) || - (mode == IP_FW_MODE_ACCT_OUT && f->fw_flg&IP_FW_F_ACCTIN))) - continue; - -#endif - /* - * For all non-TCP packets and/or non-first fragments, - * notcpsyn and notcpack will always be FALSE, - * so the IP_FW_F_TCPSYN and IP_FW_F_TCPACK flags - * are actually ignored for these packets. - */ - - if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn) - continue; - - if((f->fw_flg&IP_FW_F_TCPACK) && notcpack) - continue; - - f_prt=f->fw_flg&IP_FW_F_KIND; - if (f_prt != IP_FW_F_ALL) { - /* - * Specific firewall - packet's protocol - * must match firewall's. - */ - - if (prt != f_prt) - continue; - - if((prt==IP_FW_F_ICMP && - ! port_match(&f->fw_pts[0], f->fw_nsp, - icmp_type,f->fw_flg&IP_FW_F_SRNG)) || - !(prt==IP_FW_F_ICMP || ((match & 0x01) && - port_match(&f->fw_pts[0], f->fw_nsp, src_port, - f->fw_flg&IP_FW_F_SRNG) && - port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port, - f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) && - port_match(&f->fw_pts[0], f->fw_nsp, dst_port, - f->fw_flg&IP_FW_F_SRNG) && - port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port, - f->fw_flg&IP_FW_F_DRNG)))) - { - continue; - } - } - -#ifdef CONFIG_IP_FIREWALL_VERBOSE - if (f->fw_flg & IP_FW_F_PRN) - { - char buf[16]; - - print_packet(pskb, src_port, dst_port, icmp_type, - chain_name(chain, mode), - rule_name(f, mode, buf), - rif ? rif->name : "-"); - } -#endif - if (mode != IP_FW_MODE_CHK) { - f->fw_bcnt += ntohs((*pskb)->nh.iph->tot_len); - f->fw_pcnt++; - } - if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT))) - break; - } /* Loop */ - - if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT))) { - - /* - * We rely on policy defined in the rejecting entry or, if no match - * was found, we rely on the general policy variable for this type - * of firewall. - */ - - if (f != NULL) { - policy = f->fw_flg; - tosand = f->fw_tosand; - tosxor = f->fw_tosxor; - } else { - tosand = 0xFF; - tosxor = 0x00; - } - - if (policy & IP_FW_F_ACCEPT) { - /* Adjust priority and recompute checksum */ - __u8 tos = (*pskb)->nh.iph->tos; - - if (((tos & tosand) ^ tosxor) != tos) { - if (!skb_ip_make_writable(pskb, - offsetof(struct iphdr, tos)+1)) - goto drop_it; - - (*pskb)->nh.iph->tos = (tos & tosand) ^ tosxor; - ip_send_check((*pskb)->nh.iph); - } - -#ifdef CONFIG_IP_TRANSPARENT_PROXY - if (policy & IP_FW_F_REDIR) { - if (redirport) - if ((*redirport = htons(f->fw_pts[f->fw_nsp+f->fw_ndp])) == 0) { - /* Wildcard redirection. - * Note that redirport will become - * 0xFFFF for non-TCP/UDP packets. - */ - *redirport = htons(dst_port); - } - answer = FW_REDIRECT; - } else -#endif -#ifdef CONFIG_IP_MASQUERADE - if (policy & IP_FW_F_MASQ) - answer = FW_MASQUERADE; - else -#endif - answer = FW_ACCEPT; - - } else if (policy & IP_FW_F_ICMPRPL) - answer = FW_REJECT; - else { - drop_it: - answer = FW_BLOCK; - } - -#ifdef CONFIG_IP_FIREWALL_NETLINK - if ((policy & IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK)) - { - struct sk_buff *skb = alloc_skb(128, - (mode == IP_FW_MODE_CHK) ? - GFP_KERNEL : GFP_ATOMIC); - if (skb) { - int len = min_t(unsigned int, - 128, - ntohs((*pskb)->nh.iph->tot_len)); - - skb_put(skb, len); - skb_copy_bits(*pskb, - ((char *)(*pskb)->nh.iph - - (char *)(*pskb)->data), - skb->data, len); - if (netlink_post(NETLINK_FIREWALL, skb)) - kfree_skb(skb); - } - } -#endif - } else - /* we're doing accounting, always ok */ - answer = 0; - - if (mode == IP_FW_MODE_CHK) - READ_UNLOCK(&ip_fw_lock); - else - WRITE_UNLOCK(&ip_fw_lock); - - return answer; -} - - -static void zero_fw_chain(struct ip_fw *chainptr) -{ - struct ip_fw *ctmp=chainptr; - - WRITE_LOCK(&ip_fw_lock); - while(ctmp) - { - ctmp->fw_pcnt=0L; - ctmp->fw_bcnt=0L; - ctmp=ctmp->fw_next; - } - WRITE_UNLOCK(&ip_fw_lock); -} - -static void free_fw_chain(struct ip_fw *volatile* chainptr) -{ - WRITE_LOCK(&ip_fw_lock); - while ( *chainptr != NULL ) - { - struct ip_fw *ftmp; - ftmp = *chainptr; - *chainptr = ftmp->fw_next; - if (ftmp->fw_viadev - && ftmp->fw_viadev != (struct net_device *)-1) - dev_put(ftmp->fw_viadev); - kfree(ftmp); - /* We will block in cleanup's unregister sockopt if unloaded, - so this is safe. */ - module_put(THIS_MODULE); - } - WRITE_UNLOCK(&ip_fw_lock); -} - -/* Volatiles to keep some of the compiler versions amused */ - -static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len) -{ - struct ip_fw *ftmp; - - /* Are we unloading now? We will block on nf_unregister_sockopt */ - if (!try_module_get(THIS_MODULE)) - return ENOPROTOOPT; - - ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL ); - if ( ftmp == NULL ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: malloc said no\n"); -#endif - return( ENOMEM ); - } - - memcpy(ftmp, frwl, len); - /* - * Allow the more recent "minimise cost" flag to be - * set. [Rob van Nieuwkerk] - */ - ftmp->fw_tosand |= 0x01; - ftmp->fw_tosxor &= 0xFE; - ftmp->fw_pcnt=0L; - ftmp->fw_bcnt=0L; - - WRITE_LOCK(&ip_fw_lock); - - if ((ftmp->fw_vianame)[0]) { - if (!(ftmp->fw_viadev = dev_get_by_name(ftmp->fw_vianame))) - ftmp->fw_viadev = (struct net_device *) -1; - } else - ftmp->fw_viadev = NULL; - - ftmp->fw_next = *chainptr; - *chainptr=ftmp; - WRITE_UNLOCK(&ip_fw_lock); - return(0); -} - -static int append_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len) -{ - struct ip_fw *ftmp; - struct ip_fw *chtmp=NULL; - struct ip_fw *volatile chtmp_prev=NULL; - - /* Are we unloading now? We will block on nf_unregister_sockopt */ - if (!try_module_get(THIS_MODULE)) - return ENOPROTOOPT; - - ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL ); - if ( ftmp == NULL ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: malloc said no\n"); -#endif - return( ENOMEM ); - } - - memcpy(ftmp, frwl, len); - /* - * Allow the more recent "minimise cost" flag to be - * set. [Rob van Nieuwkerk] - */ - ftmp->fw_tosand |= 0x01; - ftmp->fw_tosxor &= 0xFE; - ftmp->fw_pcnt=0L; - ftmp->fw_bcnt=0L; - - ftmp->fw_next = NULL; - - WRITE_LOCK(&ip_fw_lock); - - if ((ftmp->fw_vianame)[0]) { - if (!(ftmp->fw_viadev = dev_get_by_name(ftmp->fw_vianame))) - ftmp->fw_viadev = (struct net_device *) -1; - } else - ftmp->fw_viadev = NULL; - - chtmp_prev=NULL; - for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) - chtmp_prev=chtmp; - - if (chtmp_prev) - chtmp_prev->fw_next=ftmp; - else - *chainptr=ftmp; - WRITE_UNLOCK(&ip_fw_lock); - return(0); -} - -static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl) -{ - struct ip_fw *ftmp,*ltmp; - unsigned short tport1,tport2,tmpnum; - char matches,was_found; - - WRITE_LOCK(&ip_fw_lock); - - ftmp=*chainptr; - - if ( ftmp == NULL ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: chain is empty\n"); -#endif - WRITE_UNLOCK(&ip_fw_lock); - return( EINVAL ); - } - - ltmp=NULL; - was_found=0; - - while( !was_found && ftmp != NULL ) - { - matches=1; - if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr - || ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr - || ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr - || ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr - || ftmp->fw_via.s_addr!=frwl->fw_via.s_addr - || ftmp->fw_flg!=frwl->fw_flg) - matches=0; - - tport1=ftmp->fw_nsp+ftmp->fw_ndp; - tport2=frwl->fw_nsp+frwl->fw_ndp; - if (tport1!=tport2) - matches=0; - else if (tport1!=0) - { - for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++) - if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum]) - matches=0; - } - if (strncmp(ftmp->fw_vianame, frwl->fw_vianame, IFNAMSIZ)) - matches=0; - if(matches) - { - was_found=1; - if (ftmp->fw_viadev - && ftmp->fw_viadev != (struct net_device *)-1) - dev_put(ftmp->fw_viadev); - if (ltmp) - { - ltmp->fw_next=ftmp->fw_next; - kfree(ftmp); - ftmp=ltmp->fw_next; - } - else - { - *chainptr=ftmp->fw_next; - kfree(ftmp); - ftmp=*chainptr; - } - } - else - { - ltmp = ftmp; - ftmp = ftmp->fw_next; - } - } - WRITE_UNLOCK(&ip_fw_lock); - if (was_found) { - /* We will block in cleanup's unregister sockopt if unloaded, - so this is safe. */ - module_put(THIS_MODULE); - return 0; - } else - return(EINVAL); -} - -#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */ - -struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len) -{ - - if ( len != sizeof(struct ip_fw) ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw)); -#endif - return(NULL); - } - - if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n", - frwl->fw_flg); -#endif - return(NULL); - } - -#ifndef CONFIG_IP_TRANSPARENT_PROXY - if (frwl->fw_flg & IP_FW_F_REDIR) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unsupported flag IP_FW_F_REDIR\n"); -#endif - return(NULL); - } -#endif - -#ifndef CONFIG_IP_MASQUERADE - if (frwl->fw_flg & IP_FW_F_MASQ) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unsupported flag IP_FW_F_MASQ\n"); -#endif - return(NULL); - } -#endif - - if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: src range set but fw_nsp=%d\n", - frwl->fw_nsp); -#endif - return(NULL); - } - - if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: dst range set but fw_ndp=%d\n", - frwl->fw_ndp); -#endif - return(NULL); - } - - if ( frwl->fw_nsp + frwl->fw_ndp > (frwl->fw_flg & IP_FW_F_REDIR ? IP_FW_MAX_PORTS - 1 : IP_FW_MAX_PORTS) ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: too many ports (%d+%d)\n", - frwl->fw_nsp,frwl->fw_ndp); -#endif - return(NULL); - } - - return frwl; -} - - - - -#ifdef CONFIG_IP_ACCT - -int ip_acct_ctl(int stage, void *m, int len) -{ - if ( stage == IP_ACCT_FLUSH ) - { - free_fw_chain(&ip_acct_chain); - return(0); - } - if ( stage == IP_ACCT_ZERO ) - { - zero_fw_chain(ip_acct_chain); - return(0); - } - if ( stage == IP_ACCT_INSERT || stage == IP_ACCT_APPEND || - stage == IP_ACCT_DELETE ) - { - struct ip_fw *frwl; - - if (!(frwl=check_ipfw_struct(m,len))) - return (EINVAL); - - switch (stage) - { - case IP_ACCT_INSERT: - return( insert_in_chain(&ip_acct_chain,frwl,len)); - case IP_ACCT_APPEND: - return( append_to_chain(&ip_acct_chain,frwl,len)); - case IP_ACCT_DELETE: - return( del_from_chain(&ip_acct_chain,frwl)); - default: - /* - * Should be panic but... (Why ??? - AC) - */ -#ifdef DEBUG_IP_FIREWALL - printk("ip_acct_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); - } - } -#ifdef DEBUG_IP_FIREWALL - printk("ip_acct_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); -} -#endif - -#ifdef CONFIG_IP_FIREWALL -int ip_fw_ctl(int stage, void *m, int len) -{ - int cmd, fwtype; - - cmd = stage & IP_FW_COMMAND; - fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT; - - if ( cmd == IP_FW_FLUSH ) - { - free_fw_chain(chains[fwtype]); - return(0); - } - - if ( cmd == IP_FW_ZERO ) - { - zero_fw_chain(*chains[fwtype]); - return(0); - } - - if ( cmd == IP_FW_POLICY ) - { - int *tmp_policy_ptr; - tmp_policy_ptr=(int *)m; - *policies[fwtype] = *tmp_policy_ptr; - return 0; - } - - if ( cmd == IP_FW_CHECK ) - { - struct sk_buff *tmp_skb; - struct net_device *viadev; - struct ip_fwpkt *ipfwp; - struct iphdr *ip; - int hdrlen, ret; - - hdrlen = sizeof(struct ip_fwpkt) - - sizeof(struct in_addr) - - IFNAMSIZ; - - if ( len != sizeof(struct ip_fwpkt) ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: length=%d, expected %d\n", - len, sizeof(struct ip_fwpkt)); -#endif - return( EINVAL ); - } - - ipfwp = (struct ip_fwpkt *)m; - ip = &(ipfwp->fwp_iph); - - if ( !(viadev = dev_get_by_name(ipfwp->fwp_vianame)) ) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: invalid device \"%s\"\n", ipfwp->fwp_vianame); -#endif - return(EINVAL); - } else if ( ip->ihl != sizeof(struct iphdr) / sizeof(int)) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl, - sizeof(struct iphdr)/sizeof(int)); -#endif - dev_put(viadev); - return(EINVAL); - } - - /* Fix this one up by hand, who knows how many - * tools will break if we start to barf on this. - */ - if (ntohs(ip->tot_len) > hdrlen) - ip->tot_len = htons(hdrlen); - - if ((tmp_skb = alloc_skb(hdrlen, GFP_ATOMIC)) == NULL) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: tmp_skb alloc failure\n"); -#endif - dev_put(viadev); - return(EFAULT); - } - skb_reserve(tmp_skb, hdrlen); - skb_push(tmp_skb, hdrlen); - memcpy(tmp_skb->data, ip, hdrlen); - - ret = ip_fw_chk(&tmp_skb, viadev, NULL, *chains[fwtype], - *policies[fwtype], IP_FW_MODE_CHK); - - kfree_skb(tmp_skb); - dev_put(viadev); - - switch (ret) { - case FW_ACCEPT: - return(0); - case FW_REDIRECT: - return(ECONNABORTED); - case FW_MASQUERADE: - return(ECONNRESET); - case FW_REJECT: - return(ECONNREFUSED); - default: /* FW_BLOCK */ - return(ETIMEDOUT); - } - } - - if ( cmd == IP_FW_MASQ_TIMEOUTS ) - return ip_fw_masq_timeouts(m, len); - -/* - * Here we really working hard-adding new elements - * to blocking/forwarding chains or deleting 'em - */ - - if ( cmd == IP_FW_INSERT || cmd == IP_FW_APPEND || cmd == IP_FW_DELETE ) - { - struct ip_fw *frwl; - int fwtype; - - frwl=check_ipfw_struct(m,len); - if (frwl==NULL) - return (EINVAL); - fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT; - - switch (cmd) - { - case IP_FW_INSERT: - return(insert_in_chain(chains[fwtype],frwl,len)); - case IP_FW_APPEND: - return(append_to_chain(chains[fwtype],frwl,len)); - case IP_FW_DELETE: - return(del_from_chain(chains[fwtype],frwl)); - default: - /* - * Should be panic but... (Why are BSD people panic obsessed ??) - */ -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); - } - } - -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unknown request %d\n",stage); -#endif - return(ENOPROTOOPT); -} -#endif /* CONFIG_IP_FIREWALL */ - -#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) -static int ip_chain_procinfo(int stage, char *buffer, char **start, - off_t offset, int length) -{ - off_t pos=0, begin=0; - struct ip_fw *i; - int len, p; - int last_len = 0; - - - switch(stage) - { -#ifdef CONFIG_IP_FIREWALL - case IP_FW_IN: - i = ip_fw_in_chain; - len=sprintf(buffer, "IP firewall input rules, default %d\n", - ip_fw_in_policy); - break; - case IP_FW_OUT: - i = ip_fw_out_chain; - len=sprintf(buffer, "IP firewall output rules, default %d\n", - ip_fw_out_policy); - break; - case IP_FW_FWD: - i = ip_fw_fwd_chain; - len=sprintf(buffer, "IP firewall forward rules, default %d\n", - ip_fw_fwd_policy); - break; -#endif -#ifdef CONFIG_IP_ACCT - case IP_FW_ACCT: - i = ip_acct_chain; - len=sprintf(buffer,"IP accounting rules\n"); - break; -#endif - default: - /* this should never be reached, but safety first... */ - i = NULL; - len=0; - break; - } - - READ_LOCK(&ip_fw_lock); - - while(i!=NULL) - { - len+=sprintf(buffer+len,"%08X/%08X->%08X/%08X %.16s %08X %X ", - ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr), - ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr), - (i->fw_vianame)[0] ? i->fw_vianame : "-", - ntohl(i->fw_via.s_addr), i->fw_flg); - /* 10 is enough for a 32 bit box but the counters are 64bit on - the Alpha and Ultrapenguin */ - len+=sprintf(buffer+len,"%u %u %-20lu %-20lu", - i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt); - for (p = 0; p < IP_FW_MAX_PORTS; p++) - len+=sprintf(buffer+len, " %u", i->fw_pts[p]); - len+=sprintf(buffer+len, " A%02X X%02X", i->fw_tosand, i->fw_tosxor); - buffer[len++]='\n'; - buffer[len]='\0'; - pos=begin+len; - if(posoffset+length) - { - len = last_len; - break; - } - last_len = len; - i=i->fw_next; - } - READ_UNLOCK(&ip_fw_lock); - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - return len; -} -#endif - -#ifdef CONFIG_IP_ACCT -static int ip_acct_procinfo(char *buffer, char **start, off_t offset, - int length) -{ - return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length); -} -#endif - -#ifdef CONFIG_IP_FIREWALL -static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset, - int length) -{ - return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length); -} - -static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset, - int length) -{ - return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length); -} - -static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, - int length) -{ - return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length); -} -#endif - - -#ifdef CONFIG_IP_FIREWALL -/* - * Interface to the generic firewall chains. - */ - -int ipfw_input_check(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb) -{ - return ip_fw_chk(pskb, dev, arg, ip_fw_in_chain, ip_fw_in_policy, - IP_FW_MODE_FW); -} - -int ipfw_output_check(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb) -{ - return ip_fw_chk(pskb, dev, arg, ip_fw_out_chain, ip_fw_out_policy, - IP_FW_MODE_FW); -} - -int ipfw_forward_check(struct firewall_ops *this, int pf, - struct net_device *dev, void *arg, - struct sk_buff **pskb) -{ - return ip_fw_chk(pskb, dev, arg, ip_fw_fwd_chain, ip_fw_fwd_policy, - IP_FW_MODE_FW); -} - -#ifdef CONFIG_IP_ACCT -int ipfw_acct_in(struct firewall_ops *this, int pf, struct net_device *dev, - void *arg, struct sk_buff **pskb) -{ - return ip_fw_chk(pskb,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN); -} - -int ipfw_acct_out(struct firewall_ops *this, int pf, struct net_device *dev, - void *arg, struct sk_buff **pskb) -{ - return ip_fw_chk(pskb,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT); -} -#endif - -struct firewall_ops ipfw_ops = { - .fw_forward = ipfw_forward_check, - .fw_input = ipfw_input_check, - .fw_output = ipfw_output_check, -#ifdef CONFIG_IP_ACCT - .fw_acct_in = ipfw_acct_in, - .fw_acct_out = ipfw_acct_out, -#endif -}; - -#endif - -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) - -int ipfw_device_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct net_device *dev=ptr; - char *devname = dev->name; - struct ip_fw *fw; - int chn; - - WRITE_LOCK(&ip_fw_lock); - - if (event == NETDEV_UP) { - for (chn = 0; chn < IP_FW_CHAINS; chn++) - for (fw = *chains[chn]; fw; fw = fw->fw_next) - if ((fw->fw_vianame)[0] && !strncmp(devname, - fw->fw_vianame, IFNAMSIZ)) { - dev_hold(dev); - fw->fw_viadev = dev; - } - } else if (event == NETDEV_DOWN) { - for (chn = 0; chn < IP_FW_CHAINS; chn++) - for (fw = *chains[chn]; fw; fw = fw->fw_next) - /* we could compare just the pointers ... */ - if ((fw->fw_vianame)[0] && !strncmp(devname, - fw->fw_vianame, IFNAMSIZ)){ - if (fw->fw_viadev - && fw->fw_viadev != (struct net_device *)-1) - dev_put(fw->fw_viadev); - fw->fw_viadev = (struct net_device*)-1; - } - } - - WRITE_UNLOCK(&ip_fw_lock); - return NOTIFY_DONE; -} - -static struct notifier_block ipfw_dev_notifier = { - .notifier_call = ipfw_device_event, -}; - -#endif - -int ipfw_init_or_cleanup(int init) -{ - int ret = 0; - - if (!init) - goto cleanup; - - ret = register_firewall(PF_INET, &ipfw_ops); - if (ret < 0) - goto cleanup_nothing; - -#ifdef CONFIG_IP_ACCT - proc_net_create("ip_acct", S_IFREG | S_IRUGO | S_IWUSR, ip_acct_procinfo); -#endif - proc_net_create("ip_input", S_IFREG | S_IRUGO | S_IWUSR, ip_fw_in_procinfo); - proc_net_create("ip_output", S_IFREG | S_IRUGO | S_IWUSR, ip_fw_out_procinfo); - proc_net_create("ip_forward", S_IFREG | S_IRUGO | S_IWUSR, ip_fw_fwd_procinfo); - - /* Register for device up/down reports */ - register_netdevice_notifier(&ipfw_dev_notifier); - -#ifdef CONFIG_IP_FIREWALL_NETLINK - ipfwsk = netlink_kernel_create(NETLINK_FIREWALL, NULL); -#endif - return ret; - - cleanup: -#ifdef CONFIG_IP_FIREWALL_NETLINK - sock_release(ipfwsk->sk_socket); -#endif - unregister_netdevice_notifier(&ipfw_dev_notifier); - -#ifdef CONFIG_IP_ACCT - proc_net_remove("ip_acct"); -#endif - proc_net_remove("ip_input"); - proc_net_remove("ip_output"); - proc_net_remove("ip_forward"); - - free_fw_chain(chains[IP_FW_FWD]); - free_fw_chain(chains[IP_FW_IN]); - free_fw_chain(chains[IP_FW_OUT]); - free_fw_chain(chains[IP_FW_ACCT]); - - unregister_firewall(PF_INET, &ipfw_ops); - - cleanup_nothing: - return ret; -} diff -L net/ipv4/netfilter/ip_fw_compat.c -puN net/ipv4/netfilter/ip_fw_compat.c~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/net/ipv4/netfilter/ip_fw_compat.c +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,303 +0,0 @@ -/* Compatibility framework for ipchains and ipfwadm support; designed - to look as much like the 2.2 infrastructure as possible. */ - -/* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -struct notifier_block; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip_fw_compat.h" - -static struct firewall_ops *fwops; - -#ifdef CONFIG_IP_VS -/* From ip_vs_core.c */ -extern unsigned int -check_for_ip_vs_out(struct sk_buff **skb_p, int (*okfn)(struct sk_buff *)); -#endif - -/* 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; - - /* Assume worse case: any hook could change packet */ - (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; - if ((*pskb)->ip_summed == CHECKSUM_HW) - if (skb_checksum_help(*pskb, (out == NULL))) - return NF_DROP; - - switch (hooknum) { - case NF_IP_PRE_ROUTING: - if (fwops->fw_acct_in) - fwops->fw_acct_in(fwops, PF_INET, - (struct net_device *)in, - &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, - &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, - &redirpt, pskb); - break; - - case NF_IP_POST_ROUTING: - ret = fwops->fw_output(fwops, PF_INET, - (struct net_device *)out, - &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, - &redirpt, - pskb); - - /* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */ - if (ip_conntrack_confirm(*pskb) == NF_DROP) - ret = FW_BLOCK; - } - 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); - /* Handle ICMP errors from client here */ - if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP - && (*pskb)->nfct) - check_for_masq_error(pskb); - } - return NF_ACCEPT; - - case FW_MASQUERADE: - if (hooknum == NF_IP_FORWARD) { -#ifdef CONFIG_IP_VS - /* check if it is for ip_vs */ - if (check_for_ip_vs_out(pskb, okfn) == NF_STOLEN) - return NF_STOLEN; -#endif - 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; - } -} - -static unsigned int fw_confirm(unsigned int hooknum, - struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ip_conntrack_confirm(*pskb); -} - -extern int ip_fw_ctl(int optval, void *m, unsigned int len); - -static int sock_fn(struct sock *sk, int optval, void __user *user, unsigned int len) -{ - /* MAX of: - 2.2: sizeof(struct ip_fwtest) (~14x4 + 3x4 = 17x4) - 2.2: sizeof(struct ip_fwnew) (~1x4 + 15x4 + 3x4 + 3x4 = 22x4) - 2.0: sizeof(struct ip_fw) (~25x4) - - We can't include both 2.0 and 2.2 headers, they conflict. - Hence, 200 is a good number. --RR */ - char tmp_fw[200]; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (len > sizeof(tmp_fw) || len < 1) - return -EINVAL; - - if (copy_from_user(&tmp_fw, user, len)) - return -EFAULT; - - return -ip_fw_ctl(optval, &tmp_fw, len); -} - -static struct nf_hook_ops preroute_ops = { - .hook = fw_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_FILTER, -}; - -static struct nf_hook_ops postroute_ops = { - .hook = fw_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_FILTER, -}; - -static struct nf_hook_ops forward_ops = { - .hook = fw_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_FORWARD, - .priority = NF_IP_PRI_FILTER, -}; - -static struct nf_hook_ops local_in_ops = { - .hook = fw_confirm, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_LAST - 1, -}; - -static struct nf_sockopt_ops sock_ops = { - .pf = PF_INET, - .set_optmin = 64, - .set_optmax = 64 + 1024 + 1, - .set = &sock_fn, -}; - -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); - nf_register_hook(&local_in_ops); - - return ret; - - cleanup: - nf_unregister_hook(&preroute_ops); - nf_unregister_hook(&postroute_ops); - nf_unregister_hook(&forward_ops); - nf_unregister_hook(&local_in_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); diff -L net/ipv4/netfilter/ip_fw_compat.h -puN net/ipv4/netfilter/ip_fw_compat.h~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/net/ipv4/netfilter/ip_fw_compat.h +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,28 +0,0 @@ -#ifndef _LINUX_IP_FW_COMPAT_H -#define _LINUX_IP_FW_COMPAT_H - -/* 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 void check_for_masq_error(struct sk_buff **pskb); - -extern unsigned int -check_for_demasq(struct sk_buff **pskb); - -extern int __init masq_init(void); -extern void masq_cleanup(void); - -#endif /* _LINUX_IP_FW_COMPAT_H */ diff -L net/ipv4/netfilter/ip_fw_compat_masq.c -puN net/ipv4/netfilter/ip_fw_compat_masq.c~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/net/ipv4/netfilter/ip_fw_compat_masq.c +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,342 +0,0 @@ -/* Masquerading compatibility layer. - - Note that there are no restrictions on other programs binding to - ports 61000:65095 (in 2.0 and 2.2 they get EADDRINUSE). Just DON'T - DO IT. - */ - -/* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) - -#include -#include -#include -#include -#include -#include -#include "ip_fw_compat.h" - -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(format, args...) -#endif - -unsigned int -do_masquerade(struct sk_buff **pskb, const struct net_device *dev) -{ - struct ip_nat_info *info; - enum ip_conntrack_info ctinfo; - struct ip_conntrack *ct; - unsigned int ret; - - /* Sorry, only ICMP, TCP and UDP. */ - if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP - && (*pskb)->nh.iph->protocol != IPPROTO_TCP - && (*pskb)->nh.iph->protocol != IPPROTO_UDP) - return NF_DROP; - - /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD, - but connection tracking doesn't expect that */ - ret = ip_conntrack_in(NF_IP_POST_ROUTING, pskb, dev, NULL, NULL); - if (ret != NF_ACCEPT) { - DEBUGP("ip_conntrack_in returned %u.\n", ret); - return ret; - } - - ct = ip_conntrack_get(*pskb, &ctinfo); - - if (!ct) { - DEBUGP("ip_conntrack_in set to invalid conntrack.\n"); - return NF_DROP; - } - - info = &ct->nat.info; - - WRITE_LOCK(&ip_nat_lock); - /* Setup the masquerade, if not already */ - if (!info->initialized) { - u_int32_t newsrc; - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr } } }; - struct rtable *rt; - struct ip_nat_multi_range range; - - /* Pass 0 instead of saddr, since it's going to be changed - anyway. */ - if (ip_route_output_key(&rt, &fl) != 0) { - DEBUGP("ipnat_rule_masquerade: Can't reroute.\n"); - return NF_DROP; - } - newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, - RT_SCOPE_UNIVERSE); - ip_rt_put(rt); - range = ((struct ip_nat_multi_range) - { 1, - {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED, - newsrc, newsrc, - { htons(61000) }, { htons(65095) } } } }); - - ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); - if (ret != NF_ACCEPT) { - WRITE_UNLOCK(&ip_nat_lock); - return ret; - } - } else - DEBUGP("Masquerading already done on this conn.\n"); - WRITE_UNLOCK(&ip_nat_lock); - - return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb); -} - -void -check_for_masq_error(struct sk_buff **pskb) -{ - enum ip_conntrack_info ctinfo; - struct ip_conntrack *ct; - - ct = ip_conntrack_get(*pskb, &ctinfo); - /* Wouldn't be here if not tracked already => masq'ed ICMP - ping or error related to masq'd connection */ - IP_NF_ASSERT(ct); - if (ctinfo == IP_CT_RELATED) { - icmp_reply_translation(pskb, ct, NF_IP_PRE_ROUTING, - CTINFO2DIR(ctinfo)); - icmp_reply_translation(pskb, ct, NF_IP_POST_ROUTING, - CTINFO2DIR(ctinfo)); - } -} - -unsigned int -check_for_demasq(struct sk_buff **pskb) -{ - struct ip_conntrack_tuple tuple; - struct ip_conntrack_protocol *protocol; - struct ip_conntrack_tuple_hash *h; - enum ip_conntrack_info ctinfo; - struct ip_conntrack *ct; - int ret; - - protocol = ip_ct_find_proto((*pskb)->nh.iph->protocol); - - /* We don't feed packets to conntrack system unless we know - they're part of an connection already established by an - explicit masq command. */ - switch ((*pskb)->nh.iph->protocol) { - case IPPROTO_ICMP: - /* ICMP errors. */ - protocol->error(*pskb, &ctinfo, NF_IP_PRE_ROUTING); - ct = (struct ip_conntrack *)(*pskb)->nfct; - if (ct) { - /* We only do SNAT in the compatibility layer. - So we can manipulate ICMP errors from - server here (== DNAT). Do SNAT icmp manips - in POST_ROUTING handling. */ - if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { - icmp_reply_translation(pskb, ct, - NF_IP_PRE_ROUTING, - CTINFO2DIR(ctinfo)); - icmp_reply_translation(pskb, ct, - NF_IP_POST_ROUTING, - CTINFO2DIR(ctinfo)); - } - return NF_ACCEPT; - } - /* Fall thru... */ - case IPPROTO_TCP: - case IPPROTO_UDP: - IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0); - - if (!ip_ct_get_tuple((*pskb)->nh.iph, *pskb, - (*pskb)->nh.iph->ihl*4, &tuple, protocol)) { - if (net_ratelimit()) - printk("ip_fw_compat_masq: Can't get tuple\n"); - return NF_ACCEPT; - } - break; - - default: - /* Not ours... */ - return NF_ACCEPT; - } - h = ip_conntrack_find_get(&tuple, NULL); - - /* MUST be found, and MUST be reply. */ - if (h && DIRECTION(h) == 1) { - ret = ip_conntrack_in(NF_IP_PRE_ROUTING, pskb, - NULL, NULL, NULL); - - /* Put back the reference gained from find_get */ - nf_conntrack_put(&h->ctrack->ct_general); - if (ret == NF_ACCEPT) { - struct ip_conntrack *ct; - ct = ip_conntrack_get(*pskb, &ctinfo); - - if (ct) { - struct ip_nat_info *info = &ct->nat.info; - - do_bindings(ct, ctinfo, info, - NF_IP_PRE_ROUTING, - pskb); - } else - if (net_ratelimit()) - printk("ip_fw_compat_masq: conntrack" - " didn't like\n"); - } - } else { - if (h) - /* Put back the reference gained from find_get */ - nf_conntrack_put(&h->ctrack->ct_general); - ret = NF_ACCEPT; - } - - return ret; -} - -int ip_fw_masq_timeouts(void *user, int len) -{ - printk("Sorry: masquerading timeouts set 5DAYS/2MINS/60SECS\n"); - return 0; -} - -static const char *masq_proto_name(u_int16_t protonum) -{ - switch (protonum) { - case IPPROTO_TCP: return "TCP"; - case IPPROTO_UDP: return "UDP"; - case IPPROTO_ICMP: return "ICMP"; - default: return "MORE-CAFFEINE-FOR-RUSTY"; - } -} - -static unsigned int -print_masq(char *buffer, const struct ip_conntrack *conntrack) -{ - char temp[129]; - - /* This is for backwards compatibility, but ick!. - We should never export jiffies to userspace. - */ - sprintf(temp,"%s %08X:%04X %08X:%04X %04X %08X %6d %6d %7lu", - masq_proto_name(conntrack->tuplehash[0].tuple.dst.protonum), - ntohl(conntrack->tuplehash[0].tuple.src.ip), - ntohs(conntrack->tuplehash[0].tuple.src.u.all), - ntohl(conntrack->tuplehash[0].tuple.dst.ip), - ntohs(conntrack->tuplehash[0].tuple.dst.u.all), - ntohs(conntrack->tuplehash[1].tuple.dst.u.all), - /* Sorry, no init_seq, delta or previous_delta (yet). */ - 0, 0, 0, - conntrack->timeout.expires - jiffies); - - return sprintf(buffer, "%-127s\n", temp); -} - -/* Returns true when finished. */ -static int -masq_iterate(const struct ip_conntrack_tuple_hash *hash, - char *buffer, off_t offset, off_t *upto, - unsigned int *len, unsigned int maxlen) -{ - unsigned int newlen; - - IP_NF_ASSERT(hash->ctrack); - - /* Only count originals */ - if (DIRECTION(hash)) - return 0; - - if ((*upto)++ < offset) - return 0; - - newlen = print_masq(buffer + *len, hash->ctrack); - if (*len + newlen > maxlen) - return 1; - else *len += newlen; - - return 0; -} - -/* Everything in the hash is masqueraded. */ -static int -masq_procinfo(char *buffer, char **start, off_t offset, int length) -{ - unsigned int i; - int len = 0; - off_t upto = 1; - - /* Header: first record */ - if (offset == 0) { - char temp[128]; - - sprintf(temp, - "Prc FromIP FPrt ToIP TPrt Masq Init-seq Delta PDelta Expires (free=0,0,0)"); - len = sprintf(buffer, "%-127s\n", temp); - offset = 1; - } - - READ_LOCK(&ip_conntrack_lock); - /* Traverse hash; print originals then reply. */ - for (i = 0; i < ip_conntrack_htable_size; i++) { - if (LIST_FIND(&ip_conntrack_hash[i], masq_iterate, - struct ip_conntrack_tuple_hash *, - buffer, offset, &upto, &len, length)) - break; - } - READ_UNLOCK(&ip_conntrack_lock); - - /* `start' hack - see fs/proc/generic.c line ~165 */ - *start = (char *)((unsigned int)upto - offset); - return len; -} - -int __init masq_init(void) -{ - int ret; - struct proc_dir_entry *proc; - - ret = ip_conntrack_init(); - if (ret == 0) { - ret = ip_nat_init(); - if (ret == 0) { - proc = proc_net_create("ip_masquerade", - 0, masq_procinfo); - if (proc) - proc->owner = THIS_MODULE; - else { - ip_nat_cleanup(); - ip_conntrack_cleanup(); - ret = -ENOMEM; - } - } else - ip_conntrack_cleanup(); - } - - return ret; -} - -void masq_cleanup(void) -{ - ip_nat_cleanup(); - ip_conntrack_cleanup(); - proc_net_remove("ip_masquerade"); -} diff -L net/ipv4/netfilter/ip_fw_compat_redir.c -puN net/ipv4/netfilter/ip_fw_compat_redir.c~netfilter-remove-ipchains-and-ipfwadm-compatibility /dev/null --- 25/net/ipv4/netfilter/ip_fw_compat_redir.c +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,318 +0,0 @@ -/* This is a file to handle the "simple" NAT cases (redirect and - masquerade) required for the compatibility layer. - - `bind to foreign address' and `getpeername' hacks are not - supported. - - FIXME: Timing is overly simplistic. If anyone complains, make it - use conntrack. -*/ - -/* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Very simple timeout pushed back by each packet */ -#define REDIR_TIMEOUT (240*HZ) - -static DECLARE_LOCK(redir_lock); -#define ASSERT_READ_LOCK(x) MUST_BE_LOCKED(&redir_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock) - -#include -#include "ip_fw_compat.h" - -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(format, args...) -#endif - -#ifdef CONFIG_NETFILTER_DEBUG -#define IP_NF_ASSERT(x) \ -do { \ - if (!(x)) \ - /* Wooah! I'm tripping my conntrack in a frenzy of \ - netplay... */ \ - printk("ASSERT: %s:%i(%s)\n", \ - __FILE__, __LINE__, __FUNCTION__); \ -} while(0) -#else -#define IP_NF_ASSERT(x) -#endif - -static u_int16_t -cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) -{ - u_int32_t diffs[] = { oldvalinv, newval }; - return csum_fold(csum_partial((char *)diffs, sizeof(diffs), - oldcheck^0xFFFF)); -} - -struct redir_core { - u_int32_t orig_srcip, orig_dstip; - u_int16_t orig_sport, orig_dport; - - u_int32_t new_dstip; - u_int16_t new_dport; -}; - -struct redir -{ - struct list_head list; - struct redir_core core; - struct timer_list destroyme; -}; - -static LIST_HEAD(redirs); - -static int -redir_cmp(const struct redir *i, - u_int32_t orig_srcip, u_int32_t orig_dstip, - u_int16_t orig_sport, u_int16_t orig_dport) -{ - return (i->core.orig_srcip == orig_srcip - && i->core.orig_dstip == orig_dstip - && i->core.orig_sport == orig_sport - && i->core.orig_dport == orig_dport); -} - -/* Search for an existing redirection of the TCP packet. */ -static struct redir * -find_redir(u_int32_t orig_srcip, u_int32_t orig_dstip, - u_int16_t orig_sport, u_int16_t orig_dport) -{ - return LIST_FIND(&redirs, redir_cmp, struct redir *, - orig_srcip, orig_dstip, orig_sport, orig_dport); -} - -static void do_tcp_redir(struct sk_buff *skb, struct redir *redir) -{ - struct iphdr *iph = skb->nh.iph; - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph - + iph->ihl); - - tcph->check = cheat_check(~redir->core.orig_dstip, - redir->core.new_dstip, - cheat_check(redir->core.orig_dport ^ 0xFFFF, - redir->core.new_dport, - tcph->check)); - iph->check = cheat_check(~redir->core.orig_dstip, - redir->core.new_dstip, iph->check); - tcph->dest = redir->core.new_dport; - iph->daddr = redir->core.new_dstip; - - skb->nfcache |= NFC_ALTERED; -} - -static int -unredir_cmp(const struct redir *i, - u_int32_t new_dstip, u_int32_t orig_srcip, - u_int16_t new_dport, u_int16_t orig_sport) -{ - return (i->core.orig_srcip == orig_srcip - && i->core.new_dstip == new_dstip - && i->core.orig_sport == orig_sport - && i->core.new_dport == new_dport); -} - -/* Match reply packet against redir */ -static struct redir * -find_unredir(u_int32_t new_dstip, u_int32_t orig_srcip, - u_int16_t new_dport, u_int16_t orig_sport) -{ - return LIST_FIND(&redirs, unredir_cmp, struct redir *, - new_dstip, orig_srcip, new_dport, orig_sport); -} - -/* `unredir' a reply packet. */ -static void do_tcp_unredir(struct sk_buff *skb, struct redir *redir) -{ - struct iphdr *iph = skb->nh.iph; - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph - + iph->ihl); - - tcph->check = cheat_check(~redir->core.new_dstip, - redir->core.orig_dstip, - cheat_check(redir->core.new_dport ^ 0xFFFF, - redir->core.orig_dport, - tcph->check)); - iph->check = cheat_check(~redir->core.new_dstip, - redir->core.orig_dstip, - iph->check); - tcph->source = redir->core.orig_dport; - iph->saddr = redir->core.orig_dstip; - - skb->nfcache |= NFC_ALTERED; -} - -static void destroyme(unsigned long me) -{ - LOCK_BH(&redir_lock); - LIST_DELETE(&redirs, (struct redir *)me); - UNLOCK_BH(&redir_lock); - kfree((struct redir *)me); -} - -/* REDIRECT a packet. */ -unsigned int -do_redirect(struct sk_buff *skb, - const struct net_device *dev, - u_int16_t redirpt) -{ - struct iphdr *iph = skb->nh.iph; - u_int32_t newdst; - - /* Figure out address: not loopback. */ - if (!dev) - return NF_DROP; - - /* Grab first address on interface. */ - newdst = ((struct in_device *)dev->ip_ptr)->ifa_list->ifa_local; - - switch (iph->protocol) { - case IPPROTO_UDP: { - /* Simple mangle. */ - struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph - + iph->ihl); - - /* Must have whole header */ - if (skb->len < iph->ihl*4 + sizeof(*udph)) - return NF_DROP; - - if (udph->check) /* 0 is a special case meaning no checksum */ - udph->check = cheat_check(~iph->daddr, newdst, - cheat_check(udph->dest ^ 0xFFFF, - redirpt, - udph->check)); - iph->check = cheat_check(~iph->daddr, newdst, iph->check); - udph->dest = redirpt; - iph->daddr = newdst; - - skb->nfcache |= NFC_ALTERED; - return NF_ACCEPT; - } - case IPPROTO_TCP: { - /* Mangle, maybe record. */ - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph - + iph->ihl); - struct redir *redir; - int ret; - - /* Must have whole header */ - if (skb->len < iph->ihl*4 + sizeof(*tcph)) - return NF_DROP; - - DEBUGP("Doing tcp redirect. %08X:%u %08X:%u -> %08X:%u\n", - iph->saddr, tcph->source, iph->daddr, tcph->dest, - newdst, redirpt); - LOCK_BH(&redir_lock); - redir = find_redir(iph->saddr, iph->daddr, - tcph->source, tcph->dest); - - if (!redir) { - redir = kmalloc(sizeof(struct redir), GFP_ATOMIC); - if (!redir) { - ret = NF_DROP; - goto out; - } - list_prepend(&redirs, redir); - init_timer(&redir->destroyme); - redir->destroyme.function = destroyme; - redir->destroyme.data = (unsigned long)redir; - redir->destroyme.expires = jiffies + REDIR_TIMEOUT; - add_timer(&redir->destroyme); - } - /* In case mangling has changed, rewrite this part. */ - redir->core = ((struct redir_core) - { iph->saddr, iph->daddr, - tcph->source, tcph->dest, - newdst, redirpt }); - do_tcp_redir(skb, redir); - ret = NF_ACCEPT; - - out: - UNLOCK_BH(&redir_lock); - return ret; - } - - default: /* give up if not TCP or UDP. */ - return NF_DROP; - } -} - -/* Incoming packet: is it a reply to a masqueraded connection, or - part of an already-redirected TCP connection? */ -void -check_for_redirect(struct sk_buff *skb) -{ - struct iphdr *iph = skb->nh.iph; - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph - + iph->ihl); - struct redir *redir; - - if (iph->protocol != IPPROTO_TCP) - return; - - /* Must have whole header */ - if (skb->len < iph->ihl*4 + sizeof(*tcph)) - return; - - LOCK_BH(&redir_lock); - redir = find_redir(iph->saddr, iph->daddr, tcph->source, tcph->dest); - if (redir) { - DEBUGP("Doing tcp redirect again.\n"); - do_tcp_redir(skb, redir); - if (del_timer(&redir->destroyme)) { - redir->destroyme.expires = jiffies + REDIR_TIMEOUT; - add_timer(&redir->destroyme); - } - } - UNLOCK_BH(&redir_lock); -} - -void -check_for_unredirect(struct sk_buff *skb) -{ - struct iphdr *iph = skb->nh.iph; - struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph - + iph->ihl); - struct redir *redir; - - if (iph->protocol != IPPROTO_TCP) - return; - - /* Must have whole header */ - if (skb->len < iph->ihl*4 + sizeof(*tcph)) - return; - - LOCK_BH(&redir_lock); - redir = find_unredir(iph->saddr, iph->daddr, tcph->source, tcph->dest); - if (redir) { - DEBUGP("Doing tcp unredirect.\n"); - do_tcp_unredir(skb, redir); - if (del_timer(&redir->destroyme)) { - redir->destroyme.expires = jiffies + REDIR_TIMEOUT; - add_timer(&redir->destroyme); - } - } - UNLOCK_BH(&redir_lock); -} diff -puN net/ipv4/netfilter/Kconfig~netfilter-remove-ipchains-and-ipfwadm-compatibility net/ipv4/netfilter/Kconfig --- 25/net/ipv4/netfilter/Kconfig~netfilter-remove-ipchains-and-ipfwadm-compatibility 2004-12-31 03:56:31.889691024 -0800 +++ 25-akpm/net/ipv4/netfilter/Kconfig 2004-12-31 03:56:31.916686920 -0800 @@ -458,7 +458,7 @@ config IP_NF_NAT config IP_NF_NAT_NEEDED bool - depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y && (IP_NF_COMPAT_IPCHAINS!=y && IP_NF_COMPAT_IPFWADM || IP_NF_COMPAT_IPCHAINS) || IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT + depends on IP_NF_NAT != n default y config IP_NF_TARGET_MASQUERADE @@ -693,30 +693,5 @@ config IP_NF_ARP_MANGLE Allows altering the ARP packet payload: source and destination hardware and network addresses. -# Backwards compatibility modules: only if you don't build in the others. -config IP_NF_COMPAT_IPCHAINS - tristate "ipchains (2.2-style) support" - depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y - help - This option places ipchains (with masquerading and redirection - support) back into the kernel, using the new netfilter - infrastructure. It is not recommended for new installations (see - `Packet filtering'). With this enabled, you should be able to use - the ipchains tool exactly as in 2.2 kernels. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_COMPAT_IPFWADM - tristate "ipfwadm (2.0-style) support" - depends on IP_NF_CONNTRACK!=y && IP_NF_IPTABLES!=y && IP_NF_COMPAT_IPCHAINS!=y - help - This option places ipfwadm (with masquerading and redirection - support) back into the kernel, using the new netfilter - infrastructure. It is not recommended for new installations (see - `Packet filtering'). With this enabled, you should be able to use - the ipfwadm tool exactly as in 2.0 kernels. - - To compile it as a module, choose M here. If unsure, say N. - endmenu diff -puN net/ipv4/netfilter/Makefile~netfilter-remove-ipchains-and-ipfwadm-compatibility net/ipv4/netfilter/Makefile --- 25/net/ipv4/netfilter/Makefile~netfilter-remove-ipchains-and-ipfwadm-compatibility 2004-12-31 03:56:31.891690720 -0800 +++ 25-akpm/net/ipv4/netfilter/Makefile 2004-12-31 03:56:31.906688440 -0800 @@ -2,19 +2,9 @@ # Makefile for the netfilter modules on top of IPv4. # -# objects for the conntrack and NAT core (used by standalone and backw. compat) -ip_nf_conntrack-objs := ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o -ip_nf_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o - # objects for the standalone - connection tracking / NAT -ip_conntrack-objs := ip_conntrack_standalone.o $(ip_nf_conntrack-objs) -iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs) - -# objects for backwards compatibility mode -ip_nf_compat-objs := ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs) - -ipfwadm-objs := $(ip_nf_compat-objs) ipfwadm_core.o -ipchains-objs := $(ip_nf_compat-objs) ipchains_core.o +ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o +iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o @@ -96,8 +86,4 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_m # just filtering instance of ARP tables for now obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o -# backwards compatibility -obj-$(CONFIG_IP_NF_COMPAT_IPCHAINS) += ipchains.o -obj-$(CONFIG_IP_NF_COMPAT_IPFWADM) += ipfwadm.o - obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o _