⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipchains_core.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* 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 <Paul.Russell@rustcorp.com.au> and *		Michael Neuling <Michael.Neuling@rustcorp.com.au> * 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 <Paul.Russell@rustcorp.com.au> * 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 <Paul.Russell@rustcorp.com.au> * 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 <ultima@snicker.emoti.com> * 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 <jm@dataprotect.com> *              Thomas Lopatic <tl@dataprotect.com> *//* * * 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 <linux/config.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/icmp.h>#include <linux/udp.h>#include <net/ip.h>#include <net/protocol.h>#include <net/route.h>#include <net/tcp.h>#include <net/udp.h>#include <net/sock.h>#include <net/icmp.h>#include <linux/netlink.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4/compat_firewall.h>#include <linux/netfilter_ipv4/ipchains_core.h>#include <net/checksum.h>#include <linux/proc_fs.h>#include <linux/stat.h>/* 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 * [cpu_number_map[smp_processor_id()]*2 + !in_interrupt()]; the array is of * size [smp_num_cpus*2].  For v2.0, smp_num_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() (cpu_number_map(smp_processor_id())*2 + !in_interrupt())#else /* !SMP */#define SLOT_NUMBER() (!in_interrupt())#endif /* CONFIG_SMP */#define NUM_SLOTS (smp_num_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_LOCKINGstatic 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 iphdr *ip,			 char tcpsyn,			 __u16 src_port, __u16 dst_port,			 char isfrag){#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(const struct iphdr *ip,			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 *) (ip + 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, ip->protocol, NIPQUAD(ip->saddr),	       src_port, NIPQUAD(ip->daddr),	       dst_port,	       ntohs(ip->tot_len), ip->tos, ntohs(ip->id),	       ntohs(ip->frag_off), ip->ttl);	for (opti = 0; opti < (ip->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;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -