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

📄 ip6_fw.c

📁 嵌入式操作系统ECOS的网络开发包
💻 C
📖 第 1 页 / 共 3 页
字号:
	ftmp->fw_bcnt = 0L;
	fwc->rule = ftmp;
	
	s = splnet();

	if (!chainptr->lh_first) {
		LIST_INSERT_HEAD(chainptr, fwc, chain);
		splx(s);
		return(0);
        } else if (ftmp->fw_number == (u_short)-1) {
		if (fwc)  free(fwc, M_IP6FW);
		if (ftmp) free(ftmp, M_IP6FW);
		splx(s);
		dprintf(("%s bad rule number\n", err_prefix));
		return (EINVAL);
        }

	/* If entry number is 0, find highest numbered rule and add 100 */
	if (ftmp->fw_number == 0) {
		for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
			if (fcp->rule->fw_number != (u_short)-1)
				nbr = fcp->rule->fw_number;
			else
				break;
		}
		if (nbr < (u_short)-1 - 100)
			nbr += 100;
		ftmp->fw_number = nbr;
	}

	/* Got a valid number; now insert it, keeping the list ordered */
	for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
		if (fcp->rule->fw_number > ftmp->fw_number) {
			if (fcpl) {
				LIST_INSERT_AFTER(fcpl, fwc, chain);
			} else {
				LIST_INSERT_HEAD(chainptr, fwc, chain);
			}
			break;
		} else {
			fcpl = fcp;
		}
	}

	splx(s);
	return (0);
}

static int
del_entry6(struct ip6_fw_head *chainptr, u_short number)
{
	struct ip6_fw_chain *fcp;
	int s;

	s = splnet();

	fcp = chainptr->lh_first;
	if (number != (u_short)-1) {
		for (; fcp; fcp = fcp->chain.le_next) {
			if (fcp->rule->fw_number == number) {
				LIST_REMOVE(fcp, chain);
				splx(s);
				free(fcp->rule, M_IP6FW);
				free(fcp, M_IP6FW);
				return 0;
			}
		}
	}

	splx(s);
	return (EINVAL);
}

static int
zero_entry6(struct mbuf *m)
{
	struct ip6_fw *frwl;
	struct ip6_fw_chain *fcp;
	int s;

	if (m && m->m_len != 0) {
		if (m->m_len != sizeof(struct ip6_fw))
			return(EINVAL);
		frwl = mtod(m, struct ip6_fw *);
	}
	else
		frwl = NULL;

	/*
	 *	It's possible to insert multiple chain entries with the
	 *	same number, so we don't stop after finding the first
	 *	match if zeroing a specific entry.
	 */
	s = splnet();
	for (fcp = ip6_fw_chain.lh_first; fcp; fcp = fcp->chain.le_next)
		if (!frwl || frwl->fw_number == fcp->rule->fw_number) {
			fcp->rule->fw_bcnt = fcp->rule->fw_pcnt = 0;
			fcp->rule->timestamp = 0;
		}
	splx(s);

	if (fw6_verbose) {
		if (frwl)
			log(LOG_SECURITY | LOG_NOTICE,
			    "ip6fw: Entry %d cleared.\n", frwl->fw_number);
		else
			log(LOG_SECURITY | LOG_NOTICE,
			    "ip6fw: Accounting cleared.\n");
	}

	return(0);
}

static struct ip6_fw *
check_ip6fw_mbuf(struct mbuf *m)
{
	/* Check length */
	if (m->m_len != sizeof(struct ip6_fw)) {
		dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
		    sizeof(struct ip6_fw)));
		return (NULL);
	}
	return(check_ip6fw_struct(mtod(m, struct ip6_fw *)));
}

