//static inline int ip_rcv_finish(struct sk_buff *skb)
inline int ip_rcv_finish(struct sk_buff *skb)
{
	struct iphdr *iph = skb->nh.iph;

	/*
	 *	Initialise the virtual path cache for the packet. It describes
	 *	how the packet travels inside Linux networking.
	 */ 
	if (likely(skb->dst == NULL)) {
		int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
					 skb->dev);
		if (unlikely(err)) {
			if (err == -EHOSTUNREACH)
				IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
			goto drop; 
		}
	}

#ifdef CONFIG_NET_CLS_ROUTE
	if (unlikely(skb->dst->tclassid)) {
		struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id();
		u32 idx = skb->dst->tclassid;
		st[idx&0xFF].o_packets++;
		st[idx&0xFF].o_bytes+=skb->len;
		st[(idx>>16)&0xFF].i_packets++;
		st[(idx>>16)&0xFF].i_bytes+=skb->len;
	}
#endif

	if (iph->ihl > 5 && ip_rcv_options(skb))
		goto drop;

	return dst_input(skb);

drop:
        kfree_skb(skb);
        return NET_RX_DROP;
}
예제 #2
0
파일: bcm_nat.c 프로젝트: jhbsz/DIR-850L_A1
static inline int bcm_fast_path(struct sk_buff *skb)
{
	if (skb_dst(skb) == NULL) {
		struct iphdr *iph = ip_hdr(skb);
		struct net_device *dev = skb->dev;

		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)) {
			return NF_DROP;
		}
		/*  Change skb owner to output device */
		skb->dev = skb_dst(skb)->dev;
	}

	if (skb_dst(skb)) {
		if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))
			return ip_fragment(skb, bcm_fast_path_output);
		else
			return bcm_fast_path_output(skb);
	}

	kfree_skb(skb);
	return -EINVAL;
}
예제 #3
0
static int br_nf_pre_routing_finish(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct iphdr *iph = ip_hdr(skb);
	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
	int err;

	if (nf_bridge->mask & BRNF_PKT_TYPE) {
		skb->pkt_type = PACKET_OTHERHOST;
		nf_bridge->mask ^= BRNF_PKT_TYPE;
	}
	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
	if (dnat_took_place(skb)) {
		if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
			struct rtable *rt;
			struct flowi fl = {
				.nl_u = {
					.ip4_u = {
						 .daddr = iph->daddr,
						 .saddr = 0,
						 .tos = RT_TOS(iph->tos) },
				},
				.proto = 0,
			};
			struct in_device *in_dev = in_dev_get(dev);

			/* If err equals -EHOSTUNREACH the error is due to a
			 * martian destination or due to the fact that
			 * forwarding is disabled. For most martian packets,
			 * ip_route_output_key() will fail. It won't fail for 2 types of
			 * martian destinations: loopback destinations and destination
			 * 0.0.0.0. In both cases the packet will be dropped because the
			 * destination is the loopback device and not the bridge. */
			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
				goto free_skb;

			if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
				/* - Bridged-and-DNAT'ed traffic doesn't
				 *   require ip_forwarding. */
				if (((struct dst_entry *)rt)->dev == dev) {
					skb->dst = (struct dst_entry *)rt;
					goto bridged_dnat;
				}
				/* we are sure that forwarding is disabled, so printing
				 * this message is no problem. Note that the packet could
				 * still have a martian destination address, in which case
				 * the packet could be dropped even if forwarding were enabled */
				__br_dnat_complain();
				dst_release((struct dst_entry *)rt);
			}
free_skb:
			kfree_skb(skb);
			return 0;
		} else {
			if (skb->dst->dev == dev) {
bridged_dnat:
				/* Tell br_nf_local_out this is a
				 * bridged frame */
				nf_bridge->mask |= BRNF_BRIDGED_DNAT;
				skb->dev = nf_bridge->physindev;
				nf_bridge_push_encap_header(skb);
				NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
					       skb, skb->dev, NULL,
					       br_nf_pre_routing_finish_bridge,
					       1);
				return 0;
			}
			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
			skb->pkt_type = PACKET_HOST;
		}
	} else {
예제 #4
0
static inline int ip_rcv_finish(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct iphdr *iph = skb->nh.iph;

	DEENC_CHECK();
	/*
	 *	Initialise the virtual path cache for the packet. It describes
	 *	how the packet travels inside Linux networking.
	 */ 
	if (skb->dst == NULL) {
		DEENC_CHECK();
		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
			goto drop; 
	}

#ifdef CONFIG_NET_CLS_ROUTE
	if (skb->dst->tclassid) {
		struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id();
		u32 idx = skb->dst->tclassid;
		st[idx&0xFF].o_packets++;
		st[idx&0xFF].o_bytes+=skb->len;
		st[(idx>>16)&0xFF].i_packets++;
		st[(idx>>16)&0xFF].i_bytes+=skb->len;
	}
#endif

	if (iph->ihl > 5) {
		struct ip_options *opt;
		DEENC_CHECK();

		/* It looks as overkill, because not all
		   IP options require packet mangling.
		   But it is the easiest for now, especially taking
		   into account that combination of IP options
		   and running sniffer is extremely rare condition.
		                                      --ANK (980813)
		*/

		if (skb_cow(skb, skb_headroom(skb)))
			goto drop;
		iph = skb->nh.iph;

		if (ip_options_compile(NULL, skb))
			goto inhdr_error;

		opt = &(IPCB(skb)->opt);
		if (opt->srr) {
			struct in_device *in_dev = in_dev_get(dev);
			if (in_dev) {
				if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
					if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
						printk(KERN_INFO "source route option %u.%u.%u.%u -> %u.%u.%u.%u\n",
						       NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
					in_dev_put(in_dev);
					goto drop;
				}
				in_dev_put(in_dev);
			}
			if (ip_options_rcv_srr(skb))
				goto drop;
		}
	}

	DEENC_CHECK();
	return skb->dst->input(skb);

inhdr_error:
	IP_INC_STATS_BH(IpInHdrErrors);
drop:
        kfree_skb(skb);
        return NET_RX_DROP;
}
예제 #5
0
파일: ip_input.c 프로젝트: 3null/fastsocket
static int ip_rcv_finish(struct sk_buff *skb)
{
	const struct iphdr *iph = ip_hdr(skb);
	struct rtable *rt;
	struct direct_tcp_stat *stat;

	stat = per_cpu_ptr(direct_tcp_stats, smp_processor_id());

	/*
	 *	Initialise the virtual path cache for the packet. It describes
	 *	how the packet travels inside Linux networking.
	 */

	if (skb_dst(skb) == NULL) {
		int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
					 skb->dev);
		stat->input_route_slow++;
		//FPRINTK("Skb 0x%p needs to go through route lookup\n", skb);

		if (unlikely(err)) {
			if (err == -EHOSTUNREACH)
				IP_INC_STATS_BH(dev_net(skb->dev),
						IPSTATS_MIB_INADDRERRORS);
			else if (err == -ENETUNREACH)
				IP_INC_STATS_BH(dev_net(skb->dev),
						IPSTATS_MIB_INNOROUTES);
			goto drop;
		}
	} else {
		stat->input_route_fast++;
		//FPRINTK("Skb 0x%p has set dst cache 0x%p[%u]\n", skb, skb_dst(skb), atomic_read(&skb_dst(skb)->__refcnt));
	}

#ifdef CONFIG_NET_CLS_ROUTE
	if (unlikely(skb_dst(skb)->tclassid)) {
		struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
		u32 idx = skb_dst(skb)->tclassid;
		st[idx&0xFF].o_packets++;
		st[idx&0xFF].o_bytes += skb->len;
		st[(idx>>16)&0xFF].i_packets++;
		st[(idx>>16)&0xFF].i_bytes += skb->len;
	}
#endif

	if (iph->ihl > 5 && ip_rcv_options(skb))
		goto drop;

	rt = skb_rtable(skb);
	if (rt->rt_type == RTN_MULTICAST) {
		IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST,
				skb->len);
	} else if (rt->rt_type == RTN_BROADCAST)
		IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST,
				skb->len);

	return dst_input(skb);

drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}
예제 #6
0
파일: ipip.c 프로젝트: GNUHurdTR/hurd
void ipip_err(struct sk_buff *skb, unsigned char *dp, int len)
{
#ifndef I_WISH_WORLD_WERE_PERFECT

/* It is not :-( All the routers (except for Linux) return only
   8 bytes of packet payload. It means, that precise relaying of
   ICMP in the real Internet is absolutely infeasible.
 */
	struct iphdr *iph = (struct iphdr*)dp;
	int type = skb->h.icmph->type;
	int code = skb->h.icmph->code;
	struct ip_tunnel *t;

	if (len < sizeof(struct iphdr))
		return;

	switch (type) {
	default:
	case ICMP_PARAMETERPROB:
		return;

	case ICMP_DEST_UNREACH:
		switch (code) {
		case ICMP_SR_FAILED:
		case ICMP_PORT_UNREACH:
			/* Impossible event. */
			return;
		case ICMP_FRAG_NEEDED:
			/* Soft state for pmtu is maintained by IP core. */
			return;
		default:
			/* All others are translated to HOST_UNREACH.
			   rfc2003 contains "deep thoughts" about NET_UNREACH,
			   I believe they are just ether pollution. --ANK
			 */
			break;
		}
		break;
	case ICMP_TIME_EXCEEDED:
		if (code != ICMP_EXC_TTL)
			return;
		break;
	}

	t = ipip_tunnel_lookup(iph->daddr, iph->saddr);
	if (t == NULL || t->parms.iph.daddr == 0)
		return;
	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
		return;

	if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
		t->err_count++;
	else
		t->err_count = 1;
	t->err_time = jiffies;
	return;
#else
	struct iphdr *iph = (struct iphdr*)dp;
	int hlen = iph->ihl<<2;
	struct iphdr *eiph;
	int type = skb->h.icmph->type;
	int code = skb->h.icmph->code;
	int rel_type = 0;
	int rel_code = 0;
	int rel_info = 0;
	struct sk_buff *skb2;
	struct rtable *rt;

	if (len < hlen + sizeof(struct iphdr))
		return;
	eiph = (struct iphdr*)(dp + hlen);

	switch (type) {
	default:
		return;
	case ICMP_PARAMETERPROB:
		if (skb->h.icmph->un.gateway < hlen)
			return;

		/* So... This guy found something strange INSIDE encapsulated
		   packet. Well, he is fool, but what can we do ?
		 */
		rel_type = ICMP_PARAMETERPROB;
		rel_info = skb->h.icmph->un.gateway - hlen;
		break;

	case ICMP_DEST_UNREACH:
		switch (code) {
		case ICMP_SR_FAILED:
		case ICMP_PORT_UNREACH:
			/* Impossible event. */
			return;
		case ICMP_FRAG_NEEDED:
			/* And it is the only really necessary thing :-) */
			rel_info = ntohs(skb->h.icmph->un.frag.mtu);
			if (rel_info < hlen+68)
				return;
			rel_info -= hlen;
			/* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
			if (rel_info > ntohs(eiph->tot_len))
				return;
			break;
		default:
			/* All others are translated to HOST_UNREACH.
			   rfc2003 contains "deep thoughts" about NET_UNREACH,
			   I believe, it is just ether pollution. --ANK
			 */
			rel_type = ICMP_DEST_UNREACH;
			rel_code = ICMP_HOST_UNREACH;
			break;
		}
		break;
	case ICMP_TIME_EXCEEDED:
		if (code != ICMP_EXC_TTL)
			return;
		break;
	}

	/* Prepare fake skb to feed it to icmp_send */
	skb2 = skb_clone(skb, GFP_ATOMIC);
	if (skb2 == NULL)
		return;
	dst_release(skb2->dst);
	skb2->dst = NULL;
	skb_pull(skb2, skb->data - (u8*)eiph);
	skb2->nh.raw = skb2->data;

	/* Try to guess incoming interface */
	if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) {
		kfree_skb(skb2);
		return;
	}
	skb2->dev = rt->u.dst.dev;

	/* route "incoming" packet */
	if (rt->rt_flags&RTCF_LOCAL) {
		ip_rt_put(rt);
		rt = NULL;
		if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) ||
		    rt->u.dst.dev->type != ARPHRD_IPGRE) {
			ip_rt_put(rt);
			kfree_skb(skb2);
			return;
		}
	} else {
		ip_rt_put(rt);
		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
		    skb2->dst->dev->type != ARPHRD_IPGRE) {
			kfree_skb(skb2);
			return;
		}
	}

	/* change mtu on this route */
	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
		if (rel_info > skb2->dst->pmtu) {
			kfree_skb(skb2);
			return;
		}
		skb2->dst->pmtu = rel_info;
		rel_info = htonl(rel_info);
	} else if (type == ICMP_TIME_EXCEEDED) {
		struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv;
		if (t->parms.iph.ttl) {
			rel_type = ICMP_DEST_UNREACH;
			rel_code = ICMP_HOST_UNREACH;
		}
	}

	icmp_send(skb2, rel_type, rel_code, rel_info);
	kfree_skb(skb2);
	return;
#endif
}
예제 #7
0
파일: arp.c 프로젝트: 274914765/C
static int arp_process(struct sk_buff *skb)
{
    struct net_device *dev = skb->dev;
    struct in_device *in_dev = in_dev_get(dev);
    struct arphdr *arp;
    unsigned char *arp_ptr;
    struct rtable *rt;
    unsigned char *sha;
    __be32 sip, tip;
    u16 dev_type = dev->type;
    int addr_type;
    struct neighbour *n;
    struct net *net = dev_net(dev);

    /* arp_rcv below verifies the ARP header and verifies the device
     * is ARP'able.
     */

    if (in_dev == NULL)
        goto out;

    arp = arp_hdr(skb);

    switch (dev_type) {
    default:
        if (arp->ar_pro != htons(ETH_P_IP) ||
            htons(dev_type) != arp->ar_hrd)
            goto out;
        break;
    case ARPHRD_ETHER:
    case ARPHRD_IEEE802_TR:
    case ARPHRD_FDDI:
    case ARPHRD_IEEE802:
        /*
         * ETHERNET, Token Ring and Fibre Channel (which are IEEE 802
         * devices, according to RFC 2625) devices will accept ARP
         * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).
         * This is the case also of FDDI, where the RFC 1390 says that
         * FDDI devices should accept ARP hardware of (1) Ethernet,
         * however, to be more robust, we'll accept both 1 (Ethernet)
         * or 6 (IEEE 802.2)
         */
        if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
             arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
            arp->ar_pro != htons(ETH_P_IP))
            goto out;
        break;
    case ARPHRD_AX25:
        if (arp->ar_pro != htons(AX25_P_IP) ||
            arp->ar_hrd != htons(ARPHRD_AX25))
            goto out;
        break;
    case ARPHRD_NETROM:
        if (arp->ar_pro != htons(AX25_P_IP) ||
            arp->ar_hrd != htons(ARPHRD_NETROM))
            goto out;
        break;
    }

    /* Understand only these message types */

    if (arp->ar_op != htons(ARPOP_REPLY) &&
        arp->ar_op != htons(ARPOP_REQUEST))
        goto out;

/*
 *    Extract fields
 */
    arp_ptr= (unsigned char *)(arp+1);
    sha    = arp_ptr;
    arp_ptr += dev->addr_len;
    memcpy(&sip, arp_ptr, 4);
    arp_ptr += 4;
    arp_ptr += dev->addr_len;
    memcpy(&tip, arp_ptr, 4);
/*
 *    Check for bad requests for 127.x.x.x and requests for multicast
 *    addresses.  If this is one such, delete it.
 */
    if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
        goto out;

/*
 *     Special case: We must set Frame Relay source Q.922 address
 */
    if (dev_type == ARPHRD_DLCI)
        sha = dev->broadcast;

/*
 *  Process entry.  The idea here is we want to send a reply if it is a
 *  request for us or if it is a request for someone else that we hold
 *  a proxy for.  We want to add an entry to our cache if it is a reply
 *  to us or if it is a request for our address.
 *  (The assumption for this last is that if someone is requesting our
 *  address, they are probably intending to talk to us, so it saves time
 *  if we cache their address.  Their address is also probably not in
 *  our cache, since ours is not in their cache.)
 *
 *  Putting this another way, we only care about replies if they are to
 *  us, in which case we add them to the cache.  For requests, we care
 *  about those for us and those for our proxies.  We reply to both,
 *  and in the case of requests for us we add the requester to the arp
 *  cache.
 */

    /* Special case: IPv4 duplicate address detection packet (RFC2131) */
    if (sip == 0) {
        if (arp->ar_op == htons(ARPOP_REQUEST) &&
            inet_addr_type(net, tip) == RTN_LOCAL &&
            !arp_ignore(in_dev, sip, tip))
            arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
                 dev->dev_addr, sha);
        goto out;
    }

    if (arp->ar_op == htons(ARPOP_REQUEST) &&
        ip_route_input(skb, tip, sip, 0, dev) == 0) {

        rt = skb->rtable;
        addr_type = rt->rt_type;

        if (addr_type == RTN_LOCAL) {
            n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
            if (n) {
                int dont_send = 0;

                if (!dont_send)
                    dont_send |= arp_ignore(in_dev,sip,tip);
                if (!dont_send && IN_DEV_ARPFILTER(in_dev))
                    dont_send |= arp_filter(sip,tip,dev);
                if (!dont_send)
                    arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);

                neigh_release(n);
            }
            goto out;
        } else if (IN_DEV_FORWARD(in_dev)) {
                if (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
                 (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
                n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                if (n)
                    neigh_release(n);

                if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
                    skb->pkt_type == PACKET_HOST ||
                    in_dev->arp_parms->proxy_delay == 0) {
                    arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
                } else {
                    pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
                    in_dev_put(in_dev);
                    return 0;
                }
                goto out;
            }
        }
    }

    /* Update our ARP tables */

    n = __neigh_lookup(&arp_tbl, &sip, dev, 0);

    if (IPV4_DEVCONF_ALL(dev_net(dev), ARP_ACCEPT)) {
        /* Unsolicited ARP is not accepted by default.
           It is possible, that this option should be enabled for some
           devices (strip is candidate)
         */
        if (n == NULL &&
            arp->ar_op == htons(ARPOP_REPLY) &&
            inet_addr_type(net, sip) == RTN_UNICAST)
            n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
    }

    if (n) {
        int state = NUD_REACHABLE;
        int override;

        /* If several different ARP replies follows back-to-back,
           use the FIRST one. It is possible, if several proxy
           agents are active. Taking the first reply prevents
           arp trashing and chooses the fastest router.
         */
        override = time_after(jiffies, n->updated + n->parms->locktime);

        /* Broadcast replies and request packets
           do not assert neighbour reachability.
         */
        if (arp->ar_op != htons(ARPOP_REPLY) ||
            skb->pkt_type != PACKET_HOST)
            state = NUD_STALE;
        neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);
        neigh_release(n);
    }
예제 #8
0
/* This requires some explaining. If DNAT has taken place,
 * we will need to fix up the destination Ethernet address.
 *
 * There are two cases to consider:
 * 1. The packet was DNAT'ed to a device in the same bridge
 *    port group as it was received on. We can still bridge
 *    the packet.
 * 2. The packet was DNAT'ed to a different device, either
 *    a non-bridged device or another bridge port group.
 *    The packet will need to be routed.
 *
 * The correct way of distinguishing between these two cases is to
 * call ip_route_input() and to look at skb->dst->dev, which is
 * changed to the destination device if ip_route_input() succeeds.
 *
 * Let's first consider the case that ip_route_input() succeeds:
 *
 * If the output device equals the logical bridge device the packet
 * came in on, we can consider this bridging. The corresponding MAC
 * address will be obtained in br_nf_pre_routing_finish_bridge.
 * Otherwise, the packet is considered to be routed and we just
 * change the destination MAC address so that the packet will
 * later be passed up to the IP stack to be routed. For a redirected
 * packet, ip_route_input() will give back the localhost as output device,
 * which differs from the bridge device.
 *
 * Let's now consider the case that ip_route_input() fails:
 *
 * This can be because the destination address is martian, in which case
 * the packet will be dropped.
 * If IP forwarding is disabled, ip_route_input() will fail, while
 * ip_route_output_key() can return success. The source
 * address for ip_route_output_key() is set to zero, so ip_route_output_key()
 * thinks we're handling a locally generated packet and won't care
 * if IP forwarding is enabled. If the output device equals the logical bridge
 * device, we proceed as if ip_route_input() succeeded. If it differs from the
 * logical bridge port or if ip_route_output_key() fails we drop the packet.
 */
