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

📄 ip_fw.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1996 Alex Nash * 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. * *	$Id: ip_fw.c,v 1.2 2003/01/03 18:09:25 joel Exp $ *//* * Implement IP packet firewall */#ifndef IPFIREWALL_MODULE#include "opt_ipfw.h"#endif#include <sys/param.h>#include <sys/systm.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/queue.h>#include <sys/kernel.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/sysctl.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_var.h>#include <netinet/ip_icmp.h>#include <netinet/ip_fw.h>#include <netinet/tcp.h>#include <netinet/tcp_timer.h>#include <netinet/tcp_var.h>#include <netinet/tcpip.h>#include <netinet/udp.h>static int fw_debug = 1;#ifdef IPFIREWALL_VERBOSEstatic int fw_verbose = 1;#elsestatic int fw_verbose = 0;#endif#ifdef IPFIREWALL_VERBOSE_LIMITstatic int fw_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;#elsestatic int fw_verbose_limit = 0;#endifLIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;/* * ccj - No current need for firewall so have provided the MIB. */#if 0#ifdef SYSCTL_NODESYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall");SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, debug, CTLFLAG_RW, &fw_debug, 0, "");SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, CTLFLAG_RW, &fw_verbose, 0, "");SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "");#endif#endif#define dprintf(a)	if (!fw_debug); else printf a#define print_ip(a)	 printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\				 		  (ntohl(a.s_addr)>>16)&0xFF,\						  (ntohl(a.s_addr)>>8)&0xFF,\						  (ntohl(a.s_addr))&0xFF);#define dprint_ip(a)	if (!fw_debug); else print_ip(a)static int	add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));static int	del_entry __P((struct ip_fw_head *chainptr, u_short number));static int	zero_entry __P((struct mbuf *m));static struct ip_fw *check_ipfw_struct __P((struct ip_fw *m));static struct ip_fw *check_ipfw_mbuf __P((struct mbuf *fw));static int	ipopts_match __P((struct ip *ip, struct ip_fw *f));static int	port_match __P((u_short *portptr, int nports, u_short port,				int range_flag));static int	tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));static int	icmptype_match __P((struct icmp *  icmp, struct ip_fw * f));static void	ipfw_report __P((struct ip_fw *f, struct ip *ip,				struct ifnet *rif, struct ifnet *oif));#ifdef IPFIREWALL_MODULEstatic ip_fw_chk_t *old_chk_ptr;static ip_fw_ctl_t *old_ctl_ptr;#endifstatic int	ip_fw_chk __P((struct ip **pip, int hlen,			struct ifnet *oif, int ignport, struct mbuf **m));static int	ip_fw_ctl __P((int stage, struct mbuf **mm));static char err_prefix[] = "ip_fw_ctl:";/* * Returns 1 if the port is matched by the vector, 0 otherwise */static inline int port_match(u_short *portptr, int nports, u_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;}static inttcpflg_match(struct tcphdr *tcp, struct ip_fw *f){	u_char		flg_set, flg_clr;		if ((f->fw_tcpf & IP_FW_TCPF_ESTAB) &&	    (tcp->th_flags & (IP_FW_TCPF_RST | IP_FW_TCPF_ACK)))		return 1;	flg_set = tcp->th_flags & f->fw_tcpf;	flg_clr = tcp->th_flags & f->fw_tcpnf;	if (flg_set != f->fw_tcpf)		return 0;	if (flg_clr)		return 0;	return 1;}static inticmptype_match(struct icmp *icmp, struct ip_fw *f){	int type;	if (!(f->fw_flg & IP_FW_F_ICMPBIT))		return(1);	type = icmp->icmp_type;	/* check for matching type in the bitmap */	if (type < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8 &&		(f->fw_icmptypes[type / (sizeof(unsigned) * 8)] & 		(1U << (type % (8 * sizeof(unsigned))))))		return(1);	return(0); /* no match */}static intipopts_match(struct ip *ip, struct ip_fw *f){	register u_char *cp;	int opt, optlen, cnt;	u_char	opts, nopts, nopts_sve;	cp = (u_char *)(ip + 1);	cnt = (ip->ip_hl << 2) - sizeof (struct ip);	opts = f->fw_ipopt;	nopts = nopts_sve = f->fw_ipnopt;	for (; cnt > 0; cnt -= optlen, cp += optlen) {		opt = cp[IPOPT_OPTVAL];		if (opt == IPOPT_EOL)			break;		if (opt == IPOPT_NOP)			optlen = 1;		else {			optlen = cp[IPOPT_OLEN];			if (optlen <= 0 || optlen > cnt) {				return 0; /*XXX*/			}		}		switch (opt) {		default:			break;		case IPOPT_LSRR:			opts &= ~IP_FW_IPOPT_LSRR;			nopts &= ~IP_FW_IPOPT_LSRR;			break;		case IPOPT_SSRR:			opts &= ~IP_FW_IPOPT_SSRR;			nopts &= ~IP_FW_IPOPT_SSRR;			break;		case IPOPT_RR:			opts &= ~IP_FW_IPOPT_RR;			nopts &= ~IP_FW_IPOPT_RR;			break;		case IPOPT_TS:			opts &= ~IP_FW_IPOPT_TS;			nopts &= ~IP_FW_IPOPT_TS;			break;		}		if (opts == nopts)			break;	}	if (opts == 0 && nopts == nopts_sve)		return 1;	else		return 0;}static inline intiface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname){	/* Check by name or by IP address */	if (byname) {		/* Check unit number (-1 is wildcard) */		if (ifu->fu_via_if.unit != -1		    && ifp->if_unit != ifu->fu_via_if.unit)			return(0);		/* Check name */		if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN))			return(0);		return(1);	} else if (ifu->fu_via_ip.s_addr != 0) {	/* Zero == wildcard */		struct ifaddr *ia;		for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {			if (ia->ifa_addr == NULL)				continue;			if (ia->ifa_addr->sa_family != AF_INET)				continue;			if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *)			    (ia->ifa_addr))->sin_addr.s_addr)				continue;			return(1);		}		return(0);	}	return(1);}static voidipfw_report(struct ip_fw *f, struct ip *ip,	struct ifnet *rif, struct ifnet *oif){	static int counter;	struct tcphdr *const tcp = (struct tcphdr *) ((u_long *) ip+ ip->ip_hl);	struct udphdr *const udp = (struct udphdr *) ((u_long *) ip+ ip->ip_hl);	struct icmp *const icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl);	int count;	count = f ? f->fw_pcnt : ++counter;	if (fw_verbose_limit != 0 && count > fw_verbose_limit)		return;	/* Print command name */	printf("ipfw: %d ", f ? f->fw_number : -1);	if (!f)		printf("Refuse");	else		switch (f->fw_flg & IP_FW_F_COMMAND) {		case IP_FW_F_DENY:			printf("Deny");			break;		case IP_FW_F_REJECT:			if (f->fw_reject_code == IP_FW_REJECT_RST)				printf("Reset");			else				printf("Unreach");			break;		case IP_FW_F_ACCEPT:			printf("Accept");			break;		case IP_FW_F_COUNT:			printf("Count");			break;		case IP_FW_F_DIVERT:			printf("Divert %d", f->fw_divert_port);			break;		case IP_FW_F_TEE:			printf("Tee %d", f->fw_divert_port);			break;		case IP_FW_F_SKIPTO:			printf("SkipTo %d", f->fw_skipto_rule);			break;		default:				printf("UNKNOWN");			break;		}	printf(" ");	switch (ip->ip_p) {	case IPPROTO_TCP:		printf("TCP ");		print_ip(ip->ip_src);		if ((ip->ip_off & IP_OFFMASK) == 0)			printf(":%d ", ntohs(tcp->th_sport));		else			printf(" ");		print_ip(ip->ip_dst);		if ((ip->ip_off & IP_OFFMASK) == 0)			printf(":%d", ntohs(tcp->th_dport));		break;	case IPPROTO_UDP:		printf("UDP ");		print_ip(ip->ip_src);		if ((ip->ip_off & IP_OFFMASK) == 0)			printf(":%d ", ntohs(udp->uh_sport));		else			printf(" ");		print_ip(ip->ip_dst);		if ((ip->ip_off & IP_OFFMASK) == 0)			printf(":%d", ntohs(udp->uh_dport));		break;	case IPPROTO_ICMP:		printf("ICMP:%u.%u ", icmp->icmp_type, icmp->icmp_code);		print_ip(ip->ip_src);		printf(" ");		print_ip(ip->ip_dst);		break;	default:		printf("P:%d ", ip->ip_p);		print_ip(ip->ip_src);		printf(" ");		print_ip(ip->ip_dst);		break;	}	if (oif)		printf(" out via %s%d", oif->if_name, oif->if_unit);	else if (rif)		printf(" in via %s%d", rif->if_name, rif->if_unit);	if ((ip->ip_off & IP_OFFMASK)) 		printf(" Fragment = %d",ip->ip_off & IP_OFFMASK);	printf("\n");	if (fw_verbose_limit != 0 && count == fw_verbose_limit)		printf("ipfw: limit reached on rule #%d\n",		f ? f->fw_number : -1);}/* * Parameters: * *	ip	Pointer to packet header (struct ip *) *	hlen	Packet header length *	oif	Outgoing interface, or NULL if packet is incoming *	ignport	Ignore all divert/tee rules to this port (if non-zero) *	*m	The packet; we set to NULL when/if we nuke it. * * Return value: * *	0	The packet is to be accepted and routed normally OR *      	the packet was denied/rejected and has been dropped; *		in the latter case, *m is equal to NULL upon return. *	port	Divert the packet to port. */static int ip_fw_chk(struct ip **pip, int hlen,	struct ifnet *oif, int ignport, struct mbuf **m){	struct ip_fw_chain *chain;	struct ip_fw *rule = NULL;	struct ip *ip = *pip;	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;	u_short offset = (ip->ip_off & IP_OFFMASK);	u_short src_port, dst_port;	/*	 * Go down the chain, looking for enlightment	 */	for (chain=ip_fw_chain.lh_first; chain; chain = chain->chain.le_next) {		register struct ip_fw *const f = chain->rule;		/* Check direction inbound */		if (!oif && !(f->fw_flg & IP_FW_F_IN))			continue;		/* Check direction outbound */		if (oif && !(f->fw_flg & IP_FW_F_OUT))			continue;		/* Fragments */		if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK))			continue;		/* If src-addr doesn't match, not this rule. */		if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr		    & f->fw_smsk.s_addr) != f->fw_src.s_addr))			continue;		/* If dest-addr doesn't match, not this rule. */		if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr		    & f->fw_dmsk.s_addr) != f->fw_dst.s_addr))			continue;		/* Interface check */		if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {			struct ifnet *const iface = oif ? oif : rif;			/* Backwards compatibility hack for "via" */			if (!iface || !iface_match(iface,			    &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))				continue;		} else {			/* Check receive interface */			if ((f->fw_flg & IP_FW_F_IIFACE)			    && (!rif || !iface_match(rif,			      &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))				continue;			/* Check outgoing interface */			if ((f->fw_flg & IP_FW_F_OIFACE)			    && (!oif || !iface_match(oif,			      &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))				continue;		}		/* Check IP options */		if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))			continue;		/* Check protocol; if wildcard, match */		if (f->fw_prot == IPPROTO_IP)			goto got_match;		/* If different, don't match */		if (ip->ip_p != f->fw_prot) 			continue;#define PULLUP_TO(len)	do {						\			    if ((*m)->m_len < (len)			\				&& (*m = m_pullup(*m, (len))) == 0) {	\				    goto bogusfrag;			\			    }						\			    *pip = ip = mtod(*m, struct ip *);		\			    offset = (ip->ip_off & IP_OFFMASK);		\			} while (0)		/* Protocol specific checks */		switch (ip->ip_p) {		case IPPROTO_TCP:		    {			struct tcphdr *tcp;			if (offset == 1)	/* cf. RFC 1858 */				goto bogusfrag;			if (offset != 0) {				/*				 * TCP flags and ports aren't available in this				 * packet -- if this rule specified either one,				 * we consider the rule a non-match.				 */				if (f->fw_nports != 0 ||				    f->fw_tcpf != f->fw_tcpnf)					continue;				break;			}			PULLUP_TO(hlen + 14);			tcp = (struct tcphdr *) ((u_long *)ip + ip->ip_hl);			if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))				continue;			src_port = ntohs(tcp->th_sport);			dst_port = ntohs(tcp->th_dport);			goto check_ports;		    }		case IPPROTO_UDP:		    {			struct udphdr *udp;			if (offset != 0) {				/*				 * Port specification is unavailable -- if this				 * rule specifies a port, we consider the rule				 * a non-match.				 */				if (f->fw_nports != 0)					continue;				break;			}			PULLUP_TO(hlen + 4);			udp = (struct udphdr *) ((u_long *)ip + ip->ip_hl);			src_port = ntohs(udp->uh_sport);			dst_port = ntohs(udp->uh_dport);check_ports:			if (!port_match(&f->fw_pts[0],			    IP_FW_GETNSRCP(f), src_port,			    f->fw_flg & IP_FW_F_SRNG))				continue;			if (!port_match(&f->fw_pts[IP_FW_GETNSRCP(f)],			    IP_FW_GETNDSTP(f), dst_port,			    f->fw_flg & IP_FW_F_DRNG)) 				continue;			break;		    }		case IPPROTO_ICMP:		    {			struct icmp *icmp;			if (offset != 0)	/* Type isn't valid */				break;			PULLUP_TO(hlen + 2);			icmp = (struct icmp *) ((u_long *)ip + ip->ip_hl);			if (!icmptype_match(icmp, f))				continue;			break;		    }#undef PULLUP_TObogusfrag:			if (fw_verbose)				ipfw_report(NULL, ip, rif, oif);			goto dropit;		}got_match:		/* Ignore divert/tee rule if socket port is "ignport" */		switch (f->fw_flg & IP_FW_F_COMMAND) {		case IP_FW_F_DIVERT:		case IP_FW_F_TEE:

⌨️ 快捷键说明

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