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

📄 ip_fw.c.svn-base

📁 wipfw 是windows下的网络控制工具
💻 SVN-BASE
📖 第 1 页 / 共 5 页
字号:

		case TCPOPT_CC:
		case TCPOPT_CCNEW:
		case TCPOPT_CCECHO:
			opts &= ~IP_FW_TCPOPT_CC;
			nopts &= ~IP_FW_TCPOPT_CC;
			break;
		}
		if (opts == nopts)
			break;
	}
	if (opts == 0 && nopts == nopts_sve)
		return 1;
	else
		return 0;
}

static int
iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
{
	/* Check by name or by IP address */
	if (byname) {
		/* Check unit number (-1 is wildcard) */
		if (ifu->fu_via_if.unit != -1
		    && ifp->if_unit != ifu->fu_via_if.unit)
			return(0);
		/* Check name */
		if (strncmp(ifp->if_name, ifu->fu_via_if.name, FW_IFNLEN))
			return(0);
		return(1);
	} else if (ifu->fu_via_ip.s_addr != 0) {	/* Zero == wildcard */
		struct ifaddr *ia;

		TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) {
			if (ia->ifa_addr == NULL)
				continue;
			if (ia->ifa_addr->sa_family != AF_INET)
				continue;
			if (ifu->fu_via_ip.s_addr != ((struct sockaddr_in *)
			    (ia->ifa_addr))->sin_addr.s_addr)
				continue;
			return(1);
		}
		return(0);
	}
	return(1);
}

static void
ipfw_report(struct ip_fw *f, struct ip *ip, int ip_off, int ip_len,
	struct ifnet *rif, struct ifnet *oif)
{
    struct tcphdr *const tcp = (struct tcphdr *) ((u_int32_t *) ip+ ip->ip_hl);
    struct udphdr *const udp = (struct udphdr *) ((u_int32_t *) ip+ ip->ip_hl);
    struct icmp *const icmp = (struct icmp *) ((u_int32_t *) ip + ip->ip_hl);
    u_int64_t count;
    char *action;
    char action2[32], proto[47], name[18], fragment[27];
    int len;
    int offset = ip_off & IP_OFFMASK;
#ifdef _WIN32
    DECLARE_INET_NTOA_BUF;
#endif

    count = f ? f->fw_pcnt : ++counter;
    if ((f == NULL && fw_verbose_limit != 0 && count > fw_verbose_limit) ||
	(f && f->fw_logamount != 0 && count > f->fw_loghighest))
	    return;

    /* Print command name */
    snprintf(SNPARGS(name, 0), "ipfw: %d", f ? f->fw_number : -1);

    action = action2;
    if (!f)
	    action = "Refuse";
    else {
	    switch (f->fw_flg & IP_FW_F_COMMAND) {
	    case IP_FW_F_DENY:
		    action = "Deny";
		    break;
	    case IP_FW_F_REJECT:
		    if (f->fw_reject_code == IP_FW_REJECT_RST)
			    action = "Reset";
		    else
			    action = "Unreach";
		    break;
	    case IP_FW_F_ACCEPT:
		    action = "Accept";
		    break;
	    case IP_FW_F_COUNT:
		    action = "Count";
		    break;
#ifdef IPDIVERT
	    case IP_FW_F_DIVERT:
		    snprintf(SNPARGS(action2, 0), "Divert %d",
			f->fw_divert_port);
		    break;
	    case IP_FW_F_TEE:
		    snprintf(SNPARGS(action2, 0), "Tee %d",
			f->fw_divert_port);
		    break;
#endif
	    case IP_FW_F_SKIPTO:
		    snprintf(SNPARGS(action2, 0), "SkipTo %d",
			f->fw_skipto_rule);
		    break;
	    case IP_FW_F_PIPE:
		    snprintf(SNPARGS(action2, 0), "Pipe %d",
			f->fw_skipto_rule);
		    break;
	    case IP_FW_F_QUEUE:
		    snprintf(SNPARGS(action2, 0), "Queue %d",
			f->fw_skipto_rule);
		    break;

	    case IP_FW_F_FWD:
		    if (f->fw_fwd_ip.sin_port)
			    snprintf(SNPARGS(action2, 0),
				"Forward to %s:%d",
				inet_ntoa(f->fw_fwd_ip.sin_addr),
				f->fw_fwd_ip.sin_port);
		    else
			    snprintf(SNPARGS(action2, 0), "Forward to %s",
				inet_ntoa(f->fw_fwd_ip.sin_addr));
		    break;

	    default:	
		    action = "UNKNOWN";
		    break;
	    }
    }