static int br_nf_pre_routing_finish(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct iphdr *iph = ip_hdr(skb);
	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
	struct rtable *rt;
	int err;

	if (nf_bridge->mask & BRNF_PKT_TYPE) {
		skb->pkt_type = PACKET_OTHERHOST;
		nf_bridge->mask ^= BRNF_PKT_TYPE;
	}
	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
	if (dnat_took_place(skb)) {
		if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
			struct in_device *in_dev = __in_dev_get_rcu(dev);

			/* If err equals -EHOSTUNREACH the error is due to a
			 * martian destination or due to the fact that
			 * forwarding is disabled. For most martian packets,
			 * ip_route_output_key() will fail. It won't fail for 2 types of
			 * martian destinations: loopback destinations and destination
			 * 0.0.0.0. In both cases the packet will be dropped because the
			 * destination is the loopback device and not the bridge. */
			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
				goto free_skb;

			rt = ip_route_output(dev_net(dev), iph->daddr, 0,
					     RT_TOS(iph->tos), 0);
			if (!IS_ERR(rt)) {
				/* - Bridged-and-DNAT'ed traffic doesn't
				 *   require ip_forwarding. */
				if (rt->dst.dev == dev) {
					skb_dst_set(skb, &rt->dst);
					goto bridged_dnat;
				}
				ip_rt_put(rt);
			}
free_skb:
			kfree_skb(skb);
			return 0;
		} else {
			if (skb_dst(skb)->dev == dev) {
bridged_dnat:
				skb->dev = nf_bridge->physindev;
				nf_bridge_update_protocol(skb);
				nf_bridge_push_encap_header(skb);
				NF_HOOK_THRESH(NFPROTO_BRIDGE,
					       NF_BR_PRE_ROUTING,
					       skb, skb->dev, NULL,
					       br_nf_pre_routing_finish_bridge,
					       1);
				return 0;
			}
			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
			skb->pkt_type = PACKET_HOST;
		}
	} else {
		rt = bridge_parent_rtable(nf_bridge->physindev);
		if (!rt) {
			kfree_skb(skb);
			return 0;
		}
		skb_dst_set_noref(skb, &rt->dst);
	}

	skb->dev = nf_bridge->physindev;
	nf_bridge_update_protocol(skb);
	nf_bridge_push_encap_header(skb);
	NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
		       br_handle_frame_finish, 1);

	return 0;
}
예제 #9
0
/* Route IPv4 packet 'skbp', using the route key selectors in 
   'route_selector' and the interface number 'ifnum_in'. */
Boolean
ssh_interceptor_reroute_skb_ipv4(SshInterceptor interceptor,
				 struct sk_buff *skbp,
				 SshUInt16 route_selector,
				 SshUInt32 ifnum_in)
{
  struct iphdr *iph;
  int rval = 0;

  /* Recalculate the route info as the engine might have touched the
     destination address. This can happen for example if we are in
     tunnel mode. */

  iph = (struct iphdr *) SSH_SKB_GET_NETHDR(skbp);
  if (iph == NULL)
    {
      SSH_DEBUG(SSH_D_ERROR, ("Could not access IP header"));
      return FALSE;
    }

  /* Release old dst_entry */
  if (skb_dst(skbp))
    dst_release(skb_dst(skbp));

  skb_dst_set(skbp, NULL);

  if ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC)
      && (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_FLAG_LOCAL_SRC) == 0
      && (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_IN_IFNUM))
    {
      u32 saddr = 0;
      u8 ipproto = 0;
      u8 tos = 0;
#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)
#ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR
      u32 fwmark = 0;
#endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */
#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */
      struct net_device *dev;

      SSH_ASSERT(skbp->protocol == __constant_htons(ETH_P_IP));

      if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC)
	saddr = iph->saddr;
           
      /* Map 'ifnum_in' to a net_device. */
      SSH_LINUX_ASSERT_VALID_IFNUM(ifnum_in);
      dev = ssh_interceptor_ifnum_to_netdev(interceptor, ifnum_in);

      /* Clear the IP protocol, if selector does not define it.
	 Ugly, but necessary to make sure the skb gets
	 rerouted like engine expects. */
      if ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO) == 0)
	{	  
	  ipproto = iph->protocol;
	  iph->protocol = 0;
	}

      if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS)
	tos = RT_TOS(iph->tos);

#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)
#ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR
      /* Clear the nfmark, if selector does not define it.
	 Ugly, but necessary to make sure the skb gets
	 rerouted like engine expects. */
      if ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION) == 0)
	{
	  fwmark = SSH_SKB_MARK(skbp);
	  SSH_SKB_MARK(skbp) = 0;
	}
#endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */
#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */
      
      /* Call ip_route_input */
      if (ip_route_input(skbp, iph->daddr, saddr, tos, dev) < 0)
	{
	  SSH_DEBUG(SSH_D_FAIL, 
		    ("ip_route_input failed. (0x%08x -> 0x%08x)",
		     iph->saddr, iph->daddr));

	  SSH_DEBUG(SSH_D_NICETOKNOW,
		    ("dst 0x%08x src 0x%08x iif %d[%s] proto %d tos 0x%02x "
		     "fwmark 0x%x",
		     iph->daddr, saddr,
		     (dev ? dev->ifindex : -1),
		     (dev ? dev->name : "none"), 
		     iph->protocol, tos, 
		     SSH_SKB_MARK(skbp)));

	  /* Release netdev reference */
	  if (dev)
	    ssh_interceptor_release_netdev(dev);

	  /* Note, skb modifications are not un-done as the caller frees the 
	     skb. If this is changed then the modifications should be un-done
	     here before returning. */

	  return FALSE;
	}

      /* Write original IP protocol back to skb */
      if (ipproto)
	iph->protocol = ipproto;

#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)
#ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR
      /* Write original fwmark back to skb */
      if (fwmark)
	SSH_SKB_MARK(skbp) = fwmark;
#endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */
#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */

      /* Release netdev reference */
      if (dev)
	ssh_interceptor_release_netdev(dev);
    }

  else
    {
      struct rtable *rt;
      struct flowi rt_key;

      if ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_FLAG_LOCAL_SRC) == 0)
	route_selector &= ~SSH_INTERCEPTOR_ROUTE_KEY_SRC;

      memset(&rt_key, 0, sizeof(rt_key));
      
      rt_key.fl4_dst = iph->daddr;
      if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC)
	rt_key.fl4_src = iph->saddr;
      if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_OUT_IFNUM)
	rt_key.oif = (skbp->dev ? skbp->dev->ifindex : 0);
      if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO)
	rt_key.proto = iph->protocol;
      if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS)
	rt_key.fl4_tos = RT_TOS(iph->tos);
      rt_key.fl4_scope = RT_SCOPE_UNIVERSE;

#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)
#ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR
      if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION)
	{
#ifdef LINUX_HAS_SKB_MARK
	  rt_key.mark = SSH_SKB_MARK(skbp);
#else /* LINUX_HAS_SKB_MARK */
#ifdef CONFIG_IP_ROUTE_FWMARK
	  rt_key.fl4_fwmark = SSH_SKB_MARK(skbp);
#endif /* CONFIG_IP_ROUTE_FWMARK */
#endif /* LINUX_HAS_SKB_MARK */
	}
#endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */
#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */
      
      /* Call ip_route_output */
#ifdef LINUX_IP_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT
      rval = ip_route_output_key(&init_net, &rt, &rt_key);
#else /* LINUX_IP_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT */
      rval = ip_route_output_key(&rt, &rt_key);
#endif /* LINUX_IP_ROUTE_OUTPUT_KEY_HAS_NET_ARGUMENT */
      if (rval < 0)
	{
	  SSH_DEBUG(SSH_D_FAIL, 
		    ("ip_route_output_key failed (0x%08x -> 0x%08x): %d",
		     iph->saddr, iph->daddr, rval));

	  SSH_DEBUG(SSH_D_NICETOKNOW,
		    ("dst 0x%08x src 0x%08x oif %d[%s] proto %d tos 0x%02x"
		     "fwmark 0x%x",
		     iph->daddr,
		     ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC) ? 
		      iph->saddr : 0),
		     ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_OUT_IFNUM) ?
		      rt_key.oif : -1),
		     ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_OUT_IFNUM) ?
		      (skbp->dev ? skbp->dev->name : "none") : "none"),
		     ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO) ?
		      iph->protocol : -1),
		     ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS) ?
		      iph->tos : 0),
		     ((route_selector & SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION) ?
		      SSH_SKB_MARK(skbp) : 0)));

	  /* Note, skb modifications are not un-done as the caller frees the 
	     skb. If this is changed then the modifications should be un-done
	     here before returning. */

	  return FALSE;
	}

      /* Make a new dst because we just rechecked the route. */
      skb_dst_set(skbp, dst_clone(&rt->u.dst));
      
      /* Release the routing table entry ; otherwise a memory leak occurs
	 in the route entry table. */
      ip_rt_put(rt);
    }
  
  SSH_ASSERT(skb_dst(skbp) != NULL);

#ifdef SSH_IPSEC_IP_ONLY_INTERCEPTOR
#ifdef LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING
  if (route_selector & SSH_INTERCEPTOR_ROUTE_KEY_FLAG_TRANSFORM_APPLIED)
    {
      /* Check if need to create a child dst_entry with interface MTU. */
      if (skb_dst(skbp)->child == NULL)
	{
          if (interceptor_route_create_child_dst(skb_dst(skbp)) == NULL)
	    {
	      SSH_DEBUG(SSH_D_ERROR,
			("Could not create child dst_entry for dst %p",
			 skb_dst(skbp)));
	      return FALSE;
	    }
	}
     
      /* Pop dst stack and use the child entry with interface MTU 
	 for sending the packet. */
      skb_dst_set(skbp, dst_pop(skb_dst(skbp)));
    }
#endif /* LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING */
#endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */

  return TRUE;
}
예제 #10
0
/* Perform route lookup using linux ip_route_input.

   The route lookup will use the following selectors:
   dst, src, inbound ifnum, ip protocol, tos, and fwmark.
   The source address is expected to be non-local and it must be defined.
   
   The following selectors are ignored:
   dst port, src port, icmp type, icmp code, ipsec spi. */
Boolean
ssh_interceptor_route_input_ipv4(SshInterceptor interceptor,
				 SshInterceptorRouteKey key,
				 SshUInt16 selector,
				 SshInterceptorRouteResult result)
{
  u32 daddr, saddr;
  u8 ipproto;
  u8 tos;
  u32 fwmark;
  struct sk_buff *skbp;
  struct net_device *dev;
  struct rtable *rt;
  int rval = 0;
  u16 rt_type;
  struct iphdr *iph = NULL;
#ifdef DEBUG_LIGHT
  unsigned char *rt_type_str;
#endif /* DEBUG_LIGHT */

  SSH_INTERCEPTOR_STACK_MARK();

  SSH_IP4_ENCODE(&key->dst, (unsigned char *) &daddr);  

  /* Initialize */
  saddr = 0;
  ipproto = 0;
  tos = 0;
  fwmark = 0;
  dev = NULL;

  if (selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC)
    SSH_IP4_ENCODE(&key->src, (unsigned char *) &saddr);
  if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IN_IFNUM)
    {
      SSH_LINUX_ASSERT_VALID_IFNUM(key->ifnum);
      dev = ssh_interceptor_ifnum_to_netdev(interceptor, key->ifnum);
    }
  if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO)
    ipproto = key->ipproto;
  if (selector & SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS)
    tos = key->nh.ip4.tos;

