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

📄 ip_fw.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;	u_short offset = 0 ;	u_short src_port, dst_port;	u_int16_t skipto = *cookie;	if (pip) { /* normal ip packet */	    ip = *pip;	    offset = (ip->ip_off & IP_OFFMASK);	} else { /* bridged or non-ip packet */	    struct ether_header *eh = mtod(*m, struct ether_header *);	    switch (ntohs(eh->ether_type)) {	    case ETHERTYPE_IP :		if ((*m)->m_len<sizeof(struct ether_header) + sizeof(struct ip))		    goto non_ip ;		ip = (struct ip *)(eh + 1 );		if (ip->ip_v != IPVERSION)		    goto non_ip ;		hlen = ip->ip_hl << 2;		if (hlen < sizeof(struct ip)) /* minimum header length */		    goto non_ip ;		if ((*m)->m_len < 14 + hlen + 14) {		    printf("-- m_len %d, need more...\n", (*m)->m_len);		    goto non_ip ;		}		offset = (ip->ip_off & IP_OFFMASK);		break ;	    default :non_ip:         ip = NULL ;		break ;	    }	}	if (*flow_id) {	    if (fw_one_pass)		return 0 ; /* accept if passed first test */	    /*	     * pkt has already been tagged. Look for the next rule	     * to restart processing	     */	    chain = LIST_NEXT( *flow_id, chain);	    if ( (chain = (*flow_id)->rule->next_rule_ptr) == NULL )		chain = (*flow_id)->rule->next_rule_ptr =			lookup_next_rule(*flow_id) ;		if (! chain) goto dropit;	} else {	/*	 * Go down the chain, looking for enlightment	 * If we've been asked to start at a given rule immediatly, do so.	 */	chain = LIST_FIRST(&ip_fw_chain);	if ( skipto ) {		if (skipto >= IPFW_DEFAULT_RULE)			goto dropit;		while (chain && (chain->rule->fw_number <= skipto)) {			chain = LIST_NEXT(chain, chain);		}		if (! chain) goto dropit;	}	}	*cookie = 0;	for (; chain; chain = LIST_NEXT(chain, chain)) {		register struct ip_fw * f ;again:		f = chain->rule;		if (oif) {			/* Check direction outbound */			if (!(f->fw_flg & IP_FW_F_OUT))				continue;		} else {			/* Check direction inbound */			if (!(f->fw_flg & IP_FW_F_IN))				continue;		}		if (ip == NULL ) {		    /*		     * do relevant checks for non-ip packets:		     * after this, only goto got_match or continue		     */		    struct ether_header *eh = mtod(*m, struct ether_header *);		    /*		     * make default rule always match or we have a panic		     */		    if (f->fw_number == IPFW_DEFAULT_RULE)			goto got_match ;		    /*		     * temporary hack: 		     *   udp from 0.0.0.0 means this rule applies.		     *   1 src port is match ether type		     *   2 src ports (interval) is match ether type		     *   3 src ports is match ether address		     */		    if ( f->fw_src.s_addr != 0 || f->fw_prot != IPPROTO_UDP			|| f->fw_smsk.s_addr != 0xffffffff )			continue;		    switch (IP_FW_GETNSRCP(f)) {		    case 1: /* match one type */			if (  /* ( (f->fw_flg & IP_FW_F_INVSRC) != 0) ^ */				( f->fw_uar.fw_pts[0] == ntohs(eh->ether_type) )  ) {			    goto got_match ;			}			break ;		    default:			break ;		    }		    continue ;		}		/* Fragments */		if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 )			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;/* * here, pip==NULL for bridged pkts -- they include the ethernet * header so i have to adjust lengths accordingly */#define PULLUP_TO(l)	do {                                            \			    int len = (pip ? l : l + 14 ) ;             \			    if ((*m)->m_len < (len) ) {                 \				if ( (*m = m_pullup(*m, (len))) == 0)   \				    goto bogusfrag;                     \				ip = mtod(*m, struct ip *);             \				if (pip)                                \				    *pip = ip ;                         \				else                                    \				    ip = (struct ip *)((int)ip + 14);   \				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_int32_t *)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_int32_t *)ip + ip->ip_hl);			src_port = ntohs(udp->uh_sport);			dst_port = ntohs(udp->uh_dport);check_ports:			if (!port_match(&f->fw_uar.fw_pts[0],			    IP_FW_GETNSRCP(f), src_port,			    f->fw_flg & IP_FW_F_SRNG))				continue;			if (!port_match(&f->fw_uar.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_int32_t *)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:		*flow_id = chain ; /* XXX set flow id */		/* Update statistics */		f->fw_pcnt += 1;		if (ip) {		    f->fw_bcnt += ip->ip_len;		}		f->timestamp = time_second;		/* Log to console if desired */		if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)			ipfw_report(f, ip, rif, oif);		/* Take appropriate action */		switch (f->fw_flg & IP_FW_F_COMMAND) {		case IP_FW_F_ACCEPT:			return(0);		case IP_FW_F_COUNT:			continue;#ifdef IPDIVERT		case IP_FW_F_DIVERT:			*cookie = f->fw_number;			return(f->fw_divert_port);#endif		case IP_FW_F_TEE:			/*			 * XXX someday tee packet here, but beware that you			 * can't use m_copym() or m_copypacket() because			 * the divert input routine modifies the mbuf			 * (and these routines only increment reference			 * counts in the case of mbuf clusters), so need			 * to write custom routine.			 */			continue;		case IP_FW_F_SKIPTO: /* XXX check */			if ( f->next_rule_ptr )			    chain = f->next_rule_ptr ;			else			    chain = lookup_next_rule(chain) ;			if (! chain) goto dropit;			goto again ;#ifdef DUMMYNET		case IP_FW_F_PIPE:			return(f->fw_pipe_nr | 0x10000 );#endif#ifdef IPFIREWALL_FORWARD		case IP_FW_F_FWD:			/* Change the next-hop address for this packet.			 * Initially we'll only worry about directly			 * reachable next-hop's, but ultimately			 * we will work out for next-hops that aren't			 * direct the route we would take for it. We			 * [cs]ould leave this latter problem to			 * ip_output.c. We hope to high [name the abode of			 * your favourite deity] that ip_output doesn't modify			 * the new value of next_hop (which is dst there)			 */			if (next_hop != NULL) /* Make sure, first... */				*next_hop = &(f->fw_fwd_ip);			return(0); /* Allow the packet */#endif		}		/* Deny/reject this packet using this rule */		rule = f;		break;	}#ifdef DIAGNOSTIC	/* Rule IPFW_DEFAULT_RULE should always be there and should always match */	if (!chain)		panic("ip_fw: chain");#endif	/*	 * At this point, we're going to drop the packet.	 * Send a reject notice if all of the following are true:	 *	 * - The packet matched a reject rule	 * - The packet is not an ICMP packet, or is an ICMP query packet	 * - The packet is not a multicast or broadcast packet	 */	if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT	    && ip	    && (ip->ip_p != IPPROTO_ICMP || is_icmp_query(ip))	    && !((*m)->m_flags & (M_BCAST|M_MCAST))	    && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {		switch (rule->fw_reject_code) {		case IP_FW_REJECT_RST:		  {			struct tcphdr *const tcp =				(struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);			struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;			if (offset != 0 || (tcp->th_flags & TH_RST))				break;			ti.ti_i = *((struct ipovly *) ip);			ti.ti_t = *tcp;			bcopy(&ti, ip, sizeof(ti));			NTOHL(tip->ti_seq);			NTOHL(tip->ti_ack);			tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);			if (tcp->th_flags & TH_ACK) {				tcp_respond(NULL, tip, *m,				    (tcp_seq)0, ntohl(tcp->th_ack), TH_RST);			} else {				if (tcp->th_flags & TH_SYN)					tip->ti_len++;				tcp_respond(NULL, tip, *m, tip->ti_seq				    + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);			}			*m = NULL;			break;		  }		default:	/* Send an ICMP unreachable using code */			icmp_error(*m, ICMP_UNREACH,			    rule->fw_reject_code, 0L, 0);			*m = NULL;			break;		}	}dropit:	/*	 * Finally, drop the packet.	 */	/* *cookie = 0; */ /* XXX is this necessary ? */	if (*m) {		m_freem(*m);		*m = NULL;	}	return(0);}/* * when a rule is added/deleted, zero the direct pointers within * all firewall rules. These will be reconstructed on the fly * as packets are matched. * Must be called at splnet(). */static voidflush_rule_ptrs(){    struct ip_fw_chain *fcp ;    for (fcp = ip_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next) {	fcp->rule->next_rule_ptr = NULL ;    }}static intadd_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl){	struct ip_fw *ftmp = 0;	struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0;	u_short nbr = 0;	int s;	fwc = malloc(sizeof *fwc, M_IPFW, M_DONTWAIT);	ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT);	if (!fwc || !ftmp) {		dprintf(("%s malloc said no\n", err_prefix));		if (fwc)  free(fwc, M_IPFW);		if (ftmp) free(ftmp, M_IPFW);		return (ENOSPC);	}	bcopy(frwl, ftmp, sizeof(struct ip_fw));	ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';	ftmp->fw_pcnt = 0L;	ftmp->fw_bcnt = 0L;	ftmp->next_rule_ptr = NULL ;	ftmp->pipe_ptr = NULL ;	fwc->rule = ftmp;		s = splnet();	if (chainptr->lh_first == 0) {		LIST_INSERT_HEAD(chainptr, fwc, chain);		splx(s);		return(0);        }	/* If entry number is 0, find highest numbered rule and add 100 */	if (ftmp->fw_number == 0) {		for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {			if (fcp->rule->fw_number != (u_short)-1)				nbr = fcp->rule->fw_number;			else				break;		}		if (nbr < IPFW_DEFAULT_RULE - 100)			nbr += 100;		ftmp->fw_number = nbr;	}	/* Got a valid number; now insert it, keeping the list ordered */	for (fcp = LIST_FIRST(chainptr); fcp; fcp = LIST_NEXT(fcp, chain)) {		if (fcp->rule->fw_number > ftmp->fw_number) {			if (fcpl) {				LIST_INSERT_AFTER(fcpl, fwc, chain);			} else {				LIST_INSERT_HEAD(chainptr, fwc, chain);			}

⌨️ 快捷键说明

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