    switch (ip->ip_p) {
    case IPPROTO_TCP:
	    len = snprintf(SNPARGS(proto, 0), "TCP %s",
		inet_ntoa(ip->ip_src));
	    if (offset == 0)
		    len += snprintf(SNPARGS(proto, len), ":%d ",
			ntohs(tcp->th_sport));
	    else
		    len += snprintf(SNPARGS(proto, len), " ");
	    len += snprintf(SNPARGS(proto, len), "%s",
		inet_ntoa(ip->ip_dst));
	    if (offset == 0)
		    snprintf(SNPARGS(proto, len), ":%d",
			ntohs(tcp->th_dport));
	    break;
    case IPPROTO_UDP:
	    len = snprintf(SNPARGS(proto, 0), "UDP %s",
		inet_ntoa(ip->ip_src));
	    if (offset == 0)
		    len += snprintf(SNPARGS(proto, len), ":%d ",
			ntohs(udp->uh_sport));
	    else
		    len += snprintf(SNPARGS(proto, len), " ");
	    len += snprintf(SNPARGS(proto, len), "%s",
		inet_ntoa(ip->ip_dst));
	    if (offset == 0)
		    snprintf(SNPARGS(proto, len), ":%d",
			ntohs(udp->uh_dport));
	    break;
    case IPPROTO_ICMP:
	    if (offset == 0)
		    len = snprintf(SNPARGS(proto, 0), "ICMP:%u.%u ",
			icmp->icmp_type, icmp->icmp_code);
	    else
		    len = snprintf(SNPARGS(proto, 0), "ICMP ");
	    len += snprintf(SNPARGS(proto, len), "%s",
		inet_ntoa(ip->ip_src));
	    snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst));
	    break;
    default:
	    len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p,
		inet_ntoa(ip->ip_src));
	    snprintf(SNPARGS(proto, len), " %s", inet_ntoa(ip->ip_dst));
	    break;
    }

    if (ip_off & (IP_MF | IP_OFFMASK))
	    snprintf(SNPARGS(fragment, 0), " (frag %d:%d@%d%s)",
		     ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2),
		     offset << 3,
		     (ip_off & IP_MF) ? "+" : "");
    else
	    fragment[0] = '\0';
    if (oif)
	    log(LOG_SECURITY | LOG_INFO, "%s %s %s out via %s%d%s\n",
		name, action, proto, oif->if_name, oif->if_unit, fragment);
    else if (rif)
	    log(LOG_SECURITY | LOG_INFO, "%s %s %s in via %s%d%s\n", name,
		action, proto, rif->if_name, rif->if_unit, fragment);
    else
	    log(LOG_SECURITY | LOG_INFO, "%s %s %s%s\n", name, action,
		proto, fragment);
    if ((f ? f->fw_logamount != 0 : 1) &&
	count == (f ? f->fw_loghighest : fw_verbose_limit))
	    log(LOG_SECURITY | LOG_NOTICE,
		"ipfw: limit %d reached on entry %d\n",
		f ? f->fw_logamount : fw_verbose_limit,
		f ? f->fw_number : -1);
}

static __inline int
hash_packet(struct ipfw_flow_id *id)
{
    u_int32_t i ;

    i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);
    i &= (curr_dyn_buckets - 1) ;
    return i ;
}

/**
 * unlink a dynamic rule from a chain. prev is a pointer to
 * the previous one, q is a pointer to the rule to delete,
 * head is a pointer to the head of the queue.
 * Modifies q and potentially also head.
 */
