示例#1
0
/*
 * IP output.  The packet in mbuf chain m contains a skeletal IP
 * header (with len, off, ttl, proto, tos, src, dst).
 * The mbuf chain containing the packet will be freed.
 * The mbuf opt, if present, will not be freed.
 * If route ro is present and has ro_rt initialized, route lookup would be
 * skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL,
 * then result of route lookup is stored in ro->ro_rt.
 *
 * In the IP forwarding case, the packet will arrive with options already
 * inserted, so must have a NULL opt pointer.
 */
int
ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
    struct ip_moptions *imo, struct inpcb *inp)
{
	struct ip *ip;
	struct ifnet *ifp = NULL;	/* keep compiler happy */
	struct mbuf *m0;
	int hlen = sizeof (struct ip);
	int mtu;
	int n;	/* scratchpad */
	int error = 0;
	struct sockaddr_in *dst;
	const struct sockaddr_in *gw;
	struct in_ifaddr *ia;
	int isbroadcast;
	uint16_t ip_len, ip_off;
	struct route iproute;
	struct rtentry *rte;	/* cache for ro->ro_rt */
	struct in_addr odst;
	struct m_tag *fwd_tag = NULL;
	int have_ia_ref;
#ifdef IPSEC
	int no_route_but_check_spd = 0;
#endif
	M_ASSERTPKTHDR(m);

	if (inp != NULL) {
		INP_LOCK_ASSERT(inp);
		M_SETFIB(m, inp->inp_inc.inc_fibnum);
		if (inp->inp_flowtype != M_HASHTYPE_NONE) {
			m->m_pkthdr.flowid = inp->inp_flowid;
			M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
		}
	}

	if (ro == NULL) {
		ro = &iproute;
		bzero(ro, sizeof (*ro));
	}

#ifdef FLOWTABLE
	if (ro->ro_rt == NULL)
		(void )flowtable_lookup(AF_INET, m, ro);
#endif

	if (opt) {
		int len = 0;
		m = ip_insertoptions(m, opt, &len);
		if (len != 0)
			hlen = len; /* ip->ip_hl is updated above */
	}
	ip = mtod(m, struct ip *);
	ip_len = ntohs(ip->ip_len);
	ip_off = ntohs(ip->ip_off);

