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

📄 ip_fw.c.svn-base

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

#ifndef _WIN32          /* (no uid/gid checks for now) */

		/* Protocol specific checks for uid only */
		if (f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)) {
		    switch (proto) {
		    case IPPROTO_TCP:
			{
			    struct inpcb *P;

			    if (offset == 1)	/* cf. RFC 1858 */
				    goto bogusfrag;
			    if (offset != 0)
				    continue;

			    if (oif)
				P = in_pcblookup_hash(&tcbinfo, dst_ip,
				   dst_port, src_ip, src_port, 0,
				   oif);
			    else
				P = in_pcblookup_hash(&tcbinfo, src_ip,
				   src_port, dst_ip, dst_port, 0,
				   NULL);

			    if (P && P->inp_socket) {
				if (f->fw_flg & IP_FW_F_UID) {
					if (P->inp_socket->so_cred->cr_uid !=
					    f->fw_uid)
						continue;
				} else if (!groupmember(f->fw_gid,
					    P->inp_socket->so_cred))
						continue;
			    } else
				continue;
			    break;
			}

		    case IPPROTO_UDP:
			{
			    struct inpcb *P;

			    if (offset != 0)
				continue;

			    if (oif)
				P = in_pcblookup_hash(&udbinfo, dst_ip,
				   dst_port, src_ip, src_port, 1,
				   oif);
			    else
				P = in_pcblookup_hash(&udbinfo, src_ip,
				   src_port, dst_ip, dst_port, 1,
				   NULL);

			    if (P && P->inp_socket) {
				if (f->fw_flg & IP_FW_F_UID) {
					if (P->inp_socket->so_cred->cr_uid !=
					    f->fw_uid)
						continue;
				} else if (!groupmember(f->fw_gid,
					    P->inp_socket->so_cred))
						continue;
			    } else
				continue;
			    break;
			}

		    default:
			    continue;
		    }
		}

#endif  /* _WIN32 */
		    
		/* Protocol specific checks */
		switch (proto) {
		case IPPROTO_TCP:
		    {
			struct tcphdr *tcp;

			if (offset == 1)	/* cf. RFC 1858 */
				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 (IP_FW_HAVEPORTS(f) != 0 ||
				    f->fw_tcpopt != f->fw_tcpnopt ||
				    f->fw_tcpf != f->fw_tcpnf)
					continue;

				break;
			}
			tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);

			if (f->fw_tcpopt != f->fw_tcpnopt && !tcpopts_match(tcp, f))
				continue;
			if (((f->fw_tcpf != f->fw_tcpnf) ||
			    (f->fw_ipflg & IP_FW_IF_TCPEST)) &&
			    !tcpflg_match(tcp, f))
				continue;
			goto check_ports;
		    }

		case IPPROTO_UDP:
			if (offset != 0) {
				/*
				 * Port specification is unavailable -- if this
				 * rule specifies a port, we consider the rule
				 * a non-match.
				 */
				if (IP_FW_HAVEPORTS(f) )
					continue;

				break;
			}
check_ports:
			if (!port_match(&f->fw_uar.fw_pts[0],
			    IP_FW_GETNSRCP(f), ntohs(src_port),
			    f->fw_flg & IP_FW_F_SRNG,
			    f->fw_flg & IP_FW_F_SMSK))
				continue;
			if (!port_match(&f->fw_uar.fw_pts[IP_FW_GETNSRCP(f)],
			    IP_FW_GETNDSTP(f), ntohs(dst_port),
			    f->fw_flg & IP_FW_F_DRNG,
			    f->fw_flg & IP_FW_F_DMSK)) 
				continue;
			break;

		case IPPROTO_ICMP:
		    {
			struct icmp *icmp;

			if (offset != 0)	/* Type isn't valid */
				break;
			icmp = (struct icmp *) ((u_int32_t *)ip + ip->ip_hl);
			if (!icmptype_match(icmp, f))
				continue;
			break;
		    }

		default:
			break;

bogusfrag:
		if (fw_verbose) {
			if (m != NULL)
				ipfw_report(NULL, ip, ip_off, ip_len, rif, oif);
			else
				printf("pullup failed\n");
		}
		goto dropit;

		}

rnd_then_got_match:
		if ( f->dont_match_prob && random() < f->dont_match_prob )
			continue ;