#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)	
#ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR
  /* Use linux fw_mark in routing */
  if (selector & SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION)
    fwmark = key->extension[SSH_LINUX_FWMARK_EXTENSION_SELECTOR];
#endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */
#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */  
  
  /* Build dummy skb */
  skbp = alloc_skb(SSH_IPH4_HDRLEN, GFP_ATOMIC);
  if (skbp == NULL)
    goto fail;

  SSH_SKB_RESET_MACHDR(skbp);
  iph = (struct iphdr *) skb_put(skbp, SSH_IPH4_HDRLEN);
  if (iph == NULL)
    {
      dev_kfree_skb(skbp);
      goto fail;
    }
  SSH_SKB_SET_NETHDR(skbp, (unsigned char *) iph); 

  skb_dst_set(skbp, NULL);
  skbp->protocol = __constant_htons(ETH_P_IP);
  SSH_SKB_MARK(skbp) = fwmark;
  iph->protocol = ipproto;
  
  SSH_DEBUG(SSH_D_LOWOK,
	    ("Route lookup: "
	     "dst %@ src %@ ifnum %d[%s] ipproto %d tos 0x%02x fwmark 0x%x",
	     ssh_ipaddr_render, &key->dst,
	     ssh_ipaddr_render, 
	     ((selector & SSH_INTERCEPTOR_ROUTE_KEY_SRC) ? 
	      &key->src : NULL),
	     (dev ? dev->ifindex : -1),
	     (dev ? dev->name : "none"),
	     ipproto,
	     tos,
	     fwmark));

  /* Perform route lookup */

  rval = ip_route_input(skbp, daddr, saddr, tos, dev);
  if (rval < 0 || skb_dst(skbp) == NULL)
    {      
      dev_kfree_skb(skbp);
      goto fail;
    }

  /* Get the gateway, mtu and ifnum */
  rt = (struct rtable *) skb_dst(skbp);
  SSH_IP4_DECODE(result->gw, &rt->rt_gateway);
  result->mtu = SSH_LINUX_DST_MTU(skb_dst(skbp));
  result->ifnum = skb_dst(skbp)->dev->ifindex;
  rt_type = rt->rt_type;
  
#ifdef DEBUG_LIGHT
  switch (rt_type)
    {
    case RTN_UNSPEC:
      rt_type_str = "unspec";
      break;
    case RTN_UNICAST:
      rt_type_str = "unicast";
      break;
    case RTN_LOCAL:
      rt_type_str = "local";
      break;
    case RTN_BROADCAST:
      rt_type_str = "broadcast";
      break;
    case RTN_ANYCAST:
      rt_type_str = "anycast";
      break;
    case RTN_MULTICAST:
      rt_type_str = "multicast";
      break;
    case RTN_BLACKHOLE:
      rt_type_str = "blackhole";
      break;
    case RTN_UNREACHABLE:
      rt_type_str = "unreachable";
      break;
    case RTN_PROHIBIT:
      rt_type_str = "prohibit";
      break;
    case RTN_THROW:
      rt_type_str = "throw";
      break;
    case RTN_NAT:
      rt_type_str = "nat";
      break;
    case RTN_XRESOLVE:
      rt_type_str = "xresolve";
      break;
    default:
      rt_type_str = "unknown";
    }
#endif /* DEBUG_LIGHT */

  SSH_DEBUG(SSH_D_LOWOK, 
	    ("Route result: dst %@ via %@ ifnum %d[%s] mtu %d type %s [%d]",
	     ssh_ipaddr_render, &key->dst,
	     ssh_ipaddr_render, result->gw, result->ifnum,
	     (rt->u.dst.dev->name ? rt->u.dst.dev->name : "none"),
	     result->mtu, rt_type_str, rt_type));

#ifdef SSH_IPSEC_IP_ONLY_INTERCEPTOR
#ifdef LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING
  /* Check if need to create a child dst_entry with interface MTU. */
  if ((selector & SSH_INTERCEPTOR_ROUTE_KEY_FLAG_TRANSFORM_APPLIED)
      && skb_dst(skbp)->child == NULL)
    {
      if (interceptor_route_create_child_dst(skb_dst(skbp)) == NULL)
	SSH_DEBUG(SSH_D_FAIL, ("Could not create child dst_entry for dst %p",
			       skb_dst(skbp)));
    }
#endif /* LINUX_FRAGMENTATION_AFTER_NF_POST_ROUTING */
#endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */

  /* Release the routing table entry ; otherwise a memory leak occurs
     in the route entry table. */
  dst_release(skb_dst(skbp));
  skb_dst_set(skbp, NULL);
  dev_kfree_skb(skbp);
  
  /* Assert that ifnum fits into the SshInterceptorIfnum data type. */
  SSH_LINUX_ASSERT_IFNUM(result->ifnum);

  /* Check that ifnum does not collide with SSH_INTERCEPTOR_INVALID_IFNUM. */
  if (result->ifnum == SSH_INTERCEPTOR_INVALID_IFNUM)
    goto fail;

  /* Accept only unicast, broadcast, anycast, 
     multicast and local routes. */
  if (rt_type == RTN_UNICAST
      || rt_type == RTN_BROADCAST
      || rt_type == RTN_ANYCAST
      || rt_type == RTN_MULTICAST
      || rt_type == RTN_LOCAL)
    {
      ssh_interceptor_release_netdev(dev);
      SSH_LINUX_ASSERT_VALID_IFNUM(result->ifnum);
      return TRUE;
    }
  /* Fail route lookup for other route types. */
  
 fail:
  if (dev)
    ssh_interceptor_release_netdev(dev);
  
  SSH_DEBUG(SSH_D_FAIL, 
	    ("Route lookup for %@ failed with code %d",
	     ssh_ipaddr_render, &key->dst, rval));
  return FALSE;
}
예제 #11
0
파일: ip_input.c 프로젝트: nskeeper/Lantern
static int ip_rcv_finish(struct sk_buff *skb)
{
    const struct iphdr *iph = ip_hdr(skb);
    struct rtable *rt;
    int dcn_flag = 0;

    /* modified by yaom for mpls dcn, 2011-10-20 */
    #if 0
    if ((mpls_dcn_proc) && (NULL == skb_dst(skb)))
    {   
        dcn_flag = mpls_dcn_proc(skb, iph->daddr, 1);
        if (dcn_flag)
        {
            kfree_skb(skb);
            return NET_RX_SUCCESS;
        }
    }
    #endif
    
    if ((dcn_flag != 1) || (NULL == skb_dst(skb)))
    {
        /*
         *  Initialise the virtual path cache for the packet. It describes
         *  how the packet travels inside Linux networking.
         */
        if (skb_dst(skb) == NULL) {
            int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
                         skb->dev);
            if (unlikely(err)) {
                if (err == -EHOSTUNREACH)
                    IP_INC_STATS_BH(dev_net(skb->dev),
                            IPSTATS_MIB_INADDRERRORS);
                else if (err == -ENETUNREACH)
                    IP_INC_STATS_BH(dev_net(skb->dev),
                            IPSTATS_MIB_INNOROUTES);
                goto drop;
            }
        }

#ifdef CONFIG_NET_CLS_ROUTE
        if (unlikely(skb_dst(skb)->tclassid)) {
            struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
            u32 idx = skb_dst(skb)->tclassid;
            st[idx&0xFF].o_packets++;
            st[idx&0xFF].o_bytes += skb->len;
            st[(idx>>16)&0xFF].i_packets++;
            st[(idx>>16)&0xFF].i_bytes += skb->len;
        }
#endif

        if (iph->ihl > 5 && ip_rcv_options(skb))
            goto drop;

        rt = skb_rtable(skb);
        if (rt->rt_type == RTN_MULTICAST) {
            IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST,
                    skb->len);
        } else if (rt->rt_type == RTN_BROADCAST)
            IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST,
                    skb->len);
    }

    return dst_input(skb);

drop:
    kfree_skb(skb);
    return NET_RX_DROP;
}
예제 #12
0
/*
 * 	Main IP Receive routine.
 */ 
int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
	struct iphdr *iph = skb->nh.iph;

	/*
	 * 	When the interface is in promisc. mode, drop all the crap
	 * 	that it receives, do not try to analyse it.
	 */
	if (skb->pkt_type == PACKET_OTHERHOST)
		goto drop;

	ip_statistics.IpInReceives++;

	/*
	 *	RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
	 *
	 *	Is the datagram acceptable?
	 *
	 *	1.	Length at least the size of an ip header
	 *	2.	Version of 4
	 *	3.	Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *	4.	Doesn't have a bogus length
	 */

	if (skb->len < sizeof(struct iphdr))
		goto inhdr_error; 
	if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0)
		goto inhdr_error; 

	{
	__u32 len = ntohs(iph->tot_len); 
	if (skb->len < len)
		goto inhdr_error; 

	/*
	 *	Our transport medium may have padded the buffer out. Now we know it
	 *	is IP we can trim to the true length of the frame.
	 *	Note this now means skb->len holds ntohs(iph->tot_len).
	 */

	__skb_trim(skb, len);
	}
	
	/*
	 *	Initialise the virtual path cache for the packet. It describes
	 *	how the packet travels inside Linux networking.
	 */ 
	if (skb->dst == NULL) {
		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
			goto drop; 
#ifdef CONFIG_CPU_IS_SLOW
		if (net_cpu_congestion > 10 && !(iph->tos&IPTOS_RELIABILITY) &&
		    IPTOS_PREC(iph->tos) < IPTOS_PREC_INTERNETCONTROL) {
			goto drop;
		}
#endif
	}

#ifdef CONFIG_IP_ALWAYS_DEFRAG
	if (iph->frag_off & htons(IP_MF|IP_OFFSET)) {
		skb = ip_defrag(skb);
		if (!skb)
			return 0;
		iph = skb->nh.iph;
		ip_send_check(iph);
	}