	/*
	 * Fill in IP header.  If we are not allowing fragmentation,
	 * then the ip_id field is meaningless, but we don't set it
	 * to zero.  Doing so causes various problems when devices along
	 * the path (routers, load balancers, firewalls, etc.) illegally
	 * disable DF on our packet.  Note that a 16-bit counter
	 * will wrap around in less than 10 seconds at 100 Mbit/s on a
	 * medium with MTU 1500.  See Steven M. Bellovin, "A Technique
	 * for Counting NATted Hosts", Proc. IMW'02, available at
	 * <http://www.cs.columbia.edu/~smb/papers/fnat.pdf>.
	 */
	if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
		ip->ip_v = IPVERSION;
		ip->ip_hl = hlen >> 2;
		ip->ip_id = ip_newid();
		IPSTAT_INC(ips_localout);
	} else {
示例#2
0
/*
 * IP output.  The packet in mbuf chain m contains a skeletal IP
 * header (with len, off, ttl, proto, tos, src, dst).
 * The mbuf chain containing the packet will be freed.
 * The mbuf opt, if present, will not be freed.
 */
int
ip_output(struct mbuf *m0, ...)
{
	struct rtentry *rt;
	struct ip *ip;
	struct ifnet *ifp;
	struct mbuf *m = m0;
	int hlen = sizeof (struct ip);
	int len, error = 0;
	struct route iproute;
	const struct sockaddr_in *dst;
	struct in_ifaddr *ia;
	struct ifaddr *xifa;
	struct mbuf *opt;
	struct route *ro;
	int flags, sw_csum;
	u_long mtu;
	struct ip_moptions *imo;
	struct socket *so;
	va_list ap;
	struct secpolicy *sp = NULL;
	bool natt_frag = false;
	bool __unused done = false;
	union {
		struct sockaddr		dst;
		struct sockaddr_in	dst4;
	} u;
	struct sockaddr *rdst = &u.dst;	/* real IP destination, as opposed
					 * to the nexthop
					 */

	len = 0;
	va_start(ap, m0);
	opt = va_arg(ap, struct mbuf *);
	ro = va_arg(ap, struct route *);
	flags = va_arg(ap, int);
	imo = va_arg(ap, struct ip_moptions *);
	so = va_arg(ap, struct socket *);
	va_end(ap);

	MCLAIM(m, &ip_tx_mowner);

	KASSERT((m->m_flags & M_PKTHDR) != 0);
	KASSERT((m->m_pkthdr.csum_flags & (M_CSUM_TCPv6|M_CSUM_UDPv6)) == 0);
	KASSERT((m->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) !=
	    (M_CSUM_TCPv4|M_CSUM_UDPv4));

	if (opt) {
		m = ip_insertoptions(m, opt, &len);
		if (len >= sizeof(struct ip))
			hlen = len;
	}
	ip = mtod(m, struct ip *);

	/*
	 * Fill in IP header.
	 */
	if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
		ip->ip_v = IPVERSION;
		ip->ip_off = htons(0);
		/* ip->ip_id filled in after we find out source ia */
		ip->ip_hl = hlen >> 2;
		IP_STATINC(IP_STAT_LOCALOUT);
	} else {
示例#3
0
/* This function will free m0! */
int
ip_output0(PNATState pData, struct socket *so, struct mbuf *m0, int urg)
{
    register struct ip *ip;
    register struct mbuf *m = m0;
    register int hlen = sizeof(struct ip);
    int len, off, error = 0;
    struct ethhdr *eh = NULL;
    uint8_t eth_dst[ETH_ALEN];
    int rc = 1;

    STAM_PROFILE_START(&pData->StatIP_output, a);

#ifdef LOG_ENABLED
    LogFlowFunc(("ip_output: so = %R[natsock], m0 = %lx\n", so, (long)m0));
#else
    NOREF(so);
#endif

    M_ASSERTPKTHDR(m);
    Assert(m->m_pkthdr.header);

#if 0 /* We do no options */
    if (opt)
    {
        m = ip_insertoptions(m, opt, &len);
        hlen = len;
    }
#endif
    ip = mtod(m, struct ip *);
    LogFunc(("ip(src:%RTnaipv4, dst:%RTnaipv4)\n", ip->ip_src, ip->ip_dst));
    /*
     * Fill in IP header.
     */
    ip->ip_v = IPVERSION;
    ip->ip_off &= IP_DF;
    ip->ip_id = RT_H2N_U16(ip_currid++);
    ip->ip_hl = hlen >> 2;
    ipstat.ips_localout++;

    /* Current TCP/IP stack hasn't routing information at
     * all so we need to calculate destination ethernet address
     */
    rc = rt_lookup_in_cache(pData, ip->ip_dst.s_addr, eth_dst);
    if (RT_FAILURE(rc))
        goto exit_drop_package;

    eh = (struct ethhdr *)(m->m_data - ETH_HLEN);
    /*
     * If small enough for interface, can just send directly.
     */
    if ((u_int16_t)ip->ip_len <= if_mtu)
    {
        ip->ip_len = RT_H2N_U16((u_int16_t)ip->ip_len);
        ip->ip_off = RT_H2N_U16((u_int16_t)ip->ip_off);
        ip->ip_sum = 0;
        ip->ip_sum = cksum(m, hlen);

        if (!(m->m_flags & M_SKIP_FIREWALL)){
            struct m_tag *t;
            STAM_PROFILE_START(&pData->StatALIAS_output, b);
            if ((t = m_tag_find(m, PACKET_TAG_ALIAS, NULL)) != 0)
                rc = LibAliasOut((struct libalias *)&t[1], mtod(m, char *),
                                 m_length(m, NULL));
            else
                rc = LibAliasOut(pData->proxy_alias, mtod(m, char *),
                                 m_length(m, NULL));

            if (rc == PKT_ALIAS_IGNORED)
            {
                Log(("NAT: packet was droppped\n"));
                goto exit_drop_package;
            }
            STAM_PROFILE_STOP(&pData->StatALIAS_output, b);
        }
示例#4
0
/*
 * IP output.  The packet in mbuf chain m contains a skeletal IP
 * header (with len, off, ttl, proto, tos, src, dst).
 * ip_len and ip_off are in host format.
 * The mbuf chain containing the packet will be freed.
 * The mbuf opt, if present, will not be freed.
 * In the IP forwarding case, the packet will arrive with options already
 * inserted, so must have a NULL opt pointer.
 */
int
ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
    struct ip_moptions *imo, struct inpcb *inp)
{
	struct ip *ip = NULL;
	struct ifnet *ifp = NULL;	/* keep compiler happy */
	struct mbuf *m0;
	int hlen = sizeof (struct ip);
	int mtu;
	int n;	/* scratchpad */
	int error = 0;
	int nortfree = 0;
	struct sockaddr_in *dst;
	struct in_ifaddr *ia = NULL;
	int isbroadcast, sw_csum;
	struct route iproute;
	struct rtentry *rte;	/* cache for ro->ro_rt */
	struct in_addr odst;
#ifdef IPFIREWALL_FORWARD
	struct m_tag *fwd_tag = NULL;
#endif
#ifdef IPSEC
	int no_route_but_check_spd = 0;
#endif
#ifdef PROMISCUOUS_INET
	struct ifl2info *l2i_tag = NULL;
	int ispromisc = 0;
#endif
	M_ASSERTPKTHDR(m);

	if (inp != NULL) {
		INP_LOCK_ASSERT(inp);
		M_SETFIB(m, inp->inp_inc.inc_fibnum);
		if (inp->inp_flags & (INP_HW_FLOWID|INP_SW_FLOWID)) {
			m->m_pkthdr.flowid = inp->inp_flowid;
			m->m_flags |= M_FLOWID;
		}
	}

#ifdef PROMISCUOUS_INET
	l2i_tag = (struct ifl2info *)m_tag_locate(m,
						  MTAG_PROMISCINET,
						  MTAG_PROMISCINET_L2INFO,
						  NULL);

	if ((inp && (inp->inp_flags2 & INP_PROMISC)) || l2i_tag) {
		unsigned int fib;

		if (l2i_tag) {
			/*
			 * This is a packet that has been turned around
			 * after reception, such as a TCP SYN packet being
			 * recycled as a RST, so fib comes from the mbuf,
			 * not the (probably nonexistent) connection
			 * context.
			 */
			fib = M_GETFIB(m);
		} else {
			fib = inp->inp_fibnum;

			if (0 != if_promiscinet_add_tag(m, inp->inp_l2info)) {
				goto bad;
			}
		}

		ifp = ifnet_byfib_ref(fib);
		if (NULL == ifp) {
			IPSTAT_INC(ips_noroute);
			error = EHOSTUNREACH;
			goto bad;
		}
		
		isbroadcast = 0;
		ispromisc = 1;
	}
#endif /* PROMISCUOUS_INET */

	if (ro == NULL) {
		ro = &iproute;
		bzero(ro, sizeof (*ro));

#ifdef FLOWTABLE
		{
			struct flentry *fle;
			
			/*
			 * The flow table returns route entries valid for up to 30
			 * seconds; we rely on the remainder of ip_output() taking no
			 * longer than that long for the stability of ro_rt.  The
			 * flow ID assignment must have happened before this point.
			 */
			if ((fle = flowtable_lookup_mbuf(V_ip_ft, m, AF_INET)) != NULL) {
				flow_to_route(fle, ro);
				nortfree = 1;
			}
		}
#endif
	}

	if (opt) {
		int len = 0;
		m = ip_insertoptions(m, opt, &len);
		if (len != 0)
			hlen = len; /* ip->ip_hl is updated above */
	}
	ip = mtod(m, struct ip *);

	/*
	 * Fill in IP header.  If we are not allowing fragmentation,
	 * then the ip_id field is meaningless, but we don't set it
	 * to zero.  Doing so causes various problems when devices along
	 * the path (routers, load balancers, firewalls, etc.) illegally
	 * disable DF on our packet.  Note that a 16-bit counter
	 * will wrap around in less than 10 seconds at 100 Mbit/s on a
	 * medium with MTU 1500.  See Steven M. Bellovin, "A Technique
	 * for Counting NATted Hosts", Proc. IMW'02, available at
	 * <http://www.cs.columbia.edu/~smb/papers/fnat.pdf>.
	 */
	if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
		ip->ip_v = IPVERSION;
		ip->ip_hl = hlen >> 2;
		ip->ip_id = ip_newid();
		IPSTAT_INC(ips_localout);
	} else {
示例#5
0
/*
 * IP output.  The packet in mbuf chain m contains a skeletal IP
 * header (with len, off, ttl, proto, tos, src, dst).
 * The mbuf chain containing the packet will be freed.
 * The mbuf opt, if present, will not be freed.
 * If route ro is present and has ro_rt initialized, route lookup would be
 * skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL,
 * then result of route lookup is stored in ro->ro_rt.
 *
 * In the IP forwarding case, the packet will arrive with options already
 * inserted, so must have a NULL opt pointer.
 */
int
ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
    struct ip_moptions *imo, struct inpcb *inp)
{
	struct rm_priotracker in_ifa_tracker;
	struct ip *ip;
	struct ifnet *ifp = NULL;	/* keep compiler happy */
	struct mbuf *m0;
	int hlen = sizeof (struct ip);
	int mtu;
	int error = 0;
	struct sockaddr_in *dst;
	const struct sockaddr_in *gw;
	struct in_ifaddr *ia;
	int isbroadcast, nortfree;
	uint16_t ip_len, ip_off;
	struct route iproute;
	struct rtentry *rte;	/* cache for ro->ro_rt */
	uint32_t fibnum;
	int have_ia_ref;
#ifdef IPSEC
	int no_route_but_check_spd = 0;
#endif
	M_ASSERTPKTHDR(m);

	if (inp != NULL) {
		INP_LOCK_ASSERT(inp);
		M_SETFIB(m, inp->inp_inc.inc_fibnum);
		if ((flags & IP_NODEFAULTFLOWID) == 0) {
			m->m_pkthdr.flowid = inp->inp_flowid;
			M_HASHTYPE_SET(m, inp->inp_flowtype);
		}
	}

	if (ro == NULL) {
		ro = &iproute;
		bzero(ro, sizeof (*ro));
	} else
		nortfree = 1;

#ifdef FLOWTABLE
	if (ro->ro_rt == NULL)
		(void )flowtable_lookup(AF_INET, m, ro);
	else {
		nortfree = 1;
	}
#endif

	if (opt) {
		int len = 0;
		m = ip_insertoptions(m, opt, &len);
		if (len != 0)
			hlen = len; /* ip->ip_hl is updated above */
	}
	ip = mtod(m, struct ip *);
	ip_len = ntohs(ip->ip_len);
	ip_off = ntohs(ip->ip_off);

	if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
		ip->ip_v = IPVERSION;
		ip->ip_hl = hlen >> 2;
		ip_fillid(ip);
		IPSTAT_INC(ips_localout);
	} else {
示例#6
0
/*
 * IP output.  The packet in mbuf chain m contains a skeletal IP
 * header (with len, off, ttl, proto, tos, src, dst).
 * The mbuf chain containing the packet will be freed.
 * The mbuf opt, if present, will not be freed.
 * If route ro is present and has ro_rt initialized, route lookup would be
 * skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL,
 * then result of route lookup is stored in ro->ro_rt.
 *
 * In the IP forwarding case, the packet will arrive with options already
 * inserted, so must have a NULL opt pointer.
 */
int
ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
    struct ip_moptions *imo, struct inpcb *inp)
{
	struct ip *ip;
	struct ifnet *ifp = NULL;	/* keep compiler happy */
	struct mbuf *m0;
	int hlen = sizeof (struct ip);
	int mtu;
	int n;	/* scratchpad */
	int error = 0;
	struct sockaddr_in *dst;
	struct in_ifaddr *ia;
	int isbroadcast;
	uint16_t ip_len, ip_off, sw_csum;
	struct route iproute;
	struct rtentry *rte;	/* cache for ro->ro_rt */
	struct in_addr odst;
#ifdef IPFIREWALL_FORWARD
	struct m_tag *fwd_tag = NULL;
#endif
#ifdef IPSEC
	int no_route_but_check_spd = 0;
#endif
	M_ASSERTPKTHDR(m);

	if (inp != NULL) {
		INP_LOCK_ASSERT(inp);
		M_SETFIB(m, inp->inp_inc.inc_fibnum);
		if (inp->inp_flags & (INP_HW_FLOWID|INP_SW_FLOWID)) {
			m->m_pkthdr.flowid = inp->inp_flowid;
			m->m_flags |= M_FLOWID;
		}
	}

	if (ro == NULL) {
		ro = &iproute;
		bzero(ro, sizeof (*ro));
	}

#ifdef FLOWTABLE
	if (ro->ro_rt == NULL) {
		struct flentry *fle;
			
		/*
		 * The flow table returns route entries valid for up to 30
		 * seconds; we rely on the remainder of ip_output() taking no
		 * longer than that long for the stability of ro_rt. The
		 * flow ID assignment must have happened before this point.
		 */
		fle = flowtable_lookup_mbuf(V_ip_ft, m, AF_INET);
		if (fle != NULL)
			flow_to_route(fle, ro);
	}
#endif

	if (opt) {
		int len = 0;
		m = ip_insertoptions(m, opt, &len);
		if (len != 0)
			hlen = len; /* ip->ip_hl is updated above */
	}
	ip = mtod(m, struct ip *);
	ip_len = ntohs(ip->ip_len);
	ip_off = ntohs(ip->ip_off);

	/*
	 * Fill in IP header.  If we are not allowing fragmentation,
	 * then the ip_id field is meaningless, but we don't set it
	 * to zero.  Doing so causes various problems when devices along
	 * the path (routers, load balancers, firewalls, etc.) illegally
	 * disable DF on our packet.  Note that a 16-bit counter
	 * will wrap around in less than 10 seconds at 100 Mbit/s on a
	 * medium with MTU 1500.  See Steven M. Bellovin, "A Technique
	 * for Counting NATted Hosts", Proc. IMW'02, available at
	 * <http://www.cs.columbia.edu/~smb/papers/fnat.pdf>.
	 */
	if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
		ip->ip_v = IPVERSION;
		ip->ip_hl = hlen >> 2;
		ip->ip_id = ip_newid();
		IPSTAT_INC(ips_localout);
	} else {