got_match:
		/*
		 * If not a dynamic match (q == NULL) and keep-state, install
		 * a new dynamic entry.
		 */
		if (q == NULL && f->fw_flg & IP_FW_F_KEEP_S) {
		    if (install_state(f, args)) /* error or limit violation */
			goto dropit;
		}
		/* Update statistics */
		f->fw_pcnt += 1;
		f->fw_bcnt += ip_len;
		f->timestamp = time_second;

		/* Log to console if desired */
		if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose && hlen > 0)
			ipfw_report(f, ip, offset, ip_len, rif, oif);

		/* Take appropriate action */
		switch (f->fw_flg & IP_FW_F_COMMAND) {
		case IP_FW_F_ACCEPT:
			return(0);
		case IP_FW_F_COUNT:
			continue;
#ifdef IPDIVERT
		case IP_FW_F_DIVERT:
			*cookie = f->fw_number;
			return(f->fw_divert_port);
		case IP_FW_F_TEE:
			*cookie = f->fw_number;
			return(f->fw_divert_port | IP_FW_PORT_TEE_FLAG);
#endif
		case IP_FW_F_SKIPTO: /* XXX check */
			if (f->next_rule_ptr == NULL)
			    f->next_rule_ptr = lookup_next_rule(f) ;
			f = f->next_rule_ptr;
			if (!f)
			    goto dropit;
			goto again ;

		case IP_FW_F_PIPE:
		case IP_FW_F_QUEUE:
			*flow_id = f ; /* XXX set flow id */
			return(f->fw_pipe_nr | IP_FW_PORT_DYNT_FLAG);

		case IP_FW_F_FWD:
			/* Change the next-hop address for this packet.
			 * Initially we'll only worry about directly
			 * reachable next-hop's, but ultimately
			 * we will work out for next-hops that aren't
			 * direct the route we would take for it. We
			 * [cs]ould leave this latter problem to
			 * ip_output.c. We hope to high [name the abode of
			 * your favourite deity] that ip_output doesn't modify
			 * the new value of next_hop (which is dst there)
			 * XXX warning-- there is a dangerous reference here
			 * from next_hop to a field within the rule. If the
			 * rule is deleted, weird things might occur.
			 */
			if (next_hop != NULL /* Make sure, first... */
			    && (q == NULL || direction == MATCH_FORWARD) )
				*next_hop = &(f->fw_fwd_ip);
			return(0); /* Allow the packet */

		}

		/* Deny/reject this packet using this rule */
		break;
	}

	/* Rule IPFW_DEFAULT_RULE should always be there and match */
	KASSERT(f != NULL, ("ip_fw: no chain"));

	/*
	 * 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 ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
	    && (proto != IPPROTO_ICMP || is_icmp_query(ip))
	    && !((*m)->m_flags & (M_BCAST|M_MCAST))
	    && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
		/* Must convert to host order for icmp_error() etc. */
#ifndef _WIN32
		if (BRIDGED) {
#endif
			ip->ip_len = ntohs(ip->ip_len);
			ip->ip_off = ntohs(ip->ip_off);
#ifndef _WIN32
		}
#endif
		switch (f->fw_reject_code) {
		case IP_FW_REJECT_RST:
		  {
			/* XXX warning, this code writes into the mbuf */
			struct tcphdr *const tcp =
				(struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
			struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;

			if (offset != 0 || (tcp->th_flags & TH_RST))
				break;
			ti.ti_i = *((struct ipovly *) ip);
			ti.ti_t = *tcp;
			bcopy(&ti, ip, sizeof(ti));
			NTOHL(tip->ti_seq);
			NTOHL(tip->ti_ack);
			tip->ti_len = ip_len - hlen - (tip->ti_off << 2);
			if (tcp->th_flags & TH_ACK) {
				tcp_respond(NULL, (void *)ip, tcp, *m,
				    (tcp_seq)0, tcp->th_ack, TH_RST);
			} else {
				if (tcp->th_flags & TH_SYN)
					tip->ti_len++;
				tcp_respond(NULL, (void *)ip, tcp, *m, 
				    tip->ti_seq + tip->ti_len,
				    (tcp_seq)0, TH_RST|TH_ACK);
			}
			*m = NULL;
			break;
		  }
		default:	/* Send an ICMP unreachable using code */
			icmp_error(*m, ICMP_UNREACH,
			    f->fw_reject_code, 0L, 0);
			*m = NULL;
			break;
		}
	}

dropit:
	/*
	 * Finally, drop the packet.
	 */
	return(IP_FW_PORT_DENY_FLAG);
#undef BRIDGED
}

/*
 * when a rule is added/deleted, zero the direct pointers within
 * all firewall rules. These will be reconstructed on the fly
 * as packets are matched.
 * Must be called at splimp().
 */
static void
flush_rule_ptrs()
{
    struct ip_fw *fcp ;

    LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
	fcp->next_rule_ptr = NULL ;
    }
}

void
flush_pipe_ptrs(struct dn_flow_set *match)
{
    struct ip_fw *fcp ;

    LIST_FOREACH(fcp, &ip_fw_chain_head, next) {
	if (match == NULL || fcp->pipe_ptr == match)
		fcp->pipe_ptr = NULL;
    }
}

static int
add_entry(struct ip_fw_head *head, struct ip_fw *rule)
{
	struct ip_fw *ftmp, *fcp, *fcpl;
	u_short nbr = 0;
	int s;

	ftmp = malloc(sizeof *ftmp, M_IPFW, M_DONTWAIT | M_ZERO);
	if (!ftmp)
		return (ENOSPC);
	bcopy(rule, ftmp, sizeof(*ftmp));

	ftmp->fw_in_if.fu_via_if.name[FW_IFNLEN - 1] = '\0';
	ftmp->fw_pcnt = 0L;
	ftmp->fw_bcnt = 0L;
	ftmp->next_rule_ptr = NULL ;
	ftmp->pipe_ptr = NULL ;
	
	s = splimp();

	if (LIST_FIRST(head) == 0) {
		LIST_INSERT_HEAD(head, ftmp, next);
		goto done;
        }

	/* If entry number is 0, find highest numbered rule and add 100 */
	if (ftmp->fw_number == 0) {
		LIST_FOREACH(fcp, head, next) {
			if (fcp->fw_number != IPFW_DEFAULT_RULE)
				nbr = fcp->fw_number;
			else
				break;
		}
		if (nbr < IPFW_DEFAULT_RULE - 100)
			nbr += 100;
		ftmp->fw_number = rule->fw_number = nbr;
	}

	/* Got a valid number; now insert it, keeping the list ordered */
	fcpl = NULL ;
	LIST_FOREACH(fcp, head, next) {
		if (fcp->fw_number > ftmp->fw_number) {
			if (fcpl) {
				LIST_INSERT_AFTER(fcpl, ftmp, next);
			} else {
				LIST_INSERT_HEAD(head, ftmp, next);
			}
			break;
		} else {
			fcpl = fcp;
		}
	}
	flush_rule_ptrs();
done:
	static_count++;
	splx(s);
	DEB(printf("++ installed rule %d, static count now %d\n",
		ftmp->fw_number, static_count);)
	return (0);
}

/**
 * free storage associated with a static rule entry (including
 * dependent dynamic rules), and zeroes rule pointers to avoid
 * dangling pointer dereferences.
 * @return a pointer to the next entry.
 * Must be called at splimp() and with a non-null argument.
 */
static struct ip_fw *
free_chain(struct ip_fw *fcp)
{
    struct ip_fw *n;

    n = LIST_NEXT(fcp, next);
    DELETE_DYN_CHAIN(fcp);
    LIST_REMOVE(fcp, next);
    static_count--;
    if (DUMMYNET_LOADED)
	ip_dn_ruledel_ptr(fcp) ;
    flush_rule_ptrs(); /* more efficient to do outside the loop */
    free(fcp, M_IPFW);
    return n;
}

/**
 * remove all rules with given number.
 */
static int
del_entry(struct ip_fw_head *chainptr, u_short number)
{
    struct ip_fw *rule;

    if (number != IPFW_DEFAULT_RULE) {
	LIST_FOREACH(rule, chainptr, next) {
	    if (rule->fw_number == number) {
		int s ;

		s = splimp(); /* prevent access to rules while removing */
		while (rule && rule->fw_number == number)
		    rule = free_chain(rule);
		/* XXX could move flush_rule_ptrs() here */
		splx(s);
		return 0 ;
	    }
	}
    }
    return (EINVAL);
}

/**
 * Reset some or all counters on firewall rules.
 * @arg frwl is null to clear all entries, or contains a specific
 * rule number.
 * @arg log_only is 1 if we only want to reset logs, zero otherwise.
 */

static int

⌨️ 快捷键说明

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