ip6_fw.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,390 行 · 第 1/3 页

C
1,390
字号
			    f->fw_divert_port);			break;		case IPV6_FW_F_SKIPTO:			snprintf(SNPARGS(action2, 0), "SkipTo %d",			    f->fw_skipto_rule);			break;		default:				action = "UNKNOWN";			break;		}	}	switch (nxt) {	case IPPROTO_TCP:		len = snprintf(SNPARGS(proto, 0), "TCP [%s]",		    ip6_sprintf(&ip6->ip6_src));		if (off > 0)			len += snprintf(SNPARGS(proto, len), ":%d ",			    ntohs(tcp6->th_sport));		else			len += snprintf(SNPARGS(proto, len), " ");		len += snprintf(SNPARGS(proto, len), "[%s]",		    ip6_sprintf(&ip6->ip6_dst));		if (off > 0)			snprintf(SNPARGS(proto, len), ":%d",			    ntohs(tcp6->th_dport));		break;	case IPPROTO_UDP:		len = snprintf(SNPARGS(proto, 0), "UDP [%s]",		    ip6_sprintf(&ip6->ip6_src));		if (off > 0)			len += snprintf(SNPARGS(proto, len), ":%d ",			    ntohs(udp->uh_sport));		else		    len += snprintf(SNPARGS(proto, len), " ");		len += snprintf(SNPARGS(proto, len), "[%s]",		    ip6_sprintf(&ip6->ip6_dst));		if (off > 0)			snprintf(SNPARGS(proto, len), ":%d",			    ntohs(udp->uh_dport));		break;	case IPPROTO_ICMPV6:		if (off > 0)			len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ",			    icmp6->icmp6_type, icmp6->icmp6_code);		else			len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP ");		len += snprintf(SNPARGS(proto, len), "[%s]",		    ip6_sprintf(&ip6->ip6_src));		snprintf(SNPARGS(proto, len), " [%s]",		    ip6_sprintf(&ip6->ip6_dst));		break;	default:		len = snprintf(SNPARGS(proto, 0), "P:%d [%s]", nxt,		    ip6_sprintf(&ip6->ip6_src));		snprintf(SNPARGS(proto, len), " [%s]",		    ip6_sprintf(&ip6->ip6_dst));		break;	}	if (oif)		log(LOG_SECURITY | LOG_INFO, "%s %s %s out via %s\n",		    name, action, proto, if_name(oif));	else if (rif)		log(LOG_SECURITY | LOG_INFO, "%s %s %s in via %s\n",		    name, action, proto, if_name(rif));	else		log(LOG_SECURITY | LOG_INFO, "%s %s %s",		    name, action, proto);	if (fw6_verbose_limit != 0 && count == fw6_verbose_limit)	    log(LOG_SECURITY | LOG_INFO, "ip6fw: limit reached on entry %d\n",		f ? f->fw_number : -1);}/* * Parameters: * *	ip	Pointer to packet header (struct ip6_hdr *) *	hlen	Packet header length *	oif	Outgoing interface, or NULL if packet is incoming *	*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 intip6_fw_chk(struct ip6_hdr **pip6,	struct ifnet *oif, struct mbuf **m){	struct ip6_fw_chain *chain;	struct ip6_fw *rule = NULL;	struct ip6_hdr *ip6 = *pip6;	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;	u_short offset = 0;	int off = sizeof(struct ip6_hdr), nxt = ip6->ip6_nxt;	u_short src_port, dst_port;#ifdef	IP6FW_DIVERT_RESTART	u_int16_t skipto = 0;#else	u_int16_t ignport = 0;#endif	/*	 * Go down the chain, looking for enlightment	 * #ifdef IP6FW_DIVERT_RESTART	 * If we've been asked to start at a given rule immediatly, do so.	 * #endif	 */	chain = LIST_FIRST(&ip6_fw_chain);#ifdef IP6FW_DIVERT_RESTART	if (skipto) {		if (skipto >= 65535)			goto dropit;		while (chain && (chain->rule->fw_number <= skipto)) {			chain = LIST_NEXT(chain, chain);		}		if (! chain) goto dropit;	}#endif /* IP6FW_DIVERT_RESTART */	for (; chain; chain = LIST_NEXT(chain, chain)) {		struct ip6_fw *const f = chain->rule;		if (oif) {			/* Check direction outbound */			if (!(f->fw_flg & IPV6_FW_F_OUT))				continue;		} else {			/* Check direction inbound */			if (!(f->fw_flg & IPV6_FW_F_IN))				continue;		}#define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\	(((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \	(((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \	(((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \	(((x)->s6_addr32[3] & (y)->s6_addr32[3]) == (z)->s6_addr32[3]))		/* If src-addr doesn't match, not this rule. */		if (((f->fw_flg & IPV6_FW_F_INVSRC) != 0) ^			(!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_src,&f->fw_smsk,&f->fw_src)))			continue;		/* If dest-addr doesn't match, not this rule. */		if (((f->fw_flg & IPV6_FW_F_INVDST) != 0) ^			(!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_dst,&f->fw_dmsk,&f->fw_dst)))			continue;#undef IN6_ARE_ADDR_MASKEQUAL		/* Interface check */		if ((f->fw_flg & IF6_FW_F_VIAHACK) == IF6_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 & IPV6_FW_F_OIFNAME))				continue;		} else {			/* Check receive interface */			if ((f->fw_flg & IPV6_FW_F_IIFACE)			    && (!rif || !iface_match(rif,			      &f->fw_in_if, f->fw_flg & IPV6_FW_F_IIFNAME)))				continue;			/* Check outgoing interface */			if ((f->fw_flg & IPV6_FW_F_OIFACE)			    && (!oif || !iface_match(oif,			      &f->fw_out_if, f->fw_flg & IPV6_FW_F_OIFNAME)))				continue;		}		/* Check IP options */		if (!ip6opts_match(&ip6, f, m, &off, &nxt, &offset))			continue;		/* Fragments */		if ((f->fw_flg & IPV6_FW_F_FRAG) && !offset)			continue;		/* Check protocol; if wildcard, match */		if (f->fw_prot == IPPROTO_IPV6)			goto got_match;		/* If different, don't match */		if (nxt != f->fw_prot)			continue;#define PULLUP_TO(len)	do {						\			    if ((*m)->m_len < (len)			\				&& (*m = m_pullup(*m, (len))) == 0) {	\				    goto dropit;			\			    }						\			    *pip6 = ip6 = mtod(*m, struct ip6_hdr *);	\			} while (0)		/* Protocol specific checks */		switch (nxt) {		case IPPROTO_TCP:		    {			struct tcphdr *tcp6;			if (offset == 1) {	/* cf. RFC 1858 */				PULLUP_TO(off + 4); /* XXX ? */				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(off + 14);			tcp6 = (struct tcphdr *) ((caddr_t)ip6 + off);			if (((f->fw_tcpf != f->fw_tcpnf) ||			   (f->fw_ipflg & IPV6_FW_IF_TCPEST))  &&			   !tcp6flg_match(tcp6, f))				continue;			src_port = ntohs(tcp6->th_sport);			dst_port = ntohs(tcp6->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(off + 4);			udp = (struct udphdr *) ((caddr_t)ip6 + off);			src_port = ntohs(udp->uh_sport);			dst_port = ntohs(udp->uh_dport);check_ports:			if (!port_match6(&f->fw_pts[0],			    IPV6_FW_GETNSRCP(f), src_port,			    f->fw_flg & IPV6_FW_F_SRNG))				continue;			if (!port_match6(&f->fw_pts[IPV6_FW_GETNSRCP(f)],			    IPV6_FW_GETNDSTP(f), dst_port,			    f->fw_flg & IPV6_FW_F_DRNG))				continue;			break;		    }		case IPPROTO_ICMPV6:		    {			struct icmp6_hdr *icmp;			if (offset != 0)	/* Type isn't valid */				break;			PULLUP_TO(off + 2);			icmp = (struct icmp6_hdr *) ((caddr_t)ip6 + off);			if (!icmp6type_match(icmp, f))				continue;			break;		    }#undef PULLUP_TObogusfrag:			if (fw6_verbose)				ip6fw_report(NULL, ip6, rif, oif, off, nxt);			goto dropit;		}got_match:#ifndef IP6FW_DIVERT_RESTART		/* Ignore divert/tee rule if socket port is "ignport" */		switch (f->fw_flg & IPV6_FW_F_COMMAND) {		case IPV6_FW_F_DIVERT:		case IPV6_FW_F_TEE:			if (f->fw_divert_port == ignport)				continue;       /* ignore this rule */			break;		}#endif /* IP6FW_DIVERT_RESTART */		/* Update statistics */		f->fw_pcnt += 1;		f->fw_bcnt += ntohs(ip6->ip6_plen);#if defined(__FreeBSD__) && __FreeBSD__ >= 3		f->timestamp = time_second;#else		f->timestamp = time.tv_sec;#endif		/* Log to console if desired */		if ((f->fw_flg & IPV6_FW_F_PRN) && fw6_verbose)			ip6fw_report(f, ip6, rif, oif, off, nxt);		/* Take appropriate action */		switch (f->fw_flg & IPV6_FW_F_COMMAND) {		case IPV6_FW_F_ACCEPT:			return(0);		case IPV6_FW_F_COUNT:			continue;		case IPV6_FW_F_DIVERT:			return(f->fw_divert_port);		case IPV6_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 IPV6_FW_F_SKIPTO:#ifdef DIAGNOSTIC			while (chain->chain.le_next			    && chain->chain.le_next->rule->fw_number				< f->fw_skipto_rule)#else			while (chain->chain.le_next->rule->fw_number			    < f->fw_skipto_rule)#endif				chain = chain->chain.le_next;			continue;		}		/* Deny/reject this packet using this rule */		rule = f;		break;	}#ifdef DIAGNOSTIC	/* Rule 65535 should always be there and should always match */	if (!chain)		panic("ip6_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 & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT	    && (nxt != IPPROTO_ICMPV6 || is_icmp6_query(ip6, off))	    && !((*m)->m_flags & (M_BCAST|M_MCAST))	    && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {		switch (rule->fw_reject_code) {		case IPV6_FW_REJECT_RST:#if 1	/* not tested */		  {			struct tcphdr *const tcp =				(struct tcphdr *) ((caddr_t)ip6 + off);			struct {				struct ip6_hdr ip6;				struct tcphdr th;			} ti;			tcp_seq ack, seq;			int flags;			if (offset != 0 || (tcp->th_flags & TH_RST))				break;			ti.ip6 = *ip6;			ti.th = *tcp;			NTOHL(ti.th.th_seq);			NTOHL(ti.th.th_ack);			ti.ip6.ip6_nxt = IPPROTO_TCP;			if (ti.th.th_flags & TH_ACK) {				ack = 0;				seq = ti.th.th_ack;				flags = TH_RST;			} else {				ack = ti.th.th_seq;				if (((*m)->m_flags & M_PKTHDR) != 0) {					ack += (*m)->m_pkthdr.len - off						- (ti.th.th_off << 2);				} else if (ip6->ip6_plen) {					ack += ntohs(ip6->ip6_plen) + sizeof(*ip6)						- off - (ti.th.th_off << 2);				} else {					m_freem(*m);					*m = 0;					break;				}				seq = 0;				flags = TH_RST|TH_ACK;			}			bcopy(&ti, ip6, sizeof(ti));#ifdef TCP6			tcp6_respond(NULL, ip6, (struct tcp6hdr *)(ip6 + 1),				*m, ack, seq, flags);#elif defined(__NetBSD__)			tcp_respond(NULL, NULL, *m, (struct tcphdr *)(ip6 + 1),				ack, seq, flags);#elif defined(__FreeBSD__) && __FreeBSD__ >= 4			tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),				*m, ack, seq, flags);#elif defined(__FreeBSD__) && __FreeBSD__ >= 3			tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),				*m, ack, seq, flags, 1);#else			m_freem(*m);#endif			*m = NULL;			break;		  }#endif		default:	/* Send an ICMP unreachable using code */			if (oif)				(*m)->m_pkthdr.rcvif = oif;			icmp6_error(*m, ICMP6_DST_UNREACH,			    rule->fw_reject_code, 0);			*m = NULL;			break;		}	}dropit:	/*	 * Finally, drop the packet.	 */	if (*m) {		m_freem(*m);		*m = NULL;	}	return(0);}static intadd_entry6(struct ip6_fw_head *chainptr, struct ip6_fw *frwl){	struct ip6_fw *ftmp = 0;	struct ip6_fw_chain *fwc = 0, *fcp, *fcpl = 0;	u_short nbr = 0;	int s;	fwc = malloc(sizeof *fwc, M_IP6FW, M_DONTWAIT);	ftmp = malloc(sizeof *ftmp, M_IP6FW, M_DONTWAIT);	if (!fwc || !ftmp) {		dprintf(("%s malloc said no\n", err_prefix));		if (fwc)  free(fwc, M_IP6FW);		if (ftmp) free(ftmp, M_IP6FW);		return (ENOSPC);	}	bcopy(frwl, ftmp, sizeof(struct ip6_fw));	ftmp->fw_in_if.fu_via_if.name[IP6FW_IFNLEN - 1] = '\0';	ftmp->fw_pcnt = 0L;

⌨️ 快捷键说明

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