static struct ip6_fw *
check_ip6fw_struct(struct ip6_fw *frwl)
{
	/* Check for invalid flag bits */
	if ((frwl->fw_flg & ~IPV6_FW_F_MASK) != 0) {
		dprintf(("%s undefined flag bits set (flags=%x)\n",
		    err_prefix, frwl->fw_flg));
		return (NULL);
	}
	/* Must apply to incoming or outgoing (or both) */
	if (!(frwl->fw_flg & (IPV6_FW_F_IN | IPV6_FW_F_OUT))) {
		dprintf(("%s neither in nor out\n", err_prefix));
		return (NULL);
	}
	/* Empty interface name is no good */
	if (((frwl->fw_flg & IPV6_FW_F_IIFNAME)
	      && !*frwl->fw_in_if.fu_via_if.name)
	    || ((frwl->fw_flg & IPV6_FW_F_OIFNAME)
	      && !*frwl->fw_out_if.fu_via_if.name)) {
		dprintf(("%s empty interface name\n", err_prefix));
		return (NULL);
	}
	/* Sanity check interface matching */
	if ((frwl->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
		;		/* allow "via" backwards compatibility */
	} else if ((frwl->fw_flg & IPV6_FW_F_IN)
	    && (frwl->fw_flg & IPV6_FW_F_OIFACE)) {
		dprintf(("%s outgoing interface check on incoming\n",
		    err_prefix));
		return (NULL);
	}
	/* Sanity check port ranges */
	if ((frwl->fw_flg & IPV6_FW_F_SRNG) && IPV6_FW_GETNSRCP(frwl) < 2) {
		dprintf(("%s src range set but n_src_p=%d\n",
		    err_prefix, IPV6_FW_GETNSRCP(frwl)));
		return (NULL);
	}
	if ((frwl->fw_flg & IPV6_FW_F_DRNG) && IPV6_FW_GETNDSTP(frwl) < 2) {
		dprintf(("%s dst range set but n_dst_p=%d\n",
		    err_prefix, IPV6_FW_GETNDSTP(frwl)));
		return (NULL);
	}
	if (IPV6_FW_GETNSRCP(frwl) + IPV6_FW_GETNDSTP(frwl) > IPV6_FW_MAX_PORTS) {
		dprintf(("%s too many ports (%d+%d)\n",
		    err_prefix, IPV6_FW_GETNSRCP(frwl), IPV6_FW_GETNDSTP(frwl)));
		return (NULL);
	}
	/*
	 *	Protocols other than TCP/UDP don't use port range
	 */
	if ((frwl->fw_prot != IPPROTO_TCP) &&
	    (frwl->fw_prot != IPPROTO_UDP) &&
	    (IPV6_FW_GETNSRCP(frwl) || IPV6_FW_GETNDSTP(frwl))) {
		dprintf(("%s port(s) specified for non TCP/UDP rule\n",
		    err_prefix));
		return(NULL);
	}

	/*
	 *	Rather than modify the entry to make such entries work,
	 *	we reject this rule and require user level utilities
	 *	to enforce whatever policy they deem appropriate.
	 */
	if ((frwl->fw_src.s6_addr32[0] & (~frwl->fw_smsk.s6_addr32[0])) ||
		(frwl->fw_src.s6_addr32[1] & (~frwl->fw_smsk.s6_addr32[1])) ||
		(frwl->fw_src.s6_addr32[2] & (~frwl->fw_smsk.s6_addr32[2])) ||
		(frwl->fw_src.s6_addr32[3] & (~frwl->fw_smsk.s6_addr32[3])) ||
		(frwl->fw_dst.s6_addr32[0] & (~frwl->fw_dmsk.s6_addr32[0])) ||
		(frwl->fw_dst.s6_addr32[1] & (~frwl->fw_dmsk.s6_addr32[1])) ||
		(frwl->fw_dst.s6_addr32[2] & (~frwl->fw_dmsk.s6_addr32[2])) ||
		(frwl->fw_dst.s6_addr32[3] & (~frwl->fw_dmsk.s6_addr32[3]))) {
		dprintf(("%s rule never matches\n", err_prefix));
		return(NULL);
	}

	if ((frwl->fw_flg & IPV6_FW_F_FRAG) &&
		(frwl->fw_prot == IPPROTO_UDP || frwl->fw_prot == IPPROTO_TCP)) {
		if (frwl->fw_nports) {
			dprintf(("%s cannot mix 'frag' and ports\n", err_prefix));
			return(NULL);
		}
		if (frwl->fw_prot == IPPROTO_TCP &&
			frwl->fw_tcpf != frwl->fw_tcpnf) {
			dprintf(("%s cannot mix 'frag' with TCP flags\n", err_prefix));
			return(NULL);
		}
	}

	/* Check command specific stuff */
	switch (frwl->fw_flg & IPV6_FW_F_COMMAND)
	{
	case IPV6_FW_F_REJECT:
		if (frwl->fw_reject_code >= 0x100
		    && !(frwl->fw_prot == IPPROTO_TCP
		      && frwl->fw_reject_code == IPV6_FW_REJECT_RST)) {
			dprintf(("%s unknown reject code\n", err_prefix));
			return(NULL);
		}
		break;
	case IPV6_FW_F_DIVERT:		/* Diverting to port zero is invalid */
	case IPV6_FW_F_TEE:
		if (frwl->fw_divert_port == 0) {
			dprintf(("%s can't divert to port 0\n", err_prefix));
			return (NULL);
		}
		break;
	case IPV6_FW_F_DENY:
	case IPV6_FW_F_ACCEPT:
	case IPV6_FW_F_COUNT:
	case IPV6_FW_F_SKIPTO:
		break;
	default:
		dprintf(("%s invalid command\n", err_prefix));
		return(NULL);
	}

	return frwl;
}

static int
ip6_fw_ctl(int stage, struct mbuf **mm)
{
	int error;
	struct mbuf *m;

	if (stage == IPV6_FW_GET) {
		struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
		*mm = m = m_get(M_WAIT, MT_DATA); /* XXX */
#else
		*mm = m = m_get(M_WAIT, MT_SOOPTS);
#endif
		if (!m)
			return(ENOBUFS);
		if (sizeof *(fcp->rule) > MLEN) {
			MCLGET(m, M_WAIT);
			if ((m->m_flags & M_EXT) == 0) {
				m_free(m);
				return(ENOBUFS);
			}
		}
		for (; fcp; fcp = fcp->chain.le_next) {
			bcopy(fcp->rule, m->m_data, sizeof *(fcp->rule));
			m->m_len = sizeof *(fcp->rule);
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
			m->m_next = m_get(M_WAIT, MT_DATA); /* XXX */
#else
			m->m_next = m_get(M_WAIT, MT_SOOPTS);
#endif
			if (!m->m_next) {
				m_freem(*mm);
				return(ENOBUFS);
			}
			m = m->m_next;
			if (sizeof *(fcp->rule) > MLEN) {
				MCLGET(m, M_WAIT);
				if ((m->m_flags & M_EXT) == 0) {
					m_freem(*mm);
					return(ENOBUFS);
				}
			}
			m->m_len = 0;
		}
		return (0);
	}
	m = *mm;
	/* only allow get calls if secure mode > 2 */
	if (securelevel > 2) {
		if (m) {
			(void)m_freem(m);
			*mm = 0;
		}
		return(EPERM);
	}
	if (stage == IPV6_FW_FLUSH) {
		while (ip6_fw_chain.lh_first != NULL &&
		    ip6_fw_chain.lh_first->rule->fw_number != (u_short)-1) {
			struct ip6_fw_chain *fcp = ip6_fw_chain.lh_first;
			int s = splnet();
			LIST_REMOVE(ip6_fw_chain.lh_first, chain);
			splx(s);
			free(fcp->rule, M_IP6FW);
			free(fcp, M_IP6FW);
		}
		if (m) {
			(void)m_freem(m);
			*mm = 0;
		}
		return (0);
	}
	if (stage == IPV6_FW_ZERO) {
		error = zero_entry6(m);
		if (m) {
			(void)m_freem(m);
			*mm = 0;
		}
		return (error);
	}
	if (m == NULL) {
		printf("%s NULL mbuf ptr\n", err_prefix);
		return (EINVAL);
	}

	if (stage == IPV6_FW_ADD) {
		struct ip6_fw *frwl = check_ip6fw_mbuf(m);

		if (!frwl)
			error = EINVAL;
		else
			error = add_entry6(&ip6_fw_chain, frwl);
		if (m) {
			(void)m_freem(m);
			*mm = 0;
		}
		return error;
	}
	if (stage == IPV6_FW_DEL) {
		if (m->m_len != sizeof(struct ip6_fw)) {
			dprintf(("%s len=%d, want %d\n", err_prefix, m->m_len,
			    sizeof(struct ip6_fw)));
			error = EINVAL;
		} else if (mtod(m, struct ip6_fw *)->fw_number == (u_short)-1) {
			dprintf(("%s can't delete rule 65535\n", err_prefix));
			error = EINVAL;
		} else
			error = del_entry6(&ip6_fw_chain,
			    mtod(m, struct ip6_fw *)->fw_number);
		if (m) {
			(void)m_freem(m);
			*mm = 0;
		}
		return error;
	}

	dprintf(("%s unknown request %d\n", err_prefix, stage));
	if (m) {
		(void)m_freem(m);
		*mm = 0;
	}
	return (EINVAL);
}

void
ip6_fw_init(void)
{
	struct ip6_fw default_rule;

	ip6_fw_chk_ptr = ip6_fw_chk;
	ip6_fw_ctl_ptr = ip6_fw_ctl;
	LIST_INIT(&ip6_fw_chain);

	bzero(&default_rule, sizeof default_rule);
	default_rule.fw_prot = IPPROTO_IPV6;
	default_rule.fw_number = (u_short)-1;
#ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
	default_rule.fw_flg |= IPV6_FW_F_ACCEPT;
#else
	default_rule.fw_flg |= IPV6_FW_F_DENY;
#endif
	default_rule.fw_flg |= IPV6_FW_F_IN | IPV6_FW_F_OUT;
	if (check_ip6fw_struct(&default_rule) == NULL ||
		add_entry6(&ip6_fw_chain, &default_rule))
		panic(__FUNCTION__);

#if 1	/* NOT SUPPORTED IPV6 DIVERT */
	printf("IPv6 packet filtering initialized, ");
#else
	printf("IPv6 packet filtering initialized, "
#ifdef IP6DIVERT
		"divert enabled, ");
#else
		"divert disabled, ");
#endif
#endif
#ifdef IPV6FIREWALL_DEFAULT_TO_ACCEPT
	printf("default to accept, ");
#endif
#ifndef IPV6FIREWALL_VERBOSE
	printf("logging disabled\n");
#else
	if (fw6_verbose_limit == 0)
		printf("unlimited logging\n");
	else
		printf("logging limited to %d packets/entry\n",
		    fw6_verbose_limit);
#endif
}