#define UNLINK_DYN_RULE(prev, head, q) {				\
	struct ipfw_dyn_rule *old_q = q;				\
									\
	/* remove a refcount to the parent */				\
	if (q->dyn_type == DYN_LIMIT)					\
		q->parent->count--;					\
	DEB(printf("-- unlink entry 0x%08x %d -> 0x%08x %d, %d left\n", \
		(q->id.src_ip), (q->id.src_port),			\
		(q->id.dst_ip), (q->id.dst_port), dyn_count-1 ); )	\
	if (prev != NULL)						\
		prev->next = q = q->next ;				\
	else								\
		ipfw_dyn_v[i] = q = q->next ;				\
	dyn_count-- ;							\
	free(old_q, M_IPFW); }

#define TIME_LEQ(a,b)       ((int)((a)-(b)) <= 0)
/**
 * Remove all dynamic rules pointing to a given rule, or all
 * rules if rule == NULL. Second parameter is 1 if we want to
 * delete unconditionally, otherwise only expired rules are removed.
 */
static void
remove_dyn_rule(struct ip_fw *rule, int force)
{
    struct ipfw_dyn_rule *prev, *q;
    int i, pass, max_pass ;
    static u_int32_t last_remove = 0 ;

    if (ipfw_dyn_v == NULL || dyn_count == 0)
	return ;
    /* do not expire more than once per second, it is useless */
    if (force == 0 && last_remove == time_second)
	return ;
    last_remove = time_second ;

    /*
     * because DYN_LIMIT refer to parent rules, during the first pass only
     * remove child and mark any pending LIMIT_PARENT, and remove
     * them in a second pass.
     */
  for (pass = max_pass = 0; pass <= max_pass ; pass++ ) {
    for (i = 0 ; i < curr_dyn_buckets ; i++) {
	for (prev=NULL, q = ipfw_dyn_v[i] ; q ; ) {
	    /*
	     * logic can become complex here, so we split tests.
	     * First, test if we match any rule,
	     * then make sure the rule is expired or we want to kill it,
	     * and possibly more in the future.
	     */
	    int zap = ( rule == NULL || rule == q->rule);
	    if (zap)
		zap = force || TIME_LEQ( q->expire , time_second );
	    /* do not zap parent in first pass, record we need a second pass */
	    if (zap && q->dyn_type == DYN_LIMIT_PARENT) {
		max_pass = 1; /* we need a second pass */
		if (pass == 0 || q->count != 0) {
		    zap = 0 ;
		    if (pass == 1 && force) /* should not happen */
			printf("OUCH! cannot remove rule, count %d\n",
				q->count);
		}
	    }
	    if (zap) {
		UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
	    } else {
		prev = q ;
		q = q->next ;
	    }
	}
    }
  }
}

#define EXPIRE_DYN_CHAIN(rule) remove_dyn_rule(rule, 0 /* expired ones */)
#define EXPIRE_DYN_CHAINS() remove_dyn_rule(NULL, 0 /* expired ones */)
#define DELETE_DYN_CHAIN(rule) remove_dyn_rule(rule, 1 /* force removal */)
#define DELETE_DYN_CHAINS() remove_dyn_rule(NULL, 1 /* force removal */)

/**
 * lookup a dynamic rule.
 */
static struct ipfw_dyn_rule *
lookup_dyn_rule(struct ipfw_flow_id *pkt, int *match_direction)
{
    /*
     * stateful ipfw extensions.
     * Lookup into dynamic session queue
     */
    struct ipfw_dyn_rule *prev, *q ;
    int i, dir = 0;
#define MATCH_FORWARD 1

    if (ipfw_dyn_v == NULL)
	return NULL ;
    i = hash_packet( pkt );
    for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) {
	if (q->dyn_type == DYN_LIMIT_PARENT)
	    goto next;
	if (TIME_LEQ( q->expire , time_second ) ) { /* expire entry */
	    UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
	    continue;
	}
	if ( pkt->proto == q->id.proto) {
	    if (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 ) {
		dir = MATCH_FORWARD ;
		goto found ;
	    }
	    if (pkt->src_ip == q->id.dst_ip &&
		    pkt->dst_ip == q->id.src_ip &&
		    pkt->src_port == q->id.dst_port &&
		    pkt->dst_port == q->id.src_port ) {
		dir = 0 ; /* reverse match */
		goto found ;
	    }
	}
next:
	prev = q ;
	q = q->next ;
    }
    return NULL ; /* clearly not found */