#endif

	if (iph->ihl > 5) {
		struct ip_options *opt;

		/* It looks as overkill, because not all
		   IP options require packet mangling.
		   But it is the easiest for now, especially taking
		   into account that combination of IP options
		   and running sniffer is extremely rare condition.
		                                      --ANK (980813)
		*/
		   
		skb = skb_cow(skb, skb_headroom(skb));
		if (skb == NULL)
			return 0;
		iph = skb->nh.iph;

		skb->ip_summed = 0;
		if (ip_options_compile(NULL, skb))
			goto inhdr_error;

		opt = &(IPCB(skb)->opt);
		if (opt->srr) {
			struct in_device *in_dev = dev->ip_ptr;
			if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev)) {
				if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())
					printk(KERN_INFO "source route option %d.%d.%d.%d -> %d.%d.%d.%d\n",
					       NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
				goto drop;
			}
			if (ip_options_rcv_srr(skb))
				goto drop;
		}
	}

	/*
	 *	See if the firewall wants to dispose of the packet. 
	 *
	 *	Note: the current standard firewall code expects that the 
	 *	destination address was already checked against the interface 
	 *	address lists.
	 *
	 *	If this code is ever moved in front of ip_route_input() you need
	 *	to fix the fw code [moving it might be a good idea anyways,
	 *	so that we can firewall against potentially bugs in the options
	 *	or routing code]
	 */
	
#ifdef	CONFIG_FIREWALL
        {
		int fwres;
		u16 rport;
#ifdef  CONFIG_IP_ROUTE_TOS
		u8  tos = iph->tos;
#endif

		if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport, &skb))<FW_ACCEPT) {
			if (fwres==FW_REJECT)
				icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
			goto drop;
		}

#ifdef	CONFIG_IP_TRANSPARENT_PROXY
		if (fwres==FW_REDIRECT && (IPCB(skb)->redirport = rport) != 0)
			return ip_local_deliver(skb);
#endif
#ifdef	CONFIG_IP_ROUTE_TOS
		/* It is for 2.2 only. Firewalling should make smart
		   rerouting itself, ideally, but now it is too late
		   to teach it. 			--ANK (980905)
		 */
		if (iph->tos != tos && ((struct rtable*)skb->dst)->rt_type == RTN_UNICAST) {
			dst_release(skb->dst);
			skb->dst = NULL;
			if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
				goto drop; 
		}
#endif
	}
#endif

	return skb->dst->input(skb);

inhdr_error:
	ip_statistics.IpInHdrErrors++;
drop:
        kfree_skb(skb);
        return(0);
}
예제 #13
0
/*
 * 	Deliver IP Packets to the higher protocol layers.
 */ 
int ip_local_deliver(struct sk_buff *skb)
{
	struct iphdr *iph = skb->nh.iph;
	struct inet_protocol *ipprot;
	struct sock *raw_sk=NULL;
	unsigned char hash;
	int flag = 0;

#ifndef CONFIG_IP_ALWAYS_DEFRAG
	/*
	 *	Reassemble IP fragments.
	 */

	if (iph->frag_off & htons(IP_MF|IP_OFFSET)) {
		skb = ip_defrag(skb);
		if (!skb)
			return 0;
		iph = skb->nh.iph;
	}
#endif

#ifdef CONFIG_IP_MASQUERADE
	/*
	 * Do we need to de-masquerade this packet?
	 */
        {
		int ret = ip_fw_demasquerade(&skb);
		if (ret < 0) {
			kfree_skb(skb);
			return 0;
		}

		if (ret) {
			iph=skb->nh.iph;
			IPCB(skb)->flags |= IPSKB_MASQUERADED;
			dst_release(skb->dst);
			skb->dst = NULL;
			if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev)) {
				kfree_skb(skb);
				return 0;
			}
			return skb->dst->input(skb);
		}
        }
#endif

        /*
	 *	Point into the IP datagram, just past the header.
	 */

        skb->h.raw = skb->nh.raw + iph->ihl*4;

	/*
	 *	Deliver to raw sockets. This is fun as to avoid copies we want to make no 
	 *	surplus copies.
	 *
	 *	RFC 1122: SHOULD pass TOS value up to the transport layer.
	 *	-> It does. And not only TOS, but all IP header.
	 */
 
	/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
	hash = iph->protocol & (MAX_INET_PROTOS - 1);

	/* 
	 *	If there maybe a raw socket we must check - if not we don't care less 
	 */
		 
	if((raw_sk = raw_v4_htable[hash]) != NULL) {
		struct sock *sknext = NULL;
		struct sk_buff *skb1;
		raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex);
		if(raw_sk) {	/* Any raw sockets */
			do {
				/* Find the next */
				sknext = raw_v4_lookup(raw_sk->next, iph->protocol,
						       iph->saddr, iph->daddr, skb->dev->ifindex);
				if (iph->protocol != IPPROTO_ICMP || !icmp_filter(raw_sk, skb)) {
					if (sknext == NULL)
						break;
					skb1 = skb_clone(skb, GFP_ATOMIC);
					if(skb1)
					{
						raw_rcv(raw_sk, skb1);
					}
				}
				raw_sk = sknext;
			} while(raw_sk!=NULL);
				
			/*	Here either raw_sk is the last raw socket, or NULL if
			 *	none.  We deliver to the last raw socket AFTER the
			 *	protocol checks as it avoids a surplus copy.
			 */
		}
	}
	
	/*
	 *	skb->h.raw now points at the protocol beyond the IP header.
	 */
	
	for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next)
	{
		struct sk_buff *skb2;
	
		if (ipprot->protocol != iph->protocol)
			continue;
		/*
		 * 	See if we need to make a copy of it.  This will
		 * 	only be set if more than one protocol wants it.
		 * 	and then not for the last one. If there is a pending
		 *	raw delivery wait for that
		 */
	
		if (ipprot->copy || raw_sk)
		{
			skb2 = skb_clone(skb, GFP_ATOMIC);
			if(skb2==NULL)
				continue;
		}
		else
		{
			skb2 = skb;
		}
		flag = 1;

		/*
		 *	Pass on the datagram to each protocol that wants it,
		 *	based on the datagram protocol.  We should really
		 *	check the protocol handler's return values here...
		 */

		ipprot->handler(skb2, ntohs(iph->tot_len) - (iph->ihl * 4));
	}

	/*
	 *	All protocols checked.
	 *	If this packet was a broadcast, we may *not* reply to it, since that
	 *	causes (proven, grin) ARP storms and a leakage of memory (i.e. all
	 *	ICMP reply messages get queued up for transmission...)
	 */

	if(raw_sk!=NULL)	/* Shift to last raw user */
	{
		raw_rcv(raw_sk, skb);

	}
	else if (!flag)		/* Free and report errors */
	{
		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);	
		kfree_skb(skb);
	}

	return(0);
}
예제 #14
0
파일: bcm_nat.c 프로젝트: jhbsz/DIR-850L_A1
static inline int
bcm_do_bindings(struct nf_conn *ct,
	    enum ip_conntrack_info ctinfo,
	    struct sk_buff **pskb,
		struct nf_conntrack_l4proto *l4proto)
{
	struct iphdr *iph = ip_hdr(*pskb);
	unsigned int i;
	static int hn[2] = {NF_IP_PRE_ROUTING, NF_IP_POST_ROUTING};
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
#ifdef HNDCTF
	bool enabled = ip_conntrack_is_ipc_allowed(*pskb, NF_IP_PRE_ROUTING);
#endif /* HNDCTF */

	for (i = 0; i < 2; i++) {
		enum nf_nat_manip_type mtype = HOOK2MANIP(hn[i]);
		unsigned long statusbit;

		if (mtype == IP_NAT_MANIP_SRC)
			statusbit = IPS_SRC_NAT;
		else
			statusbit = IPS_DST_NAT;

		/* Invert if this is reply dir. */
		if (dir == IP_CT_DIR_REPLY)
			statusbit ^= IPS_NAT_MASK;

		if (ct->status & statusbit) {
			struct nf_conntrack_tuple target;

			if (skb_cloned(*pskb) && !(*pskb)->sk) 
			{
				struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);

				printk("[debug %s:%d] should not happen!!\n" , __FILE__ , __LINE__);
				if (!nskb)
					return NF_DROP;

				kfree_skb(*pskb);
				*pskb = nskb;
			}

			if (skb_dst((*pskb)) == NULL && mtype == IP_NAT_MANIP_SRC) {
				struct net_device *dev = (*pskb)->dev;
				if (ip_route_input((*pskb), iph->daddr, iph->saddr, iph->tos, dev))
					return NF_DROP;
				/* Change skb owner */
				(*pskb)->dev = skb_dst((*pskb))->dev;
			}

			/* We are aiming to look like inverse of other direction. */
			ipv4_ct_invert_tuple(&target, &ct->tuplehash[!dir].tuple, l4proto);
#ifdef HNDCTF
			if (enabled)
				ip_conntrack_ipct_add(*pskb, hn[i], ct, ctinfo, &target);
#endif /* HNDCTF */
			if (!bcm_manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
				return NF_DROP;
		}
	}