#if defined(__FreeBSD__) && __FreeBSD__ >= 4
static ip6_fw_chk_t *old_chk_ptr;
static ip6_fw_ctl_t *old_ctl_ptr;

static int
ip6fw_modevent(module_t mod, int type, void *unused)
{
        int s;

        switch (type) {
        case MOD_LOAD:
                s = splnet();

                old_chk_ptr = ip6_fw_chk_ptr;
                old_ctl_ptr = ip6_fw_ctl_ptr;

                ip6_fw_init();
                splx(s);
                return 0;
        case MOD_UNLOAD:
                s = splnet();
                ip6_fw_chk_ptr =  old_chk_ptr;
                ip6_fw_ctl_ptr =  old_ctl_ptr;
                while (LIST_FIRST(&ip6_fw_chain) != NULL) {
                        struct ip6_fw_chain *fcp = LIST_FIRST(&ip6_fw_chain);
                        LIST_REMOVE(LIST_FIRST(&ip6_fw_chain), chain);
                        free(fcp->rule, M_IP6FW);
                        free(fcp, M_IP6FW);
                }

                splx(s);
                printf("IPv6 firewall unloaded\n");
                return 0;
        default:
                break;
        }
        return 0;
}

static moduledata_t ip6fwmod = {
        "ip6fw",
        ip6fw_modevent,
        0
};
DECLARE_MODULE(ip6fw, ip6fwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
#endif


⌨️ 快捷键说明

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