found:
    if ( prev != NULL) { /* found and not in front */
	prev->next = q->next ;
	q->next = ipfw_dyn_v[i] ;
	ipfw_dyn_v[i] = q ;
    }
    if (pkt->proto == IPPROTO_TCP) {
	/* update state according to flags */
	u_char flags = pkt->flags & (TH_FIN|TH_SYN|TH_RST);
	q->state |= (dir == MATCH_FORWARD ) ? flags : (flags << 8);
	switch (q->state) {
	case TH_SYN :
	    /* opening */
	    q->expire = time_second + dyn_syn_lifetime ;
	    break ;
	case TH_SYN | (TH_SYN << 8) :
	    /* move to established */
	    q->expire = time_second + dyn_ack_lifetime ;
	    break ;
	case TH_SYN | (TH_SYN << 8) | TH_FIN :
	case TH_SYN | (TH_SYN << 8) | (TH_FIN << 8) :
	    /* one side tries to close */
	    q->expire = time_second + dyn_ack_lifetime ;
	    break ;
	case TH_SYN | (TH_SYN << 8) | TH_FIN | (TH_FIN << 8) :
	    /* both sides closed */
	    q->expire = time_second + dyn_fin_lifetime ;
	    break ;
	default:
#if 0
	    /*
	     * reset or some invalid combination, but can also
	     * occur if we use keep-state the wrong way.
	     */
	    if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0)
		printf("invalid state: 0x%x\n", q->state);
#endif
	    q->expire = time_second + dyn_rst_lifetime ;
	    break ;
	}
    } else if (pkt->proto == IPPROTO_UDP) {
	q->expire = time_second + dyn_udp_lifetime ;
    } else {
	/* other protocols */
	q->expire = time_second + dyn_short_lifetime ;
    }
    if (match_direction)
	*match_direction = dir ;
    return q ;
}

/**
 * Install state of type 'type' for a dynamic session.
 * The hash table contains two type of rules:
 * - regular rules (DYN_KEEP_STATE)
 * - rules for sessions with limited number of sess per user
 *   (DYN_LIMIT). When they are created, the parent is
 *   increased by 1, and decreased on delete. In this case,
 *   the third parameter is the parent rule and not the chain.
 * - "parent" rules for the above (DYN_LIMIT_PARENT).
 */

static struct ipfw_dyn_rule *
add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule)
{
    struct ipfw_dyn_rule *r ;

    int i ;
    if (ipfw_dyn_v == NULL ||
		(dyn_count == 0 && dyn_buckets != curr_dyn_buckets)) {
	/* try reallocation, make sure we have a power of 2 */
	u_int32_t i = dyn_buckets ;
	while ( i > 0 && (i & 1) == 0 )
	    i >>= 1 ;
	if (i != 1) /* not a power of 2 */
	    dyn_buckets = curr_dyn_buckets ; /* reset */
	else {
	    curr_dyn_buckets = dyn_buckets ;
	    if (ipfw_dyn_v != NULL)
		free(ipfw_dyn_v, M_IPFW);
	    ipfw_dyn_v = malloc(curr_dyn_buckets * sizeof r,
                   M_IPFW, M_DONTWAIT | M_ZERO);
	    if (ipfw_dyn_v == NULL)
		return NULL; /* failed ! */
	}
    }
    i = hash_packet(id);

    r = malloc(sizeof *r, M_IPFW, M_DONTWAIT | M_ZERO);
    if (r == NULL) {
	printf ("sorry cannot allocate state\n");
	return NULL ;
    }

    /* increase refcount on parent, and set pointer */
    if (dyn_type == DYN_LIMIT) {
	struct ipfw_dyn_rule *parent = (struct ipfw_dyn_rule *)rule;
	if ( parent->dyn_type != DYN_LIMIT_PARENT)
	    panic("invalid parent");
	parent->count++ ;

⌨️ 快捷键说明

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