static inline int ip_rcv_options(struct sk_buff *skb) { struct ip_options *opt; struct iphdr *iph; struct net_device *dev = skb->dev; /* 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))) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); goto drop; } iph = ip_hdr(skb); opt = &(IPCB(skb)->opt); opt->optlen = iph->ihl*4 - sizeof(struct iphdr); if (ip_options_compile(dev_net(dev), opt, skb)) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS); goto drop; } if (unlikely(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 " NIPQUAD_FMT " -> " NIPQUAD_FMT "\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; } return 0; drop: return -1; }
static void icmp_address_reply(struct icmphdr *icmph, struct sk_buff *skb, int len) { struct rtable *rt = (struct rtable*)skb->dst; struct device *dev = skb->dev; struct in_device *in_dev = dev->ip_ptr; struct in_ifaddr *ifa; u32 mask; if (!in_dev || !in_dev->ifa_list || !IN_DEV_LOG_MARTIANS(in_dev) || !IN_DEV_FORWARD(in_dev) || len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC)) return; mask = *(u32*)&icmph[1]; for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa)) return; } if (sysctl_ip_always_defrag == 0 && net_ratelimit()) printk(KERN_INFO "Wrong address mask %08lX from %08lX/%s\n", ntohl(mask), ntohl(rt->rt_src), dev->name); }
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; }
/* * 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); }