	return NF_FAST_NAT;
}
예제 #15
0
static int br_nf_pre_routing_finish(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct iphdr *iph = skb->nh.iph;
	struct nf_bridge_info *nf_bridge = skb->nf_bridge;

	if (nf_bridge->mask & BRNF_PKT_TYPE) {
		skb->pkt_type = PACKET_OTHERHOST;
		nf_bridge->mask ^= BRNF_PKT_TYPE;
	}
	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;

	if (dnat_took_place(skb)) {
		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)) {
			struct rtable *rt;
			struct flowi fl = {
				.nl_u = {
					.ip4_u = {
						 .daddr = iph->daddr,
						 .saddr = 0,
						 .tos = RT_TOS(iph->tos) },
				},
				.proto = 0,
			};

			if (!ip_route_output_key(&rt, &fl)) {
				/* - Bridged-and-DNAT'ed traffic doesn't
				 *   require ip_forwarding.
				 * - Deal with redirected traffic. */
				if (((struct dst_entry *)rt)->dev == dev ||
				    rt->rt_type == RTN_LOCAL) {
					skb->dst = (struct dst_entry *)rt;
					goto bridged_dnat;
				}
				__br_dnat_complain();
				dst_release((struct dst_entry *)rt);
			}
			kfree_skb(skb);
			return 0;
		} else {
			if (skb->dst->dev == dev) {
bridged_dnat:
				/* Tell br_nf_local_out this is a
				 * bridged frame */
				nf_bridge->mask |= BRNF_BRIDGED_DNAT;
				skb->dev = nf_bridge->physindev;
				if (skb->protocol ==
				    htons(ETH_P_8021Q)) {
					skb_push(skb, VLAN_HLEN);
					skb->nh.raw -= VLAN_HLEN;
				}
				NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
					       skb, skb->dev, NULL,
					       br_nf_pre_routing_finish_bridge,
					       1);
				return 0;
			}
			memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
			skb->pkt_type = PACKET_HOST;
		}
	} else {
예제 #16
0
/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
{
	struct net *net = dev_net(skb_dst(skb)->dev);
	const struct iphdr *iph = ip_hdr(skb);
	struct rtable *rt;
	struct flowi4 fl4 = {};
	unsigned long orefdst;
	unsigned int hh_len;
	unsigned int type;

	type = inet_addr_type(net, iph->saddr);
	if (skb->sk && inet_sk(skb->sk)->transparent)
		type = RTN_LOCAL;
	if (addr_type == RTN_UNSPEC)
		addr_type = type;

	/* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
	 * packets with foreign saddr to appear on the NF_INET_LOCAL_OUT hook.
	 */
	if (addr_type == RTN_LOCAL) {
		fl4.daddr = iph->daddr;
		if (type == RTN_LOCAL)
			fl4.saddr = iph->saddr;
		fl4.flowi4_tos = RT_TOS(iph->tos);
		fl4.flowi4_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
		fl4.flowi4_mark = skb->mark;
		fl4.flowi4_flags = skb->sk ? inet_sk_flowi_flags(skb->sk) : 0;
		rt = ip_route_output_key(net, &fl4);
		if (IS_ERR(rt))
			return -1;

		/* Drop old route. */
		skb_dst_drop(skb);
		skb_dst_set(skb, &rt->dst);
	} else {
		/* non-local src, find valid iif to satisfy
		 * rp-filter when calling ip_route_input. */
		fl4.daddr = iph->saddr;
		rt = ip_route_output_key(net, &fl4);
		if (IS_ERR(rt))
			return -1;

		orefdst = skb->_skb_refdst;
		if (ip_route_input(skb, iph->daddr, iph->saddr,
				   RT_TOS(iph->tos), rt->dst.dev) != 0) {
			dst_release(&rt->dst);
			return -1;
		}
		dst_release(&rt->dst);
		refdst_drop(orefdst);
	}

	if (skb_dst(skb)->error)
		return -1;

#ifdef CONFIG_XFRM
	if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
	    xfrm_decode_session(skb, flowi4_to_flowi(&fl4), AF_INET) == 0) {
		struct dst_entry *dst = skb_dst(skb);
		skb_dst_set(skb, NULL);
		dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), skb->sk, 0);
		if (IS_ERR(dst))
			return -1;
		skb_dst_set(skb, dst);
	}
#endif

	/* Change in oif may mean change in hh_len. */
	hh_len = skb_dst(skb)->dev->hard_header_len;
	if (skb_headroom(skb) < hh_len &&
	    pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
		return -1;

	return 0;
}
예제 #17
0
파일: netfilter.c 프로젝트: 274914765/C
/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
{
    const struct iphdr *iph = ip_hdr(skb);
    struct rtable *rt;
    struct flowi fl = {};
    struct dst_entry *odst;
    unsigned int hh_len;
    unsigned int type;

    type = inet_addr_type(&init_net, iph->saddr);
    if (addr_type == RTN_UNSPEC)
        addr_type = type;

    /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
     * packets with foreign saddr to appear on the NF_INET_LOCAL_OUT hook.
     */
    if (addr_type == RTN_LOCAL) {
        fl.nl_u.ip4_u.daddr = iph->daddr;
        if (type == RTN_LOCAL)
            fl.nl_u.ip4_u.saddr = iph->saddr;
        fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
        fl.oif = skb->sk ? skb->sk->sk_bound_dev_if : 0;
        fl.mark = skb->mark;
        if (ip_route_output_key(&init_net, &rt, &fl) != 0)
            return -1;

        /* Drop old route. */
        dst_release(skb->dst);
        skb->dst = &rt->u.dst;
    } else {
        /* non-local src, find valid iif to satisfy
         * rp-filter when calling ip_route_input. */
        fl.nl_u.ip4_u.daddr = iph->saddr;
        if (ip_route_output_key(&init_net, &rt, &fl) != 0)
            return -1;

        odst = skb->dst;
        if (ip_route_input(skb, iph->daddr, iph->saddr,
                   RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
            dst_release(&rt->u.dst);
            return -1;
        }
        dst_release(&rt->u.dst);
        dst_release(odst);
    }

    if (skb->dst->error)
        return -1;

#ifdef CONFIG_XFRM
    if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
        xfrm_decode_session(skb, &fl, AF_INET) == 0)
        if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0))
            return -1;
#endif

    /* Change in oif may mean change in hh_len. */
    hh_len = skb->dst->dev->hard_header_len;
    if (skb_headroom(skb) < hh_len &&
        pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
        return -1;

    return 0;
}
예제 #18
0
static int
ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
	   u8 type, u8 code, int offset, __be32 info)
{
	int rel_msg = 0;
	u8 rel_type = type;
	u8 rel_code = code;
	__u32 rel_info = ntohl(info);
	int err;
	struct sk_buff *skb2;
	struct iphdr *eiph;
	struct flowi fl;
	struct rtable *rt;

	err = ip6_tnl_err(skb, IPPROTO_IPIP, opt, &rel_type, &rel_code,
			  &rel_msg, &rel_info, offset);
	if (err < 0)
		return err;

	if (rel_msg == 0)
		return 0;

	switch (rel_type) {
	case ICMPV6_DEST_UNREACH:
		if (rel_code != ICMPV6_ADDR_UNREACH)
			return 0;
		rel_type = ICMP_DEST_UNREACH;
		rel_code = ICMP_HOST_UNREACH;
		break;
	case ICMPV6_PKT_TOOBIG:
		if (rel_code != 0)
			return 0;
		rel_type = ICMP_DEST_UNREACH;
		rel_code = ICMP_FRAG_NEEDED;
		break;
	default:
		return 0;
	}

	if (!pskb_may_pull(skb, offset + sizeof(struct iphdr)))
		return 0;

	skb2 = skb_clone(skb, GFP_ATOMIC);
	if (!skb2)
		return 0;

	skb_dst_drop(skb2);

	skb_pull(skb2, offset);
	skb_reset_network_header(skb2);
	eiph = ip_hdr(skb2);

	/* Try to guess incoming interface */
	memset(&fl, 0, sizeof(fl));
	fl.fl4_dst = eiph->saddr;
	fl.fl4_tos = RT_TOS(eiph->tos);
	fl.proto = IPPROTO_IPIP;
	if (ip_route_output_key(dev_net(skb->dev), &rt, &fl))
		goto out;

	skb2->dev = rt->u.dst.dev;

	/* route "incoming" packet */
	if (rt->rt_flags & RTCF_LOCAL) {
		ip_rt_put(rt);
		rt = NULL;
		fl.fl4_dst = eiph->daddr;
		fl.fl4_src = eiph->saddr;
		fl.fl4_tos = eiph->tos;
		if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) ||
		    rt->u.dst.dev->type != ARPHRD_TUNNEL) {
			ip_rt_put(rt);
			goto out;
		}
		skb_dst_set(skb2, (struct dst_entry *)rt);
	} else {
		ip_rt_put(rt);
		if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
				   skb2->dev) ||
		    skb_dst(skb2)->dev->type != ARPHRD_TUNNEL)
			goto out;
	}

	/* change mtu on this route */
	if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) {
		if (rel_info > dst_mtu(skb_dst(skb2)))
			goto out;

		skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info);
	}

	icmp_send(skb2, rel_type, rel_code, htonl(rel_info));

out:
	kfree_skb(skb2);
	return 0;
}
예제 #19
0
static unsigned int
fw_in(unsigned int hooknum,
      struct sk_buff **pskb,
      const struct net_device *in,
      const struct net_device *out,
      int (*okfn)(struct sk_buff *))
{
	int ret = FW_BLOCK;
	u_int16_t redirpt;

	/* Assume worse case: any hook could change packet */
	(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		if (skb_checksum_help(*pskb, (out == NULL)))
			return NF_DROP;

	switch (hooknum) {
	case NF_IP_PRE_ROUTING:
		if (fwops->fw_acct_in)
			fwops->fw_acct_in(fwops, PF_INET,
					  (struct net_device *)in,
					  &redirpt, pskb);

		if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
			*pskb = ip_ct_gather_frags(*pskb);

			if (!*pskb)
				return NF_STOLEN;
		}

		ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
				      &redirpt, pskb);
		break;

	case NF_IP_FORWARD:
		/* Connection will only be set if it was
                   demasqueraded: if so, skip forward chain. */
		if ((*pskb)->nfct)
			ret = FW_ACCEPT;
		else ret = fwops->fw_forward(fwops, PF_INET,
					     (struct net_device *)out,
					     &redirpt, pskb);
		break;

	case NF_IP_POST_ROUTING:
		ret = fwops->fw_output(fwops, PF_INET,
				       (struct net_device *)out,
				       &redirpt, pskb);
		if (ret == FW_ACCEPT || ret == FW_SKIP) {
			if (fwops->fw_acct_out)
				fwops->fw_acct_out(fwops, PF_INET,
						   (struct net_device *)out,
						   &redirpt,
						   pskb);

			/* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
			if (ip_conntrack_confirm(*pskb) == NF_DROP)
				ret = FW_BLOCK;
		}
		break;
	}

	switch (ret) {
	case FW_REJECT: {
		/* Alexey says:
		 *
		 * Generally, routing is THE FIRST thing to make, when
		 * packet enters IP stack. Before packet is routed you
		 * cannot call any service routines from IP stack.  */
		struct iphdr *iph = (*pskb)->nh.iph;

		if ((*pskb)->dst != NULL
		    || ip_route_input(*pskb, iph->daddr, iph->saddr, iph->tos,
				      (struct net_device *)in) == 0)
			icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
				  0);
		return NF_DROP;
	}

	case FW_ACCEPT:
	case FW_SKIP:
		if (hooknum == NF_IP_PRE_ROUTING) {
			check_for_demasq(pskb);
			check_for_redirect(*pskb);
		} else if (hooknum == NF_IP_POST_ROUTING) {
			check_for_unredirect(*pskb);
			/* Handle ICMP errors from client here */
			if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
			    && (*pskb)->nfct)
				check_for_masq_error(pskb);
		}
		return NF_ACCEPT;

	case FW_MASQUERADE:
		if (hooknum == NF_IP_FORWARD) {
#ifdef CONFIG_IP_VS
			/* check if it is for ip_vs */
			if (check_for_ip_vs_out(pskb, okfn) == NF_STOLEN)
				return NF_STOLEN;
#endif
			return do_masquerade(pskb, out);
		}
		else return NF_ACCEPT;

	case FW_REDIRECT:
		if (hooknum == NF_IP_PRE_ROUTING)
			return do_redirect(*pskb, in, redirpt);
		else return NF_ACCEPT;

	default:
		/* FW_BLOCK */
		return NF_DROP;
	}
}
예제 #20
0
int ip_rcv_finish(struct sk_buff *skb)
{
        struct iphdr *iph = skb->nh.iph;
        /*
         *  Initialise the virtual path cache for the packet. It describes
         *  how the packet travels inside Linux networking.
         */
		
        if (skb->dst == NULL) {
            int err = 1;
            
            if(g_session_forward_enable)
            {
				if (skb->nfct && IP_CT_DIR_REPLY == CTINFO2DIR(skb->nfctinfo)
	                && !(((struct ff_cache_info_ex*)skb->nfct)->ff_info[IP_CT_DIR_ORIGINAL].flag & DRV_FF_FLAG_LINUX)
	                && !is_vpn_pkt(skb)){
	                sessfw_debug(1, "--- don't lookup route ---\n" TUPLE_INFO(
	                   &((struct ff_cache_info_ex*)skb->nfct)->ct.tuplehash[IP_CT_DIR_ORIGINAL].tuple,
	                   &((struct ff_cache_info_ex*)skb->nfct)->ct.tuplehash[IP_CT_DIR_REPLY].tuple));
	                err = 0;
	                goto route_label;
				}
				#ifdef CONFIG_NETSESSION
				if (skb->ns && NS_DIR_REPLY == NSINFO2DIR(skb->nsinfo) && 
					!(((struct net_session *)skb->ns)->ff_info[NS_DIR_ORIGINAL].flag & NS_FF_LINUX)){
					err = 0;
	                goto route_label;
				}
				#endif
            }
            if (0 != err)
            {
                sessfw_debug(2, "--- lookup route ---\n" TUPLE_INFO(
                   &((struct ff_cache_info_ex*)skb->nfct)->ct.tuplehash[IP_CT_DIR_ORIGINAL].tuple,
                   &((struct ff_cache_info_ex*)skb->nfct)->ct.tuplehash[IP_CT_DIR_REPLY].tuple));
                err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
                         skb->dev);                
            }
			
            
route_label:
            if (unlikely(err)) {
                if (err == -EHOSTUNREACH)
                    IP_INC_STATS_BH(if_dev_vrf(skb->dev), IPSTATS_MIB_INADDRERRORS);
                goto drop;
            }
        }

        if (iph->ihl > 5 && ip_rcv_options(skb))
    	{
			goto drop;
    	}
            //goto drop;

        
        /*A new entry of mcast packet. add by wangdi*/
        if (MULTICAST(iph->daddr))
        {
            return ipv4_mcast_rcv(skb, iph);
        }
		else if (g_session_forward_enable)
		{
			s32 ret;
			ret = session_forward_fix[ns_mode](skb);
			if (ret != 2)
				return ret;
			else
				return dst_input(skb);/* 没匹配上会话转发 */
		}
        else
            return dst_input(skb);

    drop:
        kfree_skb(skb);
        return NET_RX_DROP;
}
예제 #21
0
/* This requires some explaining. If DNAT has taken place,
 * we will need to fix up the destination Ethernet address.
 * This is also true when SNAT takes place (for the reply direction).
 *
 * There are two cases to consider:
 * 1. The packet was DNAT'ed to a device in the same bridge
 *    port group as it was received on. We can still bridge
 *    the packet.
 * 2. The packet was DNAT'ed to a different device, either
 *    a non-bridged device or another bridge port group.
 *    The packet will need to be routed.
 *
 * The correct way of distinguishing between these two cases is to
 * call ip_route_input() and to look at skb->dst->dev, which is
 * changed to the destination device if ip_route_input() succeeds.
 *
 * Let's first consider the case that ip_route_input() succeeds:
 *
 * If the output device equals the logical bridge device the packet
 * came in on, we can consider this bridging. The corresponding MAC
 * address will be obtained in br_nf_pre_routing_finish_bridge.
 * Otherwise, the packet is considered to be routed and we just
 * change the destination MAC address so that the packet will
 * later be passed up to the IP stack to be routed. For a redirected
 * packet, ip_route_input() will give back the localhost as output device,
 * which differs from the bridge device.
 *
 * Let's now consider the case that ip_route_input() fails:
 *
 * This can be because the destination address is martian, in which case
 * the packet will be dropped.
 * If IP forwarding is disabled, ip_route_input() will fail, while
 * ip_route_output_key() can return success. The source
 * address for ip_route_output_key() is set to zero, so ip_route_output_key()
 * thinks we're handling a locally generated packet and won't care
 * if IP forwarding is enabled. If the output device equals the logical bridge
 * device, we proceed as if ip_route_input() succeeded. If it differs from the
 * logical bridge port or if ip_route_output_key() fails we drop the packet.
 */
static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct iphdr *iph = ip_hdr(skb);
	struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
	struct rtable *rt;
	int err;

	nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;

	if (nf_bridge->pkt_otherhost) {
		skb->pkt_type = PACKET_OTHERHOST;
		nf_bridge->pkt_otherhost = false;
	}
	nf_bridge->in_prerouting = 0;
	if (br_nf_ipv4_daddr_was_changed(skb, nf_bridge)) {
		if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
			struct in_device *in_dev = __in_dev_get_rcu(dev);

			/* If err equals -EHOSTUNREACH the error is due to a
			 * martian destination or due to the fact that
			 * forwarding is disabled. For most martian packets,
			 * ip_route_output_key() will fail. It won't fail for 2 types of
			 * martian destinations: loopback destinations and destination
			 * 0.0.0.0. In both cases the packet will be dropped because the
			 * destination is the loopback device and not the bridge. */
			if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
				goto free_skb;

			rt = ip_route_output(net, iph->daddr, 0,
					     RT_TOS(iph->tos), 0);
			if (!IS_ERR(rt)) {
				/* - Bridged-and-DNAT'ed traffic doesn't
				 *   require ip_forwarding. */
				if (rt->dst.dev == dev) {
					skb_dst_set(skb, &rt->dst);
					goto bridged_dnat;
				}
				ip_rt_put(rt);
			}
free_skb:
			kfree_skb(skb);
			return 0;
		} else {
			if (skb_dst(skb)->dev == dev) {
bridged_dnat:
				skb->dev = nf_bridge->physindev;
				nf_bridge_update_protocol(skb);
				nf_bridge_push_encap_header(skb);
				br_nf_hook_thresh(NF_BR_PRE_ROUTING,
						  net, sk, skb, skb->dev,
						  NULL,
						  br_nf_pre_routing_finish_bridge);
				return 0;
			}
			ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
			skb->pkt_type = PACKET_HOST;
		}
	} else {
		rt = bridge_parent_rtable(nf_bridge->physindev);
		if (!rt) {
			kfree_skb(skb);
			return 0;
		}
		skb_dst_set_noref(skb, &rt->dst);
	}

	skb->dev = nf_bridge->physindev;
	nf_bridge_update_protocol(skb);
	nf_bridge_push_encap_header(skb);
	br_nf_hook_thresh(NF_BR_PRE_ROUTING, net, sk, skb, skb->dev, NULL,
			  br_handle_frame_finish);
	return 0;
}
예제 #22
0
/*
 * 	Main IP Receive routine.
 */
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
	struct iphdr *iph;
	u32 len;
    u32 ret = 0;
    char *raw;
    struct udphdr	*uh;

	/* When the interface is in promisc. mode, drop all the crap
	 * that it receives, do not try to analyse it.
	 */
	raw = (char*)skb->nh.iph + skb->nh.iph->ihl *4;
    uh = (struct udphdr	*)raw;

	/* just for debug... */
    SNIFFER_PACKET(SNIFFER_MODULE_IP, skb, in, NF_ACCEPT);

    skb->vid = 0;

	if (skb->pkt_type == PACKET_OTHERHOST)
		goto drop;

	if (skb->ucbitflag & SKB_FLAG_MPLS_PACKET)
	{
		dev = __if_dev_get_by_index((IF_DEV_TYPE_LO << 24) | skb->fpga_vrf_id);
		if (dev)
		{
    		skb->dev = dev;		
    		skb->iif = (IF_DEV_TYPE_LO << 24) | skb->fpga_vrf_id;
		}
		else
		{
		    skb->litevrf_id = skb->fpga_vrf_id;
		}
	}	

	IP_INC_STATS_BH(if_dev_vrf(dev), IPSTATS_MIB_INRECEIVES);

	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
		IP_INC_STATS_BH(if_dev_vrf(dev), IPSTATS_MIB_INDISCARDS);
		goto out;
	}
	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
		goto inhdr_error;
	iph = skb->nh.iph;

	/*
	 *	RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
	 *
	 *	Is the datagram acceptable?
	 *
	 *	1.	Length at least the size of an ip header
	 *	2.	Version of 4
	 *	3.	Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *	4.	Doesn't have a bogus length
	 */

	if (iph->ihl < 5 || iph->version != 4)
		goto inhdr_error;

	if (!pskb_may_pull(skb, iph->ihl*4))
		goto inhdr_error;

	iph = skb->nh.iph;

	if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
		goto inhdr_error;

	len = ntohs(iph->tot_len);
	if (skb->len < len || len < (iph->ihl*4))
		goto inhdr_error;   

	/* Our transport medium may have padded the buffer out. Now we know it
	 * is IP we can trim to the true length of the frame.
	 * Note this now means skb->len holds ntohs(iph->tot_len).
	 */
	if (pskb_trim_rcsum(skb, len)) {
		IP_INC_STATS_BH(if_dev_vrf(dev), IPSTATS_MIB_INDISCARDS);
		goto drop;
	}
    if(0 == skb->litevrf_id)
    {
        skb->litevrf_id = if_dev_litevrf_id(skb->dev);
    }    
    if (skb->nh.iph->ttl == 0 && g_icmp_status.exc_ttl == IP_OPTION_SUPPORT)
    {
         ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev);
        
         icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
         goto drop;
    }
    
#ifdef CONFIG_NLM_NET_OPTS
	*(uint64_t *)(unsigned long)IPCB(skb) = 0;
	*(uint64_t *)((unsigned long)IPCB(skb)+8) = 0;
#else    
	/* Remove any debris in the socket control block */
	memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
#endif

	if(IPPROTO_RSVP == iph->protocol)
	{
		__rsvp_input__(skb);
		return NF_STOLEN;
	}

    /* web认证pre_routing入口 */
    if(sg_webauth_switch)
    {
        if (NULL != conplat_handle_webauth)
        {
            ret = conplat_handle_webauth(NF_IP_PRE_ROUTING, &skb, dev, NULL, NULL);
            if (NF_DROP == ret)
            {
                goto drop;
            }
            if (NF_STOLEN == ret)
            {
                return NF_STOLEN;
            }

        }
    }
    /*web监听pre_routing 入口*/
    if((!sg_webauth_switch || (NF_REPEAT == ret))&& (NULL != conplat_handle_web_listen))
    {   
        
         ret = conplat_handle_web_listen(NF_IP_PRE_ROUTING, &skb, dev, NULL, NULL);
         if (NF_DROP == ret)
         {
                goto drop;
         }
         if (NF_STOLEN == ret)
         {
             return NF_STOLEN;
         }
         
    }	
	if(GET_UNDISCOVERED_NEIGHBOUR(skb))
		return ip_rcv_finish(skb);

    /*Packet route for mpls*/
    if(ip_route_mpls(skb))
    {
        dev = init_vrf.loopback_dev;
    }
    
	return NS_HOOK(NS_IP_PRE_ROUTING, PF_INET, skb, dev, NULL, ip_rcv_finish);
inhdr_error:
	IP_INC_STATS_BH(if_dev_vrf(dev), IPSTATS_MIB_INHDRERRORS);
drop:
	kfree_skb(skb);
out:
	return NET_RX_DROP;
}
예제 #23
0
/* Reroute packet to local IPv4 stack after DNAT */
static int
__ip_vs_reroute_locally(struct sk_buff *skb)
{
    struct rtable *rt = skb_rtable(skb);
    struct net_device *dev = rt->dst.dev;
    struct net *net = dev_net(dev);
    struct iphdr *iph = ip_hdr(skb);

    if (rt_is_input_route(rt)) {
        unsigned long orefdst = skb->_skb_refdst;

        if (ip_route_input(skb, iph->daddr, iph->saddr,
                           iph->tos, skb->dev))
            return 0;
        refdst_drop(orefdst);
    } else {
        struct flowi4 fl4 = {
            .daddr = iph->daddr,
            .saddr = iph->saddr,
            .flowi4_tos = RT_TOS(iph->tos),
            .flowi4_mark = skb->mark,
        };

        rt = ip_route_output_key(net, &fl4);
        if (IS_ERR(rt))
            return 0;
        if (!(rt->rt_flags & RTCF_LOCAL)) {
            ip_rt_put(rt);
            return 0;
        }
        /* Drop old route. */
        skb_dst_drop(skb);
        skb_dst_set(skb, &rt->dst);
    }
    return 1;
}

#ifdef CONFIG_IP_VS_IPV6

static inline int __ip_vs_is_local_route6(struct rt6_info *rt)
{
    return rt->rt6i_dev && rt->rt6i_dev->flags & IFF_LOOPBACK;
}

static struct dst_entry *
__ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr,
                        struct in6_addr *ret_saddr, int do_xfrm)
{
    struct dst_entry *dst;
    struct flowi6 fl6 = {
        .daddr = *daddr,
    };

    dst = ip6_route_output(net, NULL, &fl6);
    if (dst->error)
        goto out_err;
    if (!ret_saddr)
        return dst;
    if (ipv6_addr_any(&fl6.saddr) &&
            ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev,
                               &fl6.daddr, 0, &fl6.saddr) < 0)
        goto out_err;
    if (do_xfrm) {
        dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
        if (IS_ERR(dst)) {
            dst = NULL;
            goto out_err;
        }
    }
    ipv6_addr_copy(ret_saddr, &fl6.saddr);
    return dst;

out_err:
    dst_release(dst);
    IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n", daddr);
    return NULL;
}

/*
 * Get route to destination or remote server
 * rt_mode: flags, &1=Allow local dest, &2=Allow non-local dest,
 *	    &4=Allow redirect from remote daddr to local
 */
static struct rt6_info *
__ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
                      struct in6_addr *daddr, struct in6_addr *ret_saddr,
                      int do_xfrm, int rt_mode)
{
    struct net *net = dev_net(skb_dst(skb)->dev);
    struct rt6_info *rt;			/* Route to the other host */
    struct rt6_info *ort;			/* Original route */
    struct dst_entry *dst;
    int local;

    if (dest) {
        spin_lock(&dest->dst_lock);
        rt = (struct rt6_info *)__ip_vs_dst_check(dest, 0);
        if (!rt) {
            u32 cookie;

            dst = __ip_vs_route_output_v6(net, &dest->addr.in6,
                                          &dest->dst_saddr,
                                          do_xfrm);
            if (!dst) {
                spin_unlock(&dest->dst_lock);
                return NULL;
            }
            rt = (struct rt6_info *) dst;
            cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
            __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie);
            IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n",
                      &dest->addr.in6, &dest->dst_saddr,
                      atomic_read(&rt->dst.__refcnt));
        }
        if (ret_saddr)
            ipv6_addr_copy(ret_saddr, &dest->dst_saddr);
        spin_unlock(&dest->dst_lock);
    } else {
        dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm);
        if (!dst)
            return NULL;
        rt = (struct rt6_info *) dst;
    }

    local = __ip_vs_is_local_route6(rt);
    if (!((local ? 1 : 2) & rt_mode)) {
        IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6\n",
                     local ? "local":"non-local", daddr);
        dst_release(&rt->dst);
        return NULL;
    }
    if (local && !(rt_mode & 4) &&
            !((ort = (struct rt6_info *) skb_dst(skb)) &&
              __ip_vs_is_local_route6(ort))) {
        IP_VS_DBG_RL("Redirect from non-local address %pI6 to local "
                     "requires NAT method, dest: %pI6\n",
                     &ipv6_hdr(skb)->daddr, daddr);
        dst_release(&rt->dst);
        return NULL;
    }
    if (unlikely(!local && (!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
                 ipv6_addr_type(&ipv6_hdr(skb)->saddr) &
                 IPV6_ADDR_LOOPBACK)) {
        IP_VS_DBG_RL("Stopping traffic from loopback address %pI6 "
                     "to non-local address, dest: %pI6\n",
                     &ipv6_hdr(skb)->saddr, daddr);
        dst_release(&rt->dst);
        return NULL;
    }

    return rt;
}
#endif


/*
 *	Release dest->dst_cache before a dest is removed
 */
void
ip_vs_dst_reset(struct ip_vs_dest *dest)
{
    struct dst_entry *old_dst;

    old_dst = dest->dst_cache;
    dest->dst_cache = NULL;
    dst_release(old_dst);
}

#define IP_VS_XMIT_TUNNEL(skb, cp)				\
({								\
	int __ret = NF_ACCEPT;					\
								\
	(skb)->ipvs_property = 1;				\
	if (unlikely((cp)->flags & IP_VS_CONN_F_NFCT))		\
		__ret = ip_vs_confirm_conntrack(skb, cp);	\
	if (__ret == NF_ACCEPT) {				\
		nf_reset(skb);					\
		skb_forward_csum(skb);				\
	}							\
	__ret;							\
})

#define IP_VS_XMIT_NAT(pf, skb, cp, local)		\
do {							\
	(skb)->ipvs_property = 1;			\
	if (likely(!((cp)->flags & IP_VS_CONN_F_NFCT)))	\
		ip_vs_notrack(skb);			\
	else						\
		ip_vs_update_conntrack(skb, cp, 1);	\
	if (local)					\
		return NF_ACCEPT;			\
	skb_forward_csum(skb);				\
	NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL,	\
		skb_dst(skb)->dev, dst_output);		\
} while (0)

#define IP_VS_XMIT(pf, skb, cp, local)			\
do {							\
	(skb)->ipvs_property = 1;			\
	if (likely(!((cp)->flags & IP_VS_CONN_F_NFCT)))	\
		ip_vs_notrack(skb);			\
	if (local)					\
		return NF_ACCEPT;			\
	skb_forward_csum(skb);				\
	NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL,	\
		skb_dst(skb)->dev, dst_output);		\
} while (0)


/*
 *      NULL transmitter (do nothing except return NF_ACCEPT)
 */
int
ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                struct ip_vs_protocol *pp)
{
    /* we do not touch skb and do not need pskb ptr */
    IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
}
예제 #24
0
static int ip_rcv_finish(struct sk_buff *skb)
{
	const struct iphdr *iph = ip_hdr(skb);
	struct rtable *rt;

	/*
	 *	Initialise the virtual path cache for the packet. It describes
	 *	how the packet travels inside Linux networking.
	 */
	if (skb->dst == NULL) {
		int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
					 skb->dev);
		if (unlikely(err)) {
			if (err == -EHOSTUNREACH)
				IP_INC_STATS_BH(dev_net(skb->dev),
						IPSTATS_MIB_INADDRERRORS);
			else if (err == -ENETUNREACH)
				IP_INC_STATS_BH(dev_net(skb->dev),
						IPSTATS_MIB_INNOROUTES);
			goto drop;
		}
	}
#if defined (CONFIG_RTL_819X)
	/*to fix guest can access local web ui*/
	#include <linux/udp.h>
        if (skb->dst->input == &ip_local_deliver) {
                if (skb->__unused == 0xe5 && iph->protocol== IPPROTO_UDP) {
                        struct udphdr *hdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
                        if (hdr->dest == 53 || hdr->dest == 67) // DNS Domain or dhcp
                                skb->__unused = 0;
                }

                if (skb->__unused == 0xe5 && iph->protocol== IPPROTO_TCP) {
                        struct udphdr *hdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
                        if (hdr->dest == 52869) // IGD port
                                skb->__unused = 0;
                }

                if (skb->__unused == 0xe5)
                        goto drop;
        }
#endif
#ifdef CONFIG_NET_CLS_ROUTE
	if (unlikely(skb->dst->tclassid)) {
		struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
		u32 idx = skb->dst->tclassid;
		st[idx&0xFF].o_packets++;
		st[idx&0xFF].o_bytes += skb->len;
		st[(idx>>16)&0xFF].i_packets++;
		st[(idx>>16)&0xFF].i_bytes += skb->len;
	}
#endif

	if (iph->ihl > 5 && ip_rcv_options(skb))
		goto drop;

	rt = skb->rtable;
	if (rt->rt_type == RTN_MULTICAST)
		IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCASTPKTS);
	else if (rt->rt_type == RTN_BROADCAST)
		IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCASTPKTS);

	return dst_input(skb);

drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}