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

📄 ip_fw.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		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;#ifdef CONFIG_IP_TRANSPARENT_PROXY	} else if (strcmp(label,IP_FW_LABEL_REDIRECT) == 0) {                extern int sysctl_ip_always_defrag;                static int enabled = 0;                if(!enabled)                {                	enabled=1;                        sysctl_ip_always_defrag++;                }		*answer = FW_REDIRECT;		return 1;#endif#ifdef CONFIG_IP_MASQUERADE	} else if (strcmp(label,IP_FW_LABEL_MASQUERADE) == 0) {		*answer = FW_MASQUERADE;		return 1;#endif	} 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 intip_fw_domatch(struct ip_fwkernel *f,	      struct iphdr *ip, 	      const char *rif,	      const ip_chainlabel label,	      struct sk_buff *skb,	      unsigned int slot,	      __u16 src_port, __u16 dst_port, 	      unsigned int count,	      int tcpsyn){	f->counters[slot].bcnt+=ntohs(ip->tot_len);	f->counters[slot].pcnt++;	if (f->ipfw.fw_flg & IP_FW_F_PRN) {		dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn);	}	ip->tos = (ip->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)		skb->fwmark = f->ipfw.fw_mark;	else		skb->fwmark+=f->ipfw.fw_mark;#ifdef CONFIG_IP_FIREWALL_NETLINK	if (f->ipfw.fw_flg & IP_FW_F_NETLINK) {		size_t len = min(f->ipfw.fw_outputsize, ntohs(ip->tot_len)) 			+ sizeof(__u32) + sizeof(skb->fwmark) + 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))) = skb->fwmark;			strcpy(outskb->data+sizeof(__u32)*2, rif);			memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip, 			       len-(sizeof(__u32)*2+IFNAMSIZ));			netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL);		}		else {			if (net_ratelimit())				printk(KERN_WARNING "ip_fw: packet drop due to "				       "netlink failure\n");			return 0;		}	}#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(struct iphdr *ip, 	    const char *rif,	    __u16 *redirport,	    struct ip_chain *chain,	    struct sk_buff *skb,	    unsigned int slot,	    int testing){	struct tcphdr		*tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);	struct udphdr		*udp=(struct udphdr *)((__u32 *)ip+ip->ihl);	struct icmphdr		*icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);	__u32			src, dst;	__u16			src_port = 0xFFFF, dst_port = 0xFFFF;	char			tcpsyn=0;	__u16			offset;	unsigned char		oldtos;	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(ip->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 && ip->protocol == IPPROTO_TCP)	{		if (!testing && net_ratelimit()) {			printk("Suspect TCP fragment.\n");			dump_packet(ip,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 (ip->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;		}		offset = (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req);		/* If it is a truncated first fragment then it can be		 * used to rewrite port information, and thus should		 * be blocked.		 */		if (offset && (ntohs(ip->frag_off) & IP_MF)) {			if (!testing && net_ratelimit()) {				printk("Suspect short first fragment.\n");				dump_packet(ip,rif,NULL,NULL,0,0,0,0);			}			return FW_BLOCK;		}	}	src = ip->saddr;	dst = ip->daddr;	oldtos = ip->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(ip->protocol) 	{		case IPPROTO_TCP:			dprintf("TCP ");			if (!offset) {				src_port=ntohs(tcp->source);				dst_port=ntohs(tcp->dest);				/* Connection initilisation can only				 * be made when the syn bit is set and				 * neither of the ack or reset is				 * set. */				if(tcp->syn && !(tcp->ack || tcp->rst))					tcpsyn=1;			}			break;		case IPPROTO_UDP:			dprintf("UDP ");			if (!offset) {				src_port=ntohs(udp->source);				dst_port=ntohs(udp->dest);			}			break;		case IPPROTO_ICMP:			if (!offset) {				src_port=(__u16)icmp->type;				dst_port=(__u16)icmp->code;			}			dprintf("ICMP ");			break;		default:			dprintf("p=%d ",ip->protocol);			break;	}#ifdef DEBUG_IP_FIREWALL	print_ip(ip->saddr);		if (offset) 		dprintf(":fragment (%i) ", ((int)offset)<<2);	else if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP 		 || ip->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;	count = 0;	do {		for (; f; f = f->next) {			count++;			if (ip_rule_match(f,rif,ip,					  tcpsyn,src_port,dst_port,offset)) {				if (!testing				    && !ip_fw_domatch(f, ip, rif, chain->label,						      skb, slot, 						      src_port, dst_port,						      count, tcpsyn)) {					ret = FW_BLOCK;					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].count = count;					f->branch->reent[slot].prevrule 						= f->next;					chain = f->branch;					f = chain->chain;					count = 0;				}			}			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;				count = chain->reent[slot].count;				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(ip->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 (ip->tos != oldtos 	    && ret != FW_REJECT && ret != FW_BLOCK 	    && !testing)		ip_send_check(ip);#ifdef CONFIG_IP_TRANSPARENT_PROXY	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);		}	}#endif#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;	}	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++;

⌨️ 快捷键说明

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