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

📄 ip_fw.c.svn-base

📁 wipfw 是windows下的网络控制工具
💻 SVN-BASE
📖 第 1 页 / 共 5 页
字号:
zero_entry(struct ip_fw *frwl, int log_only)
{
    struct ip_fw *rule;
    int s;
    u_short number = 0 ;
    char *msg ;

    if (frwl == 0) {
	s = splimp();
	LIST_FOREACH(rule, &ip_fw_chain_head, next) {
	    if (log_only == 0) {
		rule->fw_bcnt = rule->fw_pcnt = 0;
		rule->timestamp = 0;
	    }
	    rule->fw_loghighest = rule->fw_pcnt+rule->fw_logamount;
	}
	splx(s);
	msg = log_only ? "ipfw: All logging counts cleared.\n" :
			"ipfw: Accounting cleared.\n";
    } else {
	int cleared = 0;
	number = frwl->fw_number ;
	/*
	 * It is 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.
	 */
	LIST_FOREACH(rule, &ip_fw_chain_head, next)
	    if (number == rule->fw_number) {
		s = splimp();
		while (rule && number == rule->fw_number) {
		    if (log_only == 0) {
			rule->fw_bcnt = rule->fw_pcnt = 0;
			rule->timestamp = 0;
		    }
		    rule->fw_loghighest = rule->fw_pcnt+ rule->fw_logamount;
		    rule = LIST_NEXT(rule, next);
		}
		splx(s);
		cleared = 1;
		break;
	    }
	if (!cleared)	/* we did not find any matching rules */
	    return (EINVAL);
	msg = log_only ? "ipfw: Entry %d logging count reset.\n" :
			"ipfw: Entry %d cleared.\n";
    }
    if (fw_verbose)
	log(LOG_SECURITY | LOG_NOTICE, msg, number);
    return (0);
}

static int
check_ipfw_struct(struct ip_fw *frwl)
{
	/* Check for invalid flag bits */
	if ((frwl->fw_flg & ~IP_FW_F_MASK) != 0) {
		dprintf(("%s undefined flag bits set (flags=%x)\n",
		    err_prefix, frwl->fw_flg));
		return (EINVAL);
	}
	if (frwl->fw_flg == IP_FW_F_CHECK_S) {
		/* check-state */
		return 0 ;
	}
	/* Must apply to incoming or outgoing (or both) */
	if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT))) {
		dprintf(("%s neither in nor out\n", err_prefix));
		return (EINVAL);
	}
	/* Empty interface name is no good */
	if (((frwl->fw_flg & IP_FW_F_IIFNAME)
	      && !*frwl->fw_in_if.fu_via_if.name)
	    || ((frwl->fw_flg & IP_FW_F_OIFNAME)
	      && !*frwl->fw_out_if.fu_via_if.name)) {
		dprintf(("%s empty interface name\n", err_prefix));
		return (EINVAL);
	}
	/* Sanity check interface matching */
	if ((frwl->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
		;		/* allow "via" backwards compatibility */
	} else if ((frwl->fw_flg & IP_FW_F_IN)
	    && (frwl->fw_flg & IP_FW_F_OIFACE)) {
		dprintf(("%s outgoing interface check on incoming\n",
		    err_prefix));
		return (EINVAL);
	}
	/* Sanity check port ranges */
	if ((frwl->fw_flg & IP_FW_F_SRNG) && IP_FW_GETNSRCP(frwl) < 2) {
		dprintf(("%s src range set but n_src_p=%d\n",
		    err_prefix, IP_FW_GETNSRCP(frwl)));
		return (EINVAL);
	}
	if ((frwl->fw_flg & IP_FW_F_DRNG) && IP_FW_GETNDSTP(frwl) < 2) {
		dprintf(("%s dst range set but n_dst_p=%d\n",
		    err_prefix, IP_FW_GETNDSTP(frwl)));
		return (EINVAL);
	}
	if (IP_FW_GETNSRCP(frwl) + IP_FW_GETNDSTP(frwl) > IP_FW_MAX_PORTS) {
		dprintf(("%s too many ports (%d+%d)\n",
		    err_prefix, IP_FW_GETNSRCP(frwl), IP_FW_GETNDSTP(frwl)));
		return (EINVAL);
	}
	/*
	 *	Protocols other than TCP/UDP don't use port range
	 */
	if ((frwl->fw_prot != IPPROTO_TCP) &&
	    (frwl->fw_prot != IPPROTO_UDP) &&
	    (IP_FW_GETNSRCP(frwl) || IP_FW_GETNDSTP(frwl))) {
		dprintf(("%s port(s) specified for non TCP/UDP rule\n",
		    err_prefix));
		return (EINVAL);
	}

	/*
	 *	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.s_addr & (~frwl->fw_smsk.s_addr)) || 
		(frwl->fw_dst.s_addr & (~frwl->fw_dmsk.s_addr))) {
		dprintf(("%s rule never matches\n", err_prefix));
		return (EINVAL);
	}

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

	/* Check command specific stuff */
	switch (frwl->fw_flg & IP_FW_F_COMMAND) {
	case IP_FW_F_REJECT:
		if (frwl->fw_reject_code >= 0x100
		    && !(frwl->fw_prot == IPPROTO_TCP
		      && frwl->fw_reject_code == IP_FW_REJECT_RST)) {
			dprintf(("%s unknown reject code\n", err_prefix));
			return (EINVAL);
		}
		break;
#ifdef IPDIVERT
	case IP_FW_F_DIVERT:		/* Diverting to port zero is invalid */
	case IP_FW_F_TEE:
#endif
	case IP_FW_F_PIPE:              /* pipe 0 is invalid */
	case IP_FW_F_QUEUE:             /* queue 0 is invalid */
		if (frwl->fw_divert_port == 0) {
			dprintf(("%s 0 is an invalid argument\n", err_prefix));
			return (EINVAL);
		}
		break;
	case IP_FW_F_DENY:
	case IP_FW_F_ACCEPT:
	case IP_FW_F_COUNT:
	case IP_FW_F_SKIPTO:
	case IP_FW_F_FWD:
	case IP_FW_F_UID:
	case IP_FW_F_GID:
		break;
	default:
		dprintf(("%s invalid command\n", err_prefix));
		return (EINVAL);
	}

	return 0;
}

static int
ip_fw_ctl(struct sockopt *sopt)
{
	int error, s;
	size_t size;
	struct ip_fw *fcp;
	struct ip_fw frwl, *bp , *buf;

	/*
	 * Disallow modifications in really-really secure mode, but still allow
	 * the logging counters to be reset.
	 */
	if (securelevel >= 3 && (sopt->sopt_name == IP_FW_ADD ||
	    (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)))
			return (EPERM);
	error = 0;

	switch (sopt->sopt_name) {
	case IP_FW_GET:
		/*
		 * pass up a copy of the current rules. Static rules
		 * come first (the last of which has number 65535),
		 * followed by a possibly empty list of dynamic rule.
		 * The last dynamic rule has NULL in the "next" field.
		 */
		s = splimp();
		/* size of static rules */
		size = static_count * sizeof(struct ip_fw) ;
		if (ipfw_dyn_v)		/* add size of dyn.rules */
		    size += (dyn_count * sizeof(struct ipfw_dyn_rule));

		/*
		 * XXX todo: if the user passes a short length to know how
		 * much room is needed, do not
		 * bother filling up the buffer, just jump to the
		 * sooptcopyout.
		 */
		buf = malloc(size, M_TEMP, M_WAITOK);
		if (buf == 0) {
		    splx(s);
		    error = ENOBUFS;
		    break;
		}

		bp = buf ;
		LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
		    bcopy(fcp, bp, sizeof *fcp);
		    bp++;
		}
		if (ipfw_dyn_v) {
		    int i ;
		    struct ipfw_dyn_rule *p, *dst, *last = NULL ;

		    dst = (struct ipfw_dyn_rule *)bp ;
		    for (i = 0 ; i < curr_dyn_buckets ; i++ )
			for ( p = ipfw_dyn_v[i] ; p != NULL ; p = p->next, dst++ ) {
			    bcopy(p, dst, sizeof *p);
                            (u_short)dst->rule = p->rule->fw_number ;
			    /*
			     * store a non-null value in "next". The userland
			     * code will interpret a NULL here as a marker
			     * for the last dynamic rule.
			     */
                            dst->next = dst ;
			    last = dst ;
			    if (TIME_LEQ(dst->expire, time_second) )
				dst->expire = 0 ;
			    else
				dst->expire -= time_second ;
			    }
		    if (last != NULL)
			last->next = NULL ; /* mark last dynamic rule */
		}
		splx(s);

		error = sooptcopyout(sopt, buf, size);
		free(buf, M_TEMP);
		break;

	case IP_FW_FLUSH:
		/*
		 * Normally we cannot release the lock on each iteration.
		 * We could do it here only because we start from the head all
		 * the times so there is no risk of missing some entries.
		 * On the other hand, the risk is that we end up with
		 * a very inconsistent ruleset, so better keep the lock
		 * around the whole cycle.
		 * 
		 * XXX this code can be improved by resetting the head of
		 * the list to point to the default rule, and then freeing
		 * the old list without the need for a lock.
		 */

		s = splimp();
		while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) &&
			fcp->fw_number != IPFW_DEFAULT_RULE )
		    free_chain(fcp);
		splx(s);
		break;

	case IP_FW_ADD:
		error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
		if (error || (error = check_ipfw_struct(&frwl)))
			break;

		if (frwl.fw_number == IPFW_DEFAULT_RULE) {
			dprintf(("%s can't add rule %u\n", err_prefix,
				 (unsigned)IPFW_DEFAULT_RULE));
			error = EINVAL;
		} else {
			error = add_entry(&ip_fw_chain_head, &frwl);
			if (!error && sopt->sopt_dir == SOPT_GET)
				error = sooptcopyout(sopt, &frwl, sizeof frwl);
		}
		break;

	case IP_FW_DEL:
		error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
		if (error)
			break;

		if (frwl.fw_number == IPFW_DEFAULT_RULE) {
			dprintf(("%s can't delete rule %u\n", err_prefix,
				 (unsigned)IPFW_DEFAULT_RULE));
			error = EINVAL;
		} else {
			error = del_entry(&ip_fw_chain_head, frwl.fw_number);
		}
		break;

	case IP_FW_ZERO:
	case IP_FW_RESETLOG:
	    {
		int cmd = (sopt->sopt_name == IP_FW_RESETLOG );
		void *arg = NULL ;

		if (sopt->sopt_val != 0) {
		    error = sooptcopyin(sopt, &frwl, sizeof frwl, sizeof frwl);
		    if (error)
			break;
		    arg = &frwl ;
		}
		error = zero_entry(arg, cmd);
	    }
	    break;

	default:
		printf("ip_fw_ctl invalid option %d\n", sopt->sopt_name);
		error = EINVAL ;
	}

	return (error);
}

/**
 * dummynet needs a reference to the default rule, because rules can
 * be deleted while packets hold a reference to them (e.g. to resume
 * processing at the next rule). When this happens, dummynet changes
 * the reference to the default rule (probably it could well be a
 * NULL pointer, but this way we do not need to check for the special
 * case, plus here he have info on the default behaviour.
 */
struct ip_fw *ip_fw_default_rule ;

void
ip_fw_init(void)
{
	struct ip_fw default_rule;

	ip_fw_chk_ptr = ip_fw_chk;
	ip_fw_ctl_ptr = ip_fw_ctl;
	LIST_INIT(&ip_fw_chain_head);

	bzero(&default_rule, sizeof default_rule);
	default_rule.fw_prot = IPPROTO_IP;
	default_rule.fw_number = IPFW_DEFAULT_RULE;
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
	default_rule.fw_flg |= IP_FW_F_ACCEPT;
#else
	default_rule.fw_flg |= IP_FW_F_DENY;
#endif
	default_rule.fw_flg |= IP_FW_F_IN | IP_FW_F_OUT;
	if (check_ipfw_struct(&default_rule) != 0 ||
	    add_entry(&ip_fw_chain_head, &default_rule))
		panic("ip_fw_init");

	ip_fw_default_rule = LIST_FIRST(&ip_fw_chain_head) ;
	printf("IP packet filtering initialized, "
#ifdef IPDIVERT
		"divert enabled, "
#else
		"divert disabled, "
#endif
		"rule-based forwarding enabled, "
#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
		"default to accept, ");
#else
		"default to deny, " );
#endif
#ifndef IPFIREWALL_VERBOSE
	printf("logging disabled\n");
#else
	if (fw_verbose_limit == 0)
		printf("unlimited logging\n");
	else
		printf("logging limited to %d packets/entry by default\n",
		    fw_verbose_limit);
#endif
}

static int
ipfw_modevent(module_t mod, int type, void *unused)
{
	int s;
	int err = 0 ;
#if defined(KLD_MODULE)
	struct ip_fw *fcp;
#endif
	
	switch (type) {
	case MOD_LOAD:
#ifndef _WIN32
		s = splimp();
#endif
		if (IPFW_LOADED) {
#ifndef _WIN32
			splx(s);
#endif
			printf("IP firewall already loaded\n");
			err = EEXIST ;
		} else {
			ip_fw_init();
#ifndef _WIN32
			splx(s);
#endif
		}
		break ;
	case MOD_UNLOAD:
#if !defined(KLD_MODULE)
		printf("ipfw statically compiled, cannot unload\n");
		err = EBUSY;
#else
		s = splimp();
		ip_fw_chk_ptr = NULL ;
		ip_fw_ctl_ptr = NULL ;
		while ( (fcp = LIST_FIRST(&ip_fw_chain_head)) != NULL)
			free_chain(fcp);
		splx(s);
		printf("IP firewall unloaded\n");
#endif
		break ;

	default:
		break;
	}
	return err;
}

static moduledata_t ipfwmod = {
	"ipfw",
	ipfw_modevent,
	0
};
DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PSEUDO, SI_ORDER_ANY);
#endif /* !IPFW2 */

⌨️ 快捷键说明

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