示例#1
0
static inline int
ip_output_pfil(struct mbuf **mp, struct ifnet *ifp, struct inpcb *inp,
    struct sockaddr_in *dst, int *fibnum, int *error)
{
	struct m_tag *fwd_tag = NULL;
	struct mbuf *m;
	struct in_addr odst;
	struct ip *ip;

	m = *mp;
	ip = mtod(m, struct ip *);

	/* Run through list of hooks for output packets. */
	odst.s_addr = ip->ip_dst.s_addr;
	*error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp, PFIL_OUT, inp);
	m = *mp;
	if ((*error) != 0 || m == NULL)
		return 1; /* Finished */

	ip = mtod(m, struct ip *);

	/* See if destination IP address was changed by packet filter. */
	if (odst.s_addr != ip->ip_dst.s_addr) {
		m->m_flags |= M_SKIP_FIREWALL;
		/* If destination is now ourself drop to ip_input(). */
		if (in_localip(ip->ip_dst)) {
			m->m_flags |= M_FASTFWD_OURS;
			if (m->m_pkthdr.rcvif == NULL)
				m->m_pkthdr.rcvif = V_loif;
			if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
				m->m_pkthdr.csum_flags |=
					CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
				m->m_pkthdr.csum_data = 0xffff;
			}
			m->m_pkthdr.csum_flags |=
				CSUM_IP_CHECKED | CSUM_IP_VALID;
#ifdef SCTP
			if (m->m_pkthdr.csum_flags & CSUM_SCTP)
				m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
#endif
			*error = netisr_queue(NETISR_IP, m);
			return 1; /* Finished */
		}

		bzero(dst, sizeof(*dst));
		dst->sin_family = AF_INET;
		dst->sin_len = sizeof(*dst);
		dst->sin_addr = ip->ip_dst;

		return -1; /* Reloop */
	}
	/* See if fib was changed by packet filter. */
	if ((*fibnum) != M_GETFIB(m)) {
		m->m_flags |= M_SKIP_FIREWALL;
		*fibnum = M_GETFIB(m);
		return -1; /* Reloop for FIB change */
	}

	/* See if local, if yes, send it to netisr with IP_FASTFWD_OURS. */
	if (m->m_flags & M_FASTFWD_OURS) {
		if (m->m_pkthdr.rcvif == NULL)
			m->m_pkthdr.rcvif = V_loif;
		if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
			m->m_pkthdr.csum_flags |=
				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
			m->m_pkthdr.csum_data = 0xffff;
		}
#ifdef SCTP
		if (m->m_pkthdr.csum_flags & CSUM_SCTP)
			m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
#endif
		m->m_pkthdr.csum_flags |=
			CSUM_IP_CHECKED | CSUM_IP_VALID;

		*error = netisr_queue(NETISR_IP, m);
		return 1; /* Finished */
	}
	/* Or forward to some other address? */
	if ((m->m_flags & M_IP_NEXTHOP) &&
	    ((fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL)) {
		bcopy((fwd_tag+1), dst, sizeof(struct sockaddr_in));
		m->m_flags |= M_SKIP_FIREWALL;
		m->m_flags &= ~M_IP_NEXTHOP;
		m_tag_delete(m, fwd_tag);

		return -1; /* Reloop for CHANGE of dst */
	}

	return 0;
}
示例#2
0
int
ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
    struct inpcb *inp)
{
	struct ip_fw_args args;
	struct m_tag *dn_tag;
	int ipfw = 0;
	int divert;
#ifdef IPFIREWALL_FORWARD
	struct m_tag *fwd_tag;
#endif

	KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));

	if (!fw_enable)
		goto pass;

	bzero(&args, sizeof(args));

	dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
	if (dn_tag != NULL){
		struct dn_pkt_tag *dt;

		dt = (struct dn_pkt_tag *)(dn_tag+1);
		args.rule = dt->rule;

		m_tag_delete(*m0, dn_tag);
	}

again:
	args.m = *m0;
	args.inp = inp;
	ipfw = ipfw_chk(&args);
	*m0 = args.m;

	if ((ipfw & IP_FW_PORT_DENY_FLAG) || *m0 == NULL)
		goto drop;

	if (ipfw == 0 && args.next_hop == NULL)
		goto pass;

	if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
		ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args);
		*m0 = NULL;
		return 0;		/* packet consumed */
	}

	if (ipfw != 0 && (ipfw & IP_FW_PORT_DYNT_FLAG) == 0) {
		if ((ipfw & IP_FW_PORT_TEE_FLAG) != 0)
			divert = ipfw_divert(m0, DIV_DIR_IN, 1);
		else
			divert = ipfw_divert(m0, DIV_DIR_IN, 0);

		/* tee should continue again with the firewall. */
		if (divert) {
			*m0 = NULL;
			return 0;	/* packet consumed */
		} else
			goto again;	/* continue with packet */
	}

#ifdef IPFIREWALL_FORWARD
	if (ipfw == 0 && args.next_hop != NULL) {
		fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
				sizeof(struct sockaddr_in), M_NOWAIT);
		if (fwd_tag == NULL)
			goto drop;
		bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
		m_tag_prepend(*m0, fwd_tag);

		if (in_localip(args.next_hop->sin_addr))
			(*m0)->m_flags |= M_FASTFWD_OURS;
		goto pass;
	}
#endif

drop:
	if (*m0)
		m_freem(*m0);
	*m0 = NULL;
	return (EACCES);
pass:
	return 0;	/* not filtered */
}