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

📄 ip_fw.c.svn-base

📁 wipfw 是windows下的网络控制工具
💻 SVN-BASE
📖 第 1 页 / 共 5 页
字号:
	r->parent = parent ;
	rule = parent->rule;
    }

    r->id = *id ;
    r->expire = time_second + dyn_syn_lifetime ;
    r->rule = rule ;
    r->dyn_type = dyn_type ;
    r->pcnt = r->bcnt = 0 ;
    r->count = 0 ;

    r->bucket = i ;
    r->next = ipfw_dyn_v[i] ;
    ipfw_dyn_v[i] = r ;
    dyn_count++ ;
    DEB(printf("-- add entry 0x%08x %d -> 0x%08x %d, total %d\n",
       (r->id.src_ip), (r->id.src_port),
       (r->id.dst_ip), (r->id.dst_port),
       dyn_count ); )
    return r;
}

/**
 * lookup dynamic parent rule using pkt and rule as search keys.
 * If the lookup fails, then install one.
 */
static struct ipfw_dyn_rule *
lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
{
    struct ipfw_dyn_rule *q;
    int i;

    if (ipfw_dyn_v) {
	i = hash_packet( pkt );
	for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
	    if (q->dyn_type == DYN_LIMIT_PARENT && rule == q->rule &&
		    pkt->proto == q->id.proto &&
		    pkt->src_ip == q->id.src_ip &&
		    pkt->dst_ip == q->id.dst_ip &&
		    pkt->src_port == q->id.src_port &&
		    pkt->dst_port == q->id.dst_port) {
		q->expire = time_second + dyn_short_lifetime ;
		DEB(printf("lookup_dyn_parent found 0x%p\n", q);)
		return q;
	    }
    }
    return add_dyn_rule(pkt, DYN_LIMIT_PARENT, rule);
}

/*
 * Install dynamic state.
 * There are different types of dynamic rules which can be installed.
 * The type is in rule->dyn_type.
 * Type 0 (default) is a bidirectional rule
 *
 * Returns 1 (failure) if state is not installed because of errors or because
 * session limitations are enforced.
 */
static int
install_state(struct ip_fw *rule, struct ip_fw_args *args)
{
    struct ipfw_dyn_rule *q ;
    static int last_log ;

    u_int8_t type = rule->dyn_type ;

    DEB(printf("-- install state type %d 0x%08x %u -> 0x%08x %u\n",
       type,
       (args->f_id.src_ip), (args->f_id.src_port),
       (args->f_id.dst_ip), (args->f_id.dst_port) );)

    q = lookup_dyn_rule(&args->f_id, NULL) ;
    if (q != NULL) { /* should never occur */
	if (last_log != time_second) {
	    last_log = time_second ;
	    printf(" entry already present, done\n");
	}
	return 0 ;
    }
    if (dyn_count >= dyn_max) /* try remove old ones... */
	EXPIRE_DYN_CHAINS();
    if (dyn_count >= dyn_max) {
	if (last_log != time_second) {
	    last_log = time_second ;
	    printf(" Too many dynamic rules, sorry\n");
	}
	return 1; /* cannot install, notify caller */
    }

    switch (type) {
    case DYN_KEEP_STATE: /* bidir rule */
	add_dyn_rule(&args->f_id, DYN_KEEP_STATE, rule);
	break ;
    case DYN_LIMIT: /* limit number of sessions */
	{
	u_int16_t limit_mask = rule->limit_mask ;
	u_int16_t conn_limit = rule->conn_limit ;
	struct ipfw_flow_id id;
	struct ipfw_dyn_rule *parent;

	DEB(printf("installing dyn-limit rule %d\n", conn_limit);)

	id.dst_ip = id.src_ip = 0;
	id.dst_port = id.src_port = 0 ;
	id.proto = args->f_id.proto ;

	if (limit_mask & DYN_SRC_ADDR)
	    id.src_ip = args->f_id.src_ip;
	if (limit_mask & DYN_DST_ADDR)
	    id.dst_ip = args->f_id.dst_ip;
	if (limit_mask & DYN_SRC_PORT)
	    id.src_port = args->f_id.src_port;
	if (limit_mask & DYN_DST_PORT)
	    id.dst_port = args->f_id.dst_port;
	parent = lookup_dyn_parent(&id, rule);
	if (parent == NULL) {
	    printf("add parent failed\n");
	    return 1;
	}
	if (parent->count >= conn_limit) {
	    EXPIRE_DYN_CHAIN(rule); /* try to expire some */
	    /*
	     * The expiry might have removed the parent too.
	     * We lookup again, which will re-create if necessary.
	     */
	    parent = lookup_dyn_parent(&id, rule);
	    if (parent == NULL) {
		printf("add parent failed\n");
		return 1;
	    }
	    if (parent->count >= conn_limit) {
		if (fw_verbose && last_log != time_second) {
			last_log = time_second;
			log(LOG_SECURITY | LOG_DEBUG,
			    "drop session, too many entries\n");
		}
		return 1;
	    }
	}
	add_dyn_rule(&args->f_id, DYN_LIMIT, (struct ip_fw *)parent);
	}
	break ;
    default:
	printf("unknown dynamic rule type %u\n", type);
	return 1 ;
    }
    lookup_dyn_rule(&args->f_id, NULL) ; /* XXX just set the lifetime */
    return 0;
}

/*
 * given an ip_fw *, lookup_next_rule will return a pointer
 * of the same type to the next one. This can be either the jump
 * target (for skipto instructions) or the next one in the list (in
 * all other cases including a missing jump target).
 * Backward jumps are not allowed, so start looking from the next
 * rule...
 */ 
static struct ip_fw * lookup_next_rule(struct ip_fw *me);

static struct ip_fw *
lookup_next_rule(struct ip_fw *me)
{
    struct ip_fw *rule ;
    int rulenum = me->fw_skipto_rule ; /* guess... */

    if ( (me->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_SKIPTO )
	for (rule = LIST_NEXT(me,next); rule ; rule = LIST_NEXT(rule,next))
	    if (rule->fw_number >= rulenum)
		return rule ;
    return LIST_NEXT(me,next) ; /* failure or not a skipto */
}

/*
 * Parameters:
 *
 *	*m	The packet; we set to NULL when/if we nuke it.
 *	oif	Outgoing interface, or NULL if packet is incoming
 *	*cookie Skip up to the first rule past this rule number;
 *		upon return, non-zero port number for divert or tee.
 *		Special case: cookie == NULL on input for bridging.
 *	*flow_id pointer to the last matching rule (in/out)
 *	*next_hop socket we are forwarding to (in/out).
 *
 * Return value:
 *
 *	IP_FW_PORT_DENY_FLAG	the packet must be dropped.
 *	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, with these caveats:
 *
 *		- If IP_FW_PORT_TEE_FLAG is set, tee the packet instead
 *		  of diverting it (ie, 'ipfw tee').
 *
 *		- If IP_FW_PORT_DYNT_FLAG is set, interpret the lower
 *		  16 bits as a dummynet pipe number instead of diverting
 */

static int 
ip_fw_chk(struct ip_fw_args *args)
{
	/*
	 * grab things into variables to minimize diffs.
	 * XXX this has to be cleaned up later.
	 */
	struct mbuf **m = &(args->m);
	struct ifnet *oif = args->oif;
	u_int16_t *cookie = &(args->divert_rule);
	struct ip_fw **flow_id = &(args->rule);
	struct sockaddr_in **next_hop = &(args->next_hop);

	struct ip_fw *f = NULL;		/* matching rule */
	struct ip *ip = mtod(*m, struct ip *);
	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
	struct ifnet *tif;
	u_int hlen = 0;

	u_short ip_off=0, offset = 0;
	/* local copy of addresses for faster matching */
	u_short src_port = 0, dst_port = 0;
	struct in_addr src_ip, dst_ip;
	u_int8_t proto= 0, flags = 0;
	u_int16_t skipto;
	u_int16_t ip_len=0;

	int dyn_checked = 0 ; /* set after dyn.rules have been checked. */
	int direction = MATCH_FORWARD ; /* dirty trick... */
	struct ipfw_dyn_rule *q = NULL ;

	/* Special hack for bridging (as usual) */
#define BRIDGED		(args->eh != NULL)
	if (BRIDGED) {	/* this is a bridged packet */
		if ( (*m)->m_pkthdr.len >= sizeof(struct ip) &&
			    ntohs(args->eh->ether_type) == ETHERTYPE_IP)
			hlen = ip->ip_hl << 2;
		else
			return 0; /* XXX ipfw1 always accepts non-ip pkts */
	} else
		hlen = ip->ip_hl << 2;

	/* Grab and reset cookie */
	skipto = *cookie;
	*cookie = 0;

#define PULLUP_TO(len)	do {						\
			    if ((*m)->m_len < (len)) {			\
				if ((*m = m_pullup(*m, (len))) == 0)	\
				    goto bogusfrag;			\
				ip = mtod(*m, struct ip *);		\
			    }						\
			} while (0)

    if (hlen > 0) { /* this is an IP packet */
	/*
	 * Collect parameters into local variables for faster matching.
	 */
	proto = ip->ip_p;
	src_ip = ip->ip_src;
	dst_ip = ip->ip_dst;
#ifndef _WIN32          /* on Windows all incoming packets are as on the wire */
	if (BRIDGED) { /* bridged packets are as on the wire */
#endif
	    ip_off = ntohs(ip->ip_off);
	    ip_len = ntohs(ip->ip_len);
#ifndef _WIN32
	} else {
	    ip_off = ip->ip_off;
	    ip_len = ip->ip_len;
	}
#endif
	offset = ip_off & IP_OFFMASK;
	if (offset == 0) {
	    switch (proto) {
	    case IPPROTO_TCP : {
		struct tcphdr *tcp;

		PULLUP_TO(hlen + sizeof(struct tcphdr));
		tcp =(struct tcphdr *)((u_int32_t *)ip + ip->ip_hl);
		dst_port = tcp->th_dport ;
		src_port = tcp->th_sport ;
		flags = tcp->th_flags ;
		}
		break ;

	    case IPPROTO_UDP : {
		struct udphdr *udp;

		PULLUP_TO(hlen + sizeof(struct udphdr));
		udp =(struct udphdr *)((u_int32_t *)ip + ip->ip_hl);
		dst_port = udp->uh_dport ;
		src_port = udp->uh_sport ;
		}
		break;

	    case IPPROTO_ICMP:
		PULLUP_TO(hlen + 4);	/* type, code and checksum. */
		flags = ((struct icmp *)
			((u_int32_t *)ip + ip->ip_hl))->icmp_type ;
		break ;

	    default :
		break;
	    }
	}
    }
#undef PULLUP_TO
	args->f_id.src_ip = ntohl(src_ip.s_addr);
	args->f_id.dst_ip = ntohl(dst_ip.s_addr);
	args->f_id.proto = proto;
	args->f_id.src_port = ntohs(src_port);
	args->f_id.dst_port = ntohs(dst_port);
	args->f_id.flags = flags;

	if (*flow_id) {
	    /*
	     * Packet has already been tagged. Look for the next rule
	     * to restart processing.
	     */
	    if (fw_one_pass) /* just accept if fw_one_pass is set */
		return 0;

	    f = (*flow_id)->next_rule_ptr ;
	    if (f == NULL)
		f = (*flow_id)->next_rule_ptr = lookup_next_rule(*flow_id);
	    if (f == NULL)
		goto dropit;
	} else {
	    /*
	     * Go down the list, looking for enlightment.
	     * If we've been asked to start at a given rule, do so.
	     */
	    f = LIST_FIRST(&ip_fw_chain_head);
	    if (skipto != 0) {
		if (skipto >= IPFW_DEFAULT_RULE)
		    goto dropit;
		while (f && f->fw_number <= skipto)
		    f = LIST_NEXT(f, next);
		if (f == NULL)
		    goto dropit;
	    }
	}

	for (; f; f = LIST_NEXT(f, next)) {
again:
		if (f->fw_number == IPFW_DEFAULT_RULE)
		    goto got_match ;

		/*
		 * dynamic rules are checked at the first keep-state or
		 * check-state occurrence.
		 */
		if (f->fw_flg & (IP_FW_F_KEEP_S|IP_FW_F_CHECK_S) &&
			 dyn_checked == 0 ) {
		    dyn_checked = 1 ;
		    q = lookup_dyn_rule(&args->f_id, &direction);
		    if (q != NULL) {
			DEB(printf("-- dynamic match 0x%08x %d %s 0x%08x %d\n",
			    (q->id.src_ip), (q->id.src_port),
			    (direction == MATCH_FORWARD ? "-->" : "<--"),
			    (q->id.dst_ip), (q->id.dst_port) ); )
			f = q->rule ;
			q->pcnt++ ;
			q->bcnt += ip_len;
			goto got_match ; /* random not allowed here */
		    }
		    /* if this was a check-only rule, continue with next */
		    if (f->fw_flg & IP_FW_F_CHECK_S)
			continue ;
		}

		/* Check if rule only valid for bridged packets */
		if ((f->fw_flg & IP_FW_BRIDGED) != 0 && !(BRIDGED))
			continue;

		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;
		}

		/* Fragments */
		if ((f->fw_flg & IP_FW_F_FRAG) && offset == 0 )
			continue;

		if (f->fw_flg & IP_FW_F_SME) {
			INADDR_TO_IFP(src_ip, tif);
			if (tif == NULL)
				continue;
		}
		if (f->fw_flg & IP_FW_F_DME) {
			INADDR_TO_IFP(dst_ip, tif);
			if (tif == NULL)
				continue;
		}
		/* If src-addr doesn't match, not this rule. */
		if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((src_ip.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) ^ ((dst_ip.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, and no [ug]id, match */
		if (f->fw_prot == IPPROTO_IP) {
			if (!(f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)))
				goto rnd_then_got_match;
		} else
		    /* If different, don't match */
		    if (proto != f->fw_prot) 
			    continue;

⌨️ 快捷键说明

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