static int rmnet_map_ipv6_dl_csum_trailer(struct sk_buff *skb, struct rmnet_map_dl_csum_trailer *csum_trailer) { __sum16 *csum_field, ip6_payload_csum, pseudo_csum, csum_temp; u16 csum_value, csum_value_final; __be16 ip6_hdr_csum, addend; struct ipv6hdr *ip6h; void *txporthdr; u32 length; ip6h = (struct ipv6hdr *)(skb->data); txporthdr = skb->data + sizeof(struct ipv6hdr); csum_field = rmnet_map_get_csum_field(ip6h->nexthdr, txporthdr); if (!csum_field) return -EPROTONOSUPPORT; csum_value = ~ntohs(csum_trailer->csum_value); ip6_hdr_csum = (__force __be16) ~ntohs((__force __be16)ip_compute_csum(ip6h, (int)(txporthdr - (void *)(skb->data)))); ip6_payload_csum = csum16_sub((__force __sum16)csum_value, ip6_hdr_csum); length = (ip6h->nexthdr == IPPROTO_UDP) ? ntohs(((struct udphdr *)txporthdr)->len) : ntohs(ip6h->payload_len); pseudo_csum = ~(csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, length, ip6h->nexthdr, 0)); addend = (__force __be16)ntohs((__force __be16)pseudo_csum); pseudo_csum = csum16_add(ip6_payload_csum, addend); addend = (__force __be16)ntohs((__force __be16)*csum_field); csum_temp = ~csum16_sub(pseudo_csum, addend); csum_value_final = (__force u16)csum_temp; if (unlikely(csum_value_final == 0)) { switch (ip6h->nexthdr) { case IPPROTO_UDP: /* RFC 2460 section 8.1 * DL6 One's complement rule for UDP checksum 0 */ csum_value_final = ~csum_value_final; break; case IPPROTO_TCP: /* DL6 Non-RFC compliant TCP checksum found */ if (*csum_field == (__force __sum16)0xFFFF) csum_value_final = ~csum_value_final; break; } } if (csum_value_final == ntohs((__force __be16)*csum_field)) return 0; else return -EINVAL; }
static void igmp_send_report(struct device *dev, unsigned long address, int type) { struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC); int tmp; struct igmphdr *ih; if(skb==NULL) return; if (type != IGMP_HOST_LEAVE_MESSAGE) tmp=ip_build_header(skb, dev->pa_addr, address, &dev, IPPROTO_IGMP, NULL, 28 , 0, 1, NULL); else tmp=ip_build_header(skb, dev->pa_addr, IGMP_ALL_ROUTER, &dev, IPPROTO_IGMP, NULL, 28, 0, 1, NULL); if(tmp<0) { kfree_skb(skb, FREE_WRITE); return; } ih=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr)); ih->type=type; ih->code=0; ih->csum=0; ih->group=address; ih->csum=ip_compute_csum((void *)ih,sizeof(struct igmphdr)); /* Checksum fill */ ip_queue_xmit(NULL,dev,skb,1); }
static int igmp_send_report(struct device *dev, u32 group, int type) { struct sk_buff *skb; struct iphdr *iph; struct igmphdr *ih; struct rtable *rt; u32 dst; /* According to IGMPv2 specs, LEAVE messages are * sent to all-routers group. */ dst = group; if (type == IGMP_HOST_LEAVE_MESSAGE) dst = IGMP_ALL_ROUTER; if (ip_route_output(&rt, dst, 0, 0, dev->ifindex)) return -1; if (rt->rt_src == 0) { ip_rt_put(rt); return -1; } skb=alloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC); if (skb == NULL) { ip_rt_put(rt); return -1; } skb->dst = &rt->u.dst; skb_reserve(skb, (dev->hard_header_len+15)&~15); skb->nh.iph = iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4); iph->version = 4; iph->ihl = (sizeof(struct iphdr)+4)>>2; iph->tos = 0; iph->frag_off = 0; iph->ttl = 1; iph->daddr = dst; iph->saddr = rt->rt_src; iph->protocol = IPPROTO_IGMP; iph->tot_len = htons(IGMP_SIZE); iph->id = htons(ip_id_count++); ((u8*)&iph[1])[0] = IPOPT_RA; ((u8*)&iph[1])[1] = 4; ((u8*)&iph[1])[2] = 0; ((u8*)&iph[1])[3] = 0; ip_send_check(iph); ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr)); ih->type=type; ih->code=0; ih->csum=0; ih->group=group; ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr)); return skb->dst->output(skb); }
static int pim6_rcv(struct sk_buff *skb) { struct pimreghdr *pim; struct ipv6hdr *encap; struct net_device *reg_dev = NULL; if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) goto drop; pim = (struct pimreghdr *)skb_transport_header(skb); if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) || (pim->flags & PIM_NULL_REGISTER) || (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && csum_fold(skb_checksum(skb, 0, skb->len, 0)))) goto drop; /* check if the inner packet is destined to mcast group */ encap = (struct ipv6hdr *)(skb_transport_header(skb) + sizeof(*pim)); if (!ipv6_addr_is_multicast(&encap->daddr) || encap->payload_len == 0 || ntohs(encap->payload_len) + sizeof(*pim) > skb->len) goto drop; read_lock(&mrt_lock); if (reg_vif_num >= 0) reg_dev = vif6_table[reg_vif_num].dev; if (reg_dev) dev_hold(reg_dev); read_unlock(&mrt_lock); if (reg_dev == NULL) goto drop; skb->mac_header = skb->network_header; skb_pull(skb, (u8 *)encap - skb->data); skb_reset_network_header(skb); skb->dev = reg_dev; skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; dst_release(skb->dst); ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len; ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++; skb->dst = NULL; nf_reset(skb); netif_rx(skb); dev_put(reg_dev); return 0; drop: kfree_skb(skb); return 0; }
int igmp_send_report_full(struct net_device *dev, u32 group, int type, u8 respond, u32 dst) { struct sk_buff *skb; struct iphdr *iph; struct igmphdr *ih; struct rtable *rt; if (ip_route_output(&rt, dst, 0, 0, dev->ifindex)) return -1; if (rt->rt_src == 0) { ip_rt_put(rt); return -1; } skb=alloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC); if (skb == NULL) { ip_rt_put(rt); return -1; } skb->dst = &rt->u.dst; skb_reserve(skb, (dev->hard_header_len+15)&~15); skb->nh.iph = iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4); iph->version = 4; iph->ihl = (sizeof(struct iphdr)+4)>>2; iph->tos = 0; iph->frag_off = htons(IP_DF); iph->ttl = 1; iph->daddr = dst; iph->saddr = rt->rt_src; iph->protocol = IPPROTO_IGMP; iph->tot_len = htons(IGMP_SIZE); ip_select_ident(iph, &rt->u.dst, NULL); ((u8*)&iph[1])[0] = IPOPT_RA; ((u8*)&iph[1])[1] = 4; ((u8*)&iph[1])[2] = 0; ((u8*)&iph[1])[3] = 0; ip_send_check(iph); ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr)); ih->type=type; ih->code=respond; ih->csum=0; ih->group=group; ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr)); return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, output_maybe_reroute); }
int icmp_rcv(struct sk_buff *skb, unsigned short len) { struct icmphdr *icmph = skb->h.icmph; struct rtable *rt = (struct rtable*)skb->dst; icmp_statistics.IcmpInMsgs++; /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded. */ if(len < sizeof(struct icmphdr) || ip_compute_csum((unsigned char *) icmph, len) || icmph->type > NR_ICMP_TYPES) goto error; /* * Parse the ICMP message */ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) { /* * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be * silently ignored (we let user decide with a sysctl). * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently * discarded if to broadcast/multicast. */ if (icmph->type == ICMP_ECHO && sysctl_icmp_echo_ignore_broadcasts) { goto error; } if (icmph->type != ICMP_ECHO && icmph->type != ICMP_TIMESTAMP && icmph->type != ICMP_ADDRESS && icmph->type != ICMP_ADDRESSREPLY) { goto error; } } len -= sizeof(struct icmphdr); (*icmp_pointers[icmph->type].input)++; (icmp_pointers[icmph->type].handler)(icmph, skb, len); drop: kfree_skb(skb); return 0; error: icmp_statistics.IcmpInErrors++; goto drop; }
int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, __u32 daddr, unsigned short len, __u32 saddr, int redo, struct inet_protocol *protocol) { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *ih; /* * Mrouted needs to able to query local interfaces. So * report for the device this was sent at. (Which can * be the loopback this time) */ if(dev->flags&IFF_LOOPBACK) { dev=ip_dev_find(saddr); if(dev==NULL) dev=&loopback_dev; } ih=(struct igmphdr *)skb->h.raw; if(len <sizeof(struct igmphdr) || skb->ip_hdr->ttl<1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr))) { kfree_skb(skb, FREE_READ); return 0; } /* * I have a report that someone does this! */ if(saddr==0) { printk(KERN_INFO "Broken multicast host using 0.0.0.0 heard on %s\n", dev->name); kfree_skb(skb, FREE_READ); return 0; } if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS) igmp_heard_query(dev,ih->code); if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group) igmp_heard_report(dev,ih->group, saddr); if(ih->type==IGMP_HOST_NEW_MEMBERSHIP_REPORT && daddr==ih->group) igmp_heard_report(dev,ih->group, saddr); kfree_skb(skb, FREE_READ); return 0; }
int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, unsigned long daddr, unsigned short len, unsigned long saddr, int redo, struct inet_protocol *protocol) { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *igh=(struct igmphdr *)skb->h.raw; if(skb->ip_hdr->ttl!=1 || ip_compute_csum((void *)igh,sizeof(*igh))) { kfree_skb(skb, FREE_READ); return 0; } if(igh->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS) igmp_heard_query(dev); if(igh->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==igh->group) igmp_heard_report(dev,igh->group); kfree_skb(skb, FREE_READ); return 0; }
int igmp_rcv(struct sk_buff *skb, unsigned short len) { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *ih = skb->h.igmph; struct in_device *in_dev = skb->dev->ip_ptr; if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len) || in_dev==NULL) { kfree_skb(skb); return 0; } switch (ih->type) { case IGMP_HOST_MEMBERSHIP_QUERY: igmp_heard_query(in_dev, ih->code, ih->group); break; case IGMP_HOST_MEMBERSHIP_REPORT: case IGMP_HOST_NEW_MEMBERSHIP_REPORT: /* Is it our report looped back? */ if (((struct rtable*)skb->dst)->key.iif == 0) break; igmp_heard_report(in_dev, ih->group); break; case IGMP_PIM: #ifdef CONFIG_IP_PIMSM_V1 return pim_rcv_v1(skb, len); #endif case IGMP_DVMRP: case IGMP_TRACE: case IGMP_HOST_LEAVE_MESSAGE: case IGMP_MTRACE: case IGMP_MTRACE_RESP: break; default: NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type)); } kfree_skb(skb); return 0; }
static bool ipv4_validate_packet_len(struct sk_buff *skb_in, struct sk_buff *skb_out) { struct iphdr *ip4_hdr = ip_hdr(skb_out); if (skb_out->len <= skb_out->dev->mtu) return true; if (ip4_hdr->protocol == IPPROTO_ICMP) { struct icmphdr *icmp4_hdr = icmp_hdr(skb_out); if (is_icmp4_error(icmp4_hdr->type)) { int new_packet_len = skb_out->dev->mtu; skb_trim(skb_out, new_packet_len); ip4_hdr->tot_len = cpu_to_be16(new_packet_len); ip4_hdr->check = 0; ip4_hdr->check = ip_fast_csum(ip4_hdr, ip4_hdr->ihl); icmp4_hdr->checksum = 0; icmp4_hdr->checksum = ip_compute_csum(icmp4_hdr, new_packet_len - 4 * ip4_hdr->ihl); return true; } } if (is_dont_fragment_set(ip4_hdr)) { unsigned int ipv6_mtu = skb_in->dev->mtu; unsigned int ipv4_mtu = skb_out->dev->mtu; log_debug("Packet is too large for the outgoing MTU and the DF flag is set. Dropping..."); icmpv6_send(skb_in, ICMPV6_PKT_TOOBIG, 0, cpu_to_be32(min_uint(ipv4_mtu, ipv6_mtu - 20))); return false; } /* The kernel will fragment it. */ return true; }
static void igmp_send_report(struct device *dev, unsigned long address, int type) { struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC); int tmp; struct igmphdr *igh; if(skb==NULL) return; tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL, skb->mem_len, 0, 1); if(tmp<0) { kfree_skb(skb, FREE_WRITE); return; } igh=(struct igmphdr *)(skb->data+tmp); skb->len=tmp+sizeof(*igh); igh->csum=0; igh->unused=0; igh->type=type; igh->group=address; igh->csum=ip_compute_csum((void *)igh,sizeof(*igh)); ip_queue_xmit(NULL,dev,skb,1); }
__initfunc(int whitehole_init(struct device *dev)) { dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) return -ENOBUFS; memset(dev->priv, 0, sizeof(struct net_device_stats)); dev->get_stats = whitehole_get_stats; dev->hard_start_xmit = whitehole_xmit; dev->open = whitehole_open; dev->stop = whitehole_close; ether_setup(dev); dev->tx_queue_len = 0; dev->flags |= IFF_NOARP; dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST); dev->iflink = 0; whitehole_iph.ihl = 5; whitehole_iph.version = 4; whitehole_iph.ttl = 2; whitehole_iph.saddr = in_aton("193.233.7.21"); whitehole_iph.daddr = in_aton("193.233.7.10"); whitehole_iph.tot_len = htons(20); whitehole_iph.check = ip_compute_csum((void *)&whitehole_iph, 20); return 0; }
int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, __u32 daddr, unsigned short len, __u32 saddr, int redo, struct inet_protocol *protocol) { struct icmphdr *icmph=(void *)skb->h.raw; #ifdef CONFIG_IP_TRANSPARENT_PROXY int r; #endif icmp_statistics.IcmpInMsgs++; if(len < sizeof(struct icmphdr)) { icmp_statistics.IcmpInErrors++; NETDEBUG(printk(KERN_INFO "ICMP: runt packet\n")); kfree_skb(skb, FREE_READ); return 0; } /* * Validate the packet */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ icmp_statistics.IcmpInErrors++; NETDEBUG(printk(KERN_INFO "ICMP: failed checksum from %s!\n", in_ntoa(saddr))); kfree_skb(skb, FREE_READ); return(0); } /* * 18 is the highest 'known' ICMP type. Anything else is a mystery * * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded. */ if(icmph->type > 18) { icmp_statistics.IcmpInErrors++; /* Is this right - or do we ignore ? */ kfree_skb(skb,FREE_READ); return(0); } /* * Parse the ICMP message */ #ifdef CONFIG_IP_TRANSPARENT_PROXY /* * We may get non-local addresses and still want to handle them * locally, due to transparent proxying. * Thus, narrow down the test to what is really meant. */ if (daddr!=dev->pa_addr && ((r = ip_chk_addr(daddr)) == IS_BROADCAST || r == IS_MULTICAST)) #else if (daddr && daddr!=dev->pa_addr && ip_chk_addr(daddr) != IS_MYADDR) #endif { /* * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be silently ignored (we don't as it is used * by some network mapping tools). * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently discarded if to broadcast/multicast. */ if (icmph->type != ICMP_ECHO) { icmp_statistics.IcmpInErrors++; kfree_skb(skb, FREE_READ); return(0); } /* * Reply the multicast/broadcast using a legal * interface - in this case the device we got * it from. */ daddr=dev->pa_addr; } len-=sizeof(struct icmphdr); (*icmp_pointers[icmph->type].input)++; (icmp_pointers[icmph->type].handler)(icmph,skb,skb->dev,saddr,daddr,len); return 0; }
int udp_user_read(int fd, void *buf, int len, struct udp_data *pri) { char buffer[BUF_SIZE], *udpStart = buffer + sizeof(struct iphdr); CHECK_SOCKET(fd); #ifdef INCLUDE_MAC #error INCLUDE_MAC support does not work #endif const int invalidPacketLen = -1; struct sockaddr_in srcAddr; int srcAddrLen = sizeof(struct sockaddr_in); int rcv_packet_len = invalidPacketLen; __u32 srcIP; if ((rcv_packet_len = recvfrom(fd, udpStart, BUF_SIZE, 0, (struct sockaddr *) & srcAddr, &srcAddrLen)) <= 0) { //DEBUG(1, "recvfrom"); return 0; } srcIP = srcAddr.sin_addr.s_addr; if(rcv_packet_len > 0) { DEBUG(2,"Packet recv'd(%d); need to perform unwrap operation\n", rcv_packet_len); /* XXX Copy unwrap code from kernel-level skbuff reorg stuff * */ struct ipudp *iuh = (struct ipudp *)udpStart; char *dataStart = (char*)(iuh + 1); struct iphdr *iph = ((struct iphdr*)dataStart) - 1; struct tcphdr *th = (struct tcphdr *)dataStart; int cookedLen = rcv_packet_len - sizeof(struct ipudp) + sizeof(struct iphdr); if(cookedLen < sizeof(struct tcphdr)) { printk("Cooked length is shorter than minimum tcp " "header len\n"); return 0; } __u16 origCheck = th->check; // This code does NOT respect the ipudp src and dest addresses // Remove UDP header; push on IP header if(iuh->saddr != srcIP) { #ifndef SUPPORT_NAT addrPrintComp("IPUDP header src did not match addr", "!=",iuh->saddr, srcIP); return 0; #else // th->check adjustment needed th->check = ip_nat_cheat_check(~iuh->saddr, srcIP, th->check); #endif } if(iuh->daddr != pri->local_addr) { #ifndef SUPPORT_NAT addrPrintComp("IPUDP header dest did not match addr", "!=",iuh->daddr, pri->local_addr); return 0; #else // th->check adjustment needed th->check = ip_nat_cheat_check(~iuh->daddr, pri->local_addr, th->check); #endif } int ihl = sizeof(*iph); iph->version = 4; iph->ihl = ihl / 4; iph->tos = 0; iph->tot_len = htons(cookedLen); static int ip_id = 0; iph->id = ip_id++; iph->frag_off = 0; iph->ttl = 255; iph->protocol = IPPROTO_TCP; iph->check = 0; #ifdef SUPPORT_NAT iph->saddr = srcIP; iph->daddr = pri->local_addr; #else iph->saddr = iuh->saddr; iph->daddr = iuh->daddr; #endif iph->check = ip_compute_csum((unsigned char *)iph, ihl); // XXX should copy protocol from an ipudp field DEBUG(2,"Returning cooked length %d, " "origCheck = %d, newCheck = %d\n", cookedLen, origCheck, th->check); DEBUG_GUARD(2, printk("IPH: "); hexdump((char*)iph, ihl) ); memcpy(buf, (char*)iph, cookedLen); return(cookedLen); }
/* Compute an IPv4 header checksum, where 'data' points to the IPv4 header, * and 'len' is the IPv4 header length. Return value is in network byte * order. */ uint16_t nm_csum_ipv4(struct nm_iphdr *iph) { return ip_compute_csum((void*)iph, sizeof(struct nm_iphdr)); }
/* * Handle ICMP messages in the outside-to-inside direction (incoming) * and sometimes in outgoing direction from ip_vs_forward_icmp. * Find any that might be relevant, check against existing connections, * forward to the right destination host if relevant. * Currently handles error types - unreachable, quench, ttl exceeded. */ static int ip_vs_in_icmp(struct sk_buff **skb_p) { struct sk_buff *skb = *skb_p; struct iphdr *iph; struct icmphdr *icmph; struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ unsigned short len; unsigned short clen, csize; struct ip_vs_conn *cp; struct rtable *rt; /* Route to the other host */ int mtu; if (skb_is_nonlinear(skb)) { if (skb_linearize(skb, GFP_ATOMIC) != 0) return NF_DROP; } iph = skb->nh.iph; ip_send_check(iph); icmph = (struct icmphdr *)((char *)iph + (iph->ihl << 2)); len = ntohs(iph->tot_len) - (iph->ihl<<2); if (len < sizeof(struct icmphdr)) return NF_DROP; IP_VS_DBG(12, "icmp in (%d,%d) %u.%u.%u.%u -> %u.%u.%u.%u\n", icmph->type, ntohs(icmp_id(icmph)), NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return NF_ACCEPT; /* * If we get here we have an ICMP error of one of the above 3 types * Now find the contained IP header */ clen = len - sizeof(struct icmphdr); if (clen < sizeof(struct iphdr)) return NF_DROP; ciph = (struct iphdr *) (icmph + 1); csize = ciph->ihl << 2; if (clen < csize) return NF_DROP; /* We are only interested ICMPs generated from TCP or UDP packets */ if (ciph->protocol != IPPROTO_UDP && ciph->protocol != IPPROTO_TCP) return NF_ACCEPT; /* Skip non-first embedded TCP/UDP fragments */ if (ciph->frag_off & __constant_htons(IP_OFFSET)) return NF_ACCEPT; /* We need at least TCP/UDP ports here */ if (clen < csize + sizeof(struct udphdr)) return NF_DROP; /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ IP_VS_ERR_RL("incoming ICMP: failed checksum from " "%d.%d.%d.%d!\n", NIPQUAD(iph->saddr)); return NF_DROP; } pptr = (__u16 *)&(((char *)ciph)[csize]); IP_VS_DBG(11, "Handling incoming ICMP for " "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n", NIPQUAD(ciph->saddr), ntohs(pptr[0]), NIPQUAD(ciph->daddr), ntohs(pptr[1])); /* This is pretty much what ip_vs_conn_in_get() does, except parameters are in the reverse order */ cp = ip_vs_conn_in_get(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (cp == NULL) return NF_ACCEPT; ip_vs_in_stats(cp, skb); /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be forwarded directly here, because there is no need to translate address/port back */ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { int ret; if (cp->packet_xmit) ret = cp->packet_xmit(skb, cp); else ret = NF_ACCEPT; atomic_inc(&cp->in_pkts); ip_vs_conn_put(cp); return ret; } /* * mangle and send the packet here */ if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos)))) goto tx_error_icmp; /* MTU checking */ mtu = rt->u.dst.pmtu; if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) { ip_rt_put(rt); icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n"); goto tx_error; } /* drop old route */ dst_release(skb->dst); skb->dst = &rt->u.dst; /* copy-on-write the packet before mangling it */ if (ip_vs_skb_cow(skb, rt->u.dst.dev->hard_header_len, &iph, (unsigned char**)&icmph)) { ip_vs_conn_put(cp); return NF_DROP; } ciph = (struct iphdr *) (icmph + 1); pptr = (__u16 *)&(((char *)ciph)[csize]); /* The ICMP packet for VS/NAT must be written to correct addresses before being forwarded to the right server */ /* First change the dest IP address, and recalc checksum */ iph->daddr = cp->daddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = cp->daddr; ip_send_check(ciph); /* the TCP/UDP source port - cannot redo check */ pptr[0] = cp->dport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); skb->ip_summed = CHECKSUM_UNNECESSARY; IP_VS_DBG(11, "Forwarding incoming ICMP to " "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n", NIPQUAD(ciph->saddr), ntohs(pptr[0]), NIPQUAD(ciph->daddr), ntohs(pptr[1])); #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 1 << NF_IP_LOCAL_OUT; #endif /* CONFIG_NETFILTER_DEBUG */ ip_send(skb); ip_vs_conn_put(cp); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: dev_kfree_skb(skb); ip_vs_conn_put(cp); return NF_STOLEN; }
/* * Handle ICMP messages in the inside-to-outside direction (outgoing). * Find any that might be relevant, check against existing connections, * forward to the right destination host if relevant. * Currently handles error types - unreachable, quench, ttl exceeded. * (Only used in VS/NAT) */ static int ip_vs_out_icmp(struct sk_buff **skb_p) { struct sk_buff *skb = *skb_p; struct iphdr *iph; struct icmphdr *icmph; struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ unsigned short ihl; unsigned short len; unsigned short clen, csize; struct ip_vs_conn *cp; /* reassemble IP fragments, but will it happen in ICMP packets?? */ if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) { skb = ip_defrag(skb, IP_DEFRAG_VS_OUT); if (!skb) return NF_STOLEN; *skb_p = skb; } if (skb_is_nonlinear(skb)) { if (skb_linearize(skb, GFP_ATOMIC) != 0) return NF_DROP; ip_send_check(skb->nh.iph); } iph = skb->nh.iph; ihl = iph->ihl << 2; icmph = (struct icmphdr *)((char *)iph + ihl); len = ntohs(iph->tot_len) - ihl; if (len < sizeof(struct icmphdr)) return NF_DROP; IP_VS_DBG(12, "outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n", icmph->type, ntohs(icmp_id(icmph)), NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); /* * Work through seeing if this is for us. * These checks are supposed to be in an order that means easy * things are checked first to speed up processing.... however * this means that some packets will manage to get a long way * down this stack and then be rejected, but that's life. */ if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return NF_ACCEPT; /* Now find the contained IP header */ clen = len - sizeof(struct icmphdr); if (clen < sizeof(struct iphdr)) return NF_DROP; ciph = (struct iphdr *) (icmph + 1); csize = ciph->ihl << 2; if (clen < csize) return NF_DROP; /* We are only interested ICMPs generated from TCP or UDP packets */ if (ciph->protocol != IPPROTO_UDP && ciph->protocol != IPPROTO_TCP) return NF_ACCEPT; /* Skip non-first embedded TCP/UDP fragments */ if (ciph->frag_off & __constant_htons(IP_OFFSET)) return NF_ACCEPT; /* We need at least TCP/UDP ports here */ if (clen < csize + sizeof(struct udphdr)) return NF_DROP; /* * Find the ports involved - this packet was * incoming so the ports are right way round * (but reversed relative to outer IP header!) */ pptr = (__u16 *)&(((char *)ciph)[csize]); /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ IP_VS_DBG(1, "forward ICMP: failed checksum from %d.%d.%d.%d!\n", NIPQUAD(iph->saddr)); return NF_DROP; } IP_VS_DBG(11, "Handling outgoing ICMP for " "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n", NIPQUAD(ciph->saddr), ntohs(pptr[0]), NIPQUAD(ciph->daddr), ntohs(pptr[1])); /* ciph content is actually <protocol, caddr, cport, daddr, dport> */ cp = ip_vs_conn_out_get(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (!cp) return NF_ACCEPT; if (IP_VS_FWD_METHOD(cp) != 0) { IP_VS_ERR("shouldn't reach here, because the box is on the" "half connection in the tun/dr module.\n"); } /* Now we do real damage to this packet...! */ /* First change the source IP address, and recalc checksum */ iph->saddr = cp->vaddr; ip_send_check(iph); /* Now change the *dest* address in the contained IP */ ciph->daddr = cp->vaddr; ip_send_check(ciph); /* the TCP/UDP dest port - cannot redo check */ pptr[1] = cp->vport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); skb->ip_summed = CHECKSUM_UNNECESSARY; /* do the statistics and put it back */ ip_vs_out_stats(cp, skb); ip_vs_conn_put(cp); IP_VS_DBG(11, "Forwarding correct outgoing ICMP to " "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n", NIPQUAD(ciph->saddr), ntohs(pptr[0]), NIPQUAD(ciph->daddr), ntohs(pptr[1])); skb->nfcache |= NFC_IPVS_PROPERTY; return NF_ACCEPT; }
struct iphdr *diph = template->iph; int ihl = template->ihl; BUG_TRAP(ihl == 20); int tot_len = ntohs(diph->tot_len) + adjPacketLen; #if 0 printk("new tot_len = %d\n", tot_len); #endif diph->saddr = newSrc; diph->daddr = newDest; diph->tot_len = htons(tot_len); diph->protocol = newProto; diph->check = 0; // Compute checksum diph->check = ip_compute_csum((unsigned char *)diph, ihl); skb->nh.iph = (struct iphdr*)skb_push(skb, ihl); memcpy((char*)skb->nh.iph, diph, ihl); if(updateFlags & INCLUDE_LL) { // push on link layer header BUG_TRAP(template->ll_len == 14); skb->mac.raw = skb_push(skb, template->ll_len); memcpy(skb->mac.raw, template->ll_rawh, template->ll_len); } #if 0 printk("dumping final iph: \n"); hexdump(skb->nh.iph, ihl); #endif }
int ip_fw_masq_icmp(struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ struct ip_masq *ms; unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("Incoming forward ICMP (%d,%d) %lX -> %lX\n", icmph->type, ntohs(icmp_id(icmph)), ntohl(iph->saddr), ntohl(iph->daddr)); #endif #ifdef CONFIG_IP_MASQUERADE_ICMP if ((icmph->type == ICMP_ECHO ) || (icmph->type == ICMP_TIMESTAMP ) || (icmph->type == ICMP_INFO_REQUEST ) || (icmph->type == ICMP_ADDRESS )) { #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp request rcv %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif ms = ip_masq_out_get_2(iph->protocol, iph->saddr, icmp_id(icmph), iph->daddr, icmp_hv_req(icmph)); if (ms == NULL) { ms = ip_masq_new(dev, iph->protocol, iph->saddr, icmp_id(icmph), iph->daddr, icmp_hv_req(icmph), 0); if (ms == NULL) return (-1); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: Create new icmp entry\n"); #endif } ip_masq_set_expire(ms, 0); /* Rewrite source address */ /* * If sysctl !=0 and no pkt has been received yet * in this tunnel and routing iface address has changed... * "You are welcome, diald". */ if ( sysctl_ip_dynaddr && ms->flags & IP_MASQ_F_NO_REPLY && dev->pa_addr != ms->maddr) { unsigned long flags; #ifdef DEBUG_CONFIG_IP_MASQUERADE printk(KERN_INFO "ip_fw_masq_icmp(): change masq.addr %s", in_ntoa(ms->maddr)); printk("-> %s\n", in_ntoa(dev->pa_addr)); #endif save_flags(flags); cli(); ip_masq_unhash(ms); ms->maddr = dev->pa_addr; ip_masq_hash(ms); restore_flags(flags); } iph->saddr = ms->maddr; ip_send_check(iph); /* Rewrite port (id) */ (icmph->un).echo.id = ms->mport; icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *)icmph, len); ip_masq_set_expire(ms, MASQUERADE_EXPIRE_ICMP); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp request rwt %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif return (1); } #endif /* * Work through seeing if this is for us. * These checks are supposed to be in an order that * means easy things are checked first to speed up * processing.... however this means that some * packets will manage to get a long way down this * stack and then be rejected, but thats life */ if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return 0; /* Now find the contained IP header */ ciph = (struct iphdr *) (icmph + 1); #ifdef CONFIG_IP_MASQUERADE_ICMP if (ciph->protocol == IPPROTO_ICMP) { /* * This section handles ICMP errors for ICMP packets */ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + (ciph->ihl<<2)); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: fw icmp/icmp rcv %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif ms = ip_masq_out_get_2(ciph->protocol, ciph->daddr, icmp_id(cicmph), ciph->saddr, icmp_hv_rep(cicmph)); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the source IP address, and recalc checksum */ iph->saddr = ms->maddr; ip_send_check(iph); /* Now change the *dest* address in the contained IP */ ciph->daddr = ms->maddr; ip_send_check(ciph); /* Change the ID to the masqed one! */ (cicmph->un).echo.id = ms->mport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: fw icmp/icmp rwt %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif return 1; } #endif /* CONFIG_IP_MASQUERADE_ICMP */ /* We are only interested ICMPs generated from TCP or UDP packets */ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP)) return 0; /* * Find the ports involved - this packet was * incoming so the ports are right way round * (but reversed relative to outer IP header!) */ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ printk(KERN_DEBUG "MASQ: forward ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr)); return(-1); } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Handling forward ICMP for %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif /* This is pretty much what ip_masq_out_get() does */ ms = ip_masq_out_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the source IP address, and recalc checksum */ iph->saddr = ms->maddr; ip_send_check(iph); /* Now change the *dest* address in the contained IP */ ciph->daddr = ms->maddr; ip_send_check(ciph); /* the TCP/UDP dest port - cannot redo check */ pptr[1] = ms->mport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Rewrote forward ICMP to %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif return 1; }
int ip_fw_demasq_icmp(struct sk_buff **skb_p, struct device *dev) { struct sk_buff *skb = *skb_p; struct iphdr *iph = skb->h.iph; struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); struct iphdr *ciph; /* The ip header contained within the ICMP */ __u16 *pptr; /* port numbers from TCP/UDP contained header */ struct ip_masq *ms; unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp in/rev (%d,%d) %lX -> %lX\n", icmph->type, ntohs(icmp_id(icmph)), ntohl(iph->saddr), ntohl(iph->daddr)); #endif #ifdef CONFIG_IP_MASQUERADE_ICMP if ((icmph->type == ICMP_ECHOREPLY) || (icmph->type == ICMP_TIMESTAMPREPLY) || (icmph->type == ICMP_INFO_REPLY) || (icmph->type == ICMP_ADDRESSREPLY)) { #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp reply rcv %lX->%lX id %d type %d, req %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type, icmp_type_request(icmph->type)); #endif ms = ip_masq_in_get_2(iph->protocol, iph->saddr, icmp_hv_rep(icmph), iph->daddr, icmp_id(icmph)); if (ms == NULL) return 0; ip_masq_set_expire(ms,0); /* * got reply, so clear flag */ ms->flags &= ~IP_MASQ_F_NO_REPLY; /* Reset source address */ iph->daddr = ms->saddr; /* Redo IP header checksum */ ip_send_check(iph); /* Set ID to fake port number */ (icmph->un).echo.id = ms->sport; /* Reset ICMP checksum and set expiry */ icmph->checksum=0; icmph->checksum=ip_compute_csum((unsigned char *)icmph,len); ip_masq_set_expire(ms, MASQUERADE_EXPIRE_ICMP); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: icmp reply rwt %lX->%lX id %d type %d\n", ntohl(iph->saddr), ntohl(iph->daddr), ntohs(icmp_id(icmph)), icmph->type); #endif return 1; } else { #endif if ((icmph->type != ICMP_DEST_UNREACH) && (icmph->type != ICMP_SOURCE_QUENCH) && (icmph->type != ICMP_TIME_EXCEEDED)) return 0; #ifdef CONFIG_IP_MASQUERADE_ICMP } #endif /* * If we get here we have an ICMP error of one of the above 3 types * Now find the contained IP header */ ciph = (struct iphdr *) (icmph + 1); #ifdef CONFIG_IP_MASQUERADE_ICMP if (ciph->protocol == IPPROTO_ICMP) { /* * This section handles ICMP errors for ICMP packets * * First get a new ICMP header structure out of the IP packet */ struct icmphdr *cicmph = (struct icmphdr *)((char *)ciph + (ciph->ihl<<2)); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: rv icmp/icmp rcv %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, icmp_hv_req(cicmph), ciph->saddr, icmp_id(cicmph)); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the dest IP address, and recalc checksum */ iph->daddr = ms->saddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = ms->saddr; ip_send_check(ciph); /* Change the ID to the original one! */ (cicmph->un).echo.id = ms->sport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE_ICMP printk("MASQ: rv icmp/icmp rwt %lX->%lX id %d type %d\n", ntohl(ciph->saddr), ntohl(ciph->daddr), ntohs(icmp_id(cicmph)), cicmph->type); #endif return 1; } #endif /* CONFIG_IP_MASQUERADE_ICMP */ /* We are only interested ICMPs generated from TCP or UDP packets */ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP)) return 0; /* * Find the ports involved - remember this packet was * *outgoing* so the ports are reversed (and addresses) */ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]); if (ntohs(pptr[0]) < PORT_MASQ_BEGIN || ntohs(pptr[0]) > PORT_MASQ_END) return 0; /* Ensure the checksum is correct */ if (ip_compute_csum((unsigned char *) icmph, len)) { /* Failed checksum! */ printk(KERN_DEBUG "MASQ: reverse ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr)); return(-1); } #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Handling reverse ICMP for %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif /* This is pretty much what ip_masq_in_get() does, except params are wrong way round */ ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]); if (ms == NULL) return 0; /* Now we do real damage to this packet...! */ /* First change the dest IP address, and recalc checksum */ iph->daddr = ms->saddr; ip_send_check(iph); /* Now change the *source* address in the contained IP */ ciph->saddr = ms->saddr; ip_send_check(ciph); /* the TCP/UDP source port - cannot redo check */ pptr[0] = ms->sport; /* And finally the ICMP checksum */ icmph->checksum = 0; icmph->checksum = ip_compute_csum((unsigned char *) icmph, len); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("Rewrote reverse ICMP to %lX:%X -> %lX:%X\n", ntohl(ciph->saddr), ntohs(pptr[0]), ntohl(ciph->daddr), ntohs(pptr[1])); #endif return 1; }
int igmp_rcv(struct sk_buff *skb) { /* This basically follows the spec line by line -- see RFC1112 */ struct igmphdr *ih = skb->h.igmph; struct in_device *in_dev = in_dev_get(skb->dev); int len = skb->len; if (in_dev==NULL) { kfree_skb(skb); return 0; } if (skb_is_nonlinear(skb)) { if (skb_linearize(skb, GFP_ATOMIC) != 0) { kfree_skb(skb); return -ENOMEM; } ih = skb->h.igmph; } if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)) { in_dev_put(in_dev); kfree_skb(skb); return 0; } #ifdef CONFIG_RG_IGMP_PROXY igmprx_recv(skb); #endif #ifdef CONFIG_RG_IGMP_PROXY_MODULE if (igmp_proxy_recv) igmp_proxy_recv(skb); #endif switch (ih->type) { case IGMP_HOST_MEMBERSHIP_QUERY: igmp_heard_query(in_dev, ih->code, ih->group); break; case IGMP_HOST_MEMBERSHIP_REPORT: case IGMP_HOST_NEW_MEMBERSHIP_REPORT: /* Is it our report looped back? */ if (((struct rtable*)skb->dst)->key.iif == 0) break; igmp_heard_report(in_dev, ih->group); break; case IGMP_PIM: #ifdef CONFIG_IP_PIMSM_V1 in_dev_put(in_dev); return pim_rcv_v1(skb); #endif case IGMP_DVMRP: case IGMP_TRACE: case IGMP_HOST_LEAVE_MESSAGE: case IGMP_MTRACE: case IGMP_MTRACE_RESP: break; default: // NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type)); ; } in_dev_put(in_dev); kfree_skb(skb); return 0; }
static void send_unreach(struct sk_buff *skb_in, int code) { struct iphdr *iph; struct udphdr *udph; struct icmphdr *icmph; struct sk_buff *nskb; u32 saddr; u8 tos; int hh_len, length; struct rtable *rt = (struct rtable*)skb_in->dst; unsigned char *data; if (!rt) return; /* FIXME: Use sysctl number. --RR */ if (!xrlim_allow(&rt->u.dst, 1*HZ)) return; iph = skb_in->nh.iph; /* No replies to physical multicast/broadcast */ if (skb_in->pkt_type!=PACKET_HOST) return; /* Now check at the protocol level */ if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) return; /* Only reply to fragment 0. */ if (iph->frag_off&htons(IP_OFFSET)) return; /* if UDP checksum is set, verify it's correct */ if (iph->protocol == IPPROTO_UDP && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) { int datalen = skb_in->len - (iph->ihl<<2); udph = (struct udphdr *)((char *)iph + (iph->ihl<<2)); if (udph->check && csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, IPPROTO_UDP, csum_partial((char *)udph, datalen, 0)) != 0) return; } /* If we send an ICMP error to an ICMP error a mess would result.. */ if (iph->protocol == IPPROTO_ICMP && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) { icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); /* Between echo-reply (0) and timestamp (13), everything except echo-request (8) is an error. Also, anything greater than NR_ICMP_TYPES is unknown, and hence should be treated as an error... */ if ((icmph->type < ICMP_TIMESTAMP && icmph->type != ICMP_ECHOREPLY && icmph->type != ICMP_ECHO) || icmph->type > NR_ICMP_TYPES) return; } saddr = iph->daddr; if (!(rt->rt_flags & RTCF_LOCAL)) saddr = 0; tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL; if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) return; /* RFC says return as much as we can without exceeding 576 bytes. */ length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr); if (length > rt->u.dst.pmtu) length = rt->u.dst.pmtu; if (length > 576) length = 576; hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; nskb = alloc_skb(hh_len+15+length, GFP_ATOMIC); if (!nskb) { ip_rt_put(rt); return; } nskb->priority = 0; nskb->dst = &rt->u.dst; skb_reserve(nskb, hh_len); /* Set up IP header */ iph = nskb->nh.iph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); iph->version=4; iph->ihl=5; iph->tos=tos; iph->tot_len = htons(length); /* PMTU discovery never applies to ICMP packets. */ iph->frag_off = 0; iph->ttl = MAXTTL; ip_select_ident(iph, &rt->u.dst, NULL); iph->protocol=IPPROTO_ICMP; iph->saddr=rt->rt_src; iph->daddr=rt->rt_dst; iph->check=0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); /* Set up ICMP header. */ icmph = nskb->h.icmph = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr)); icmph->type = ICMP_DEST_UNREACH; icmph->code = code; icmph->un.gateway = 0; icmph->checksum = 0; /* Copy as much of original packet as will fit */ data = skb_put(nskb, length - sizeof(struct iphdr) - sizeof(struct icmphdr)); /* FIXME: won't work with nonlinear skbs --RR */ memcpy(data, skb_in->nh.iph, length - sizeof(struct iphdr) - sizeof(struct icmphdr)); icmph->checksum = ip_compute_csum((unsigned char *)icmph, length - sizeof(struct iphdr)); nf_ct_attach(nskb, skb_in); NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, ip_finish_output); }
int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, unsigned long daddr, unsigned short len, unsigned long saddr, int redo, struct ip_protocol *protocol ) { int size, offset; struct icmp_header *icmph, *icmphr; struct sk_buff *skb; unsigned char *buff; /* drop broadcast packets. */ if ((daddr & 0xff000000) == 0 || (daddr & 0xff000000) == 0xff000000) { skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } buff = skb1->h.raw; icmph = (struct icmp_header *)buff; /* Validate the packet first */ if( icmph->checksum ) { /* Checksums Enabled? */ if( ip_compute_csum( (unsigned char *)icmph, len ) ) { /* Failed checksum! */ PRINTK("\nICMP ECHO failed checksum!"); skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } } print_icmph(icmph); /* Parse the ICMP message */ switch( icmph->type ) { case ICMP_DEST_UNREACH: case ICMP_SOURCE_QUENCH: { struct ip_header *iph; struct ip_protocol *ipprot; unsigned char hash; int err; err = icmph->type << 8 | icmph->code; /* we need to cause the socket to be closed and the error message to be set appropriately. */ iph = (struct ip_header *)(icmph+1); /* get the protocol(s) */ hash = iph->protocol & (MAX_IP_PROTOS -1 ); for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next) { /* pass it off to everyone who wants it. */ ipprot->err_handler (err, (unsigned char *)iph+4*iph->ihl, iph->daddr, iph->saddr, ipprot); } skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } case ICMP_REDIRECT: { /* we need to put a new route in the routing table. */ struct rtable *rt; /* we will add a new route. */ struct ip_header *iph; iph = (struct ip_header *)(icmph+1); rt = malloc (sizeof (*rt)); if (rt != NULL) { rt->net = iph->daddr; /* assume class C network. Technically this is incorrect, but will give it a try. */ if ((icmph->code & 1) == 0) rt->net &= 0x00ffffff; rt->dev = dev; rt->router = icmph->un.gateway; add_route (rt); } skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } case ICMP_ECHO: /* Allocate an sk_buff response buffer (assume 64 byte IP header) */ size = sizeof( struct sk_buff ) + dev->hard_header_len + 64 + len; skb = malloc( size ); if (skb == NULL) { skb1->sk = NULL; free_skb (skb1, FREE_READ); return (0); } skb->sk = NULL; skb->mem_addr = skb; skb->mem_len = size; /* Build Layer 2-3 headers for message back to source */ offset = ip_build_header( skb, daddr, saddr, &dev, IP_ICMP, opt, len ); if (offset < 0) { /* Problems building header */ PRINTK("\nCould not build IP Header for ICMP ECHO Response"); free_s (skb->mem_addr, skb->mem_len); skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); /* just toss the received packet */ } /* Readjust length according to actual IP header size */ skb->len = offset + len; /* Build ICMP_ECHO Response message */ icmphr = (struct icmp_header *)( (char *)( skb + 1 ) + offset ); memcpy( (char *)icmphr, (char *)icmph, len ); icmphr->type = ICMP_ECHOREPLY; icmphr->code = 0; icmphr->checksum = 0; if( icmph->checksum ) { /* Calculate Checksum */ icmphr->checksum = ip_compute_csum( (void *)icmphr, len ); } /* Ship it out - free it when done */ ip_queue_xmit( (volatile struct sock *)NULL, dev, skb, 1 ); skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); default: PRINTK("\nUnsupported ICMP type = x%x", icmph->type ); skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); /* just toss the packet */ } /* should be unecessary, but just in case. */ skb1->sk = NULL; free_skb (skb1, FREE_READ); return( 0 ); /* just toss the packet */ }
static int ipv4_icmp_post(void *l4_hdr, u16 datagram_len, struct tuple *tuple4) { struct icmphdr *hdr = l4_hdr; hdr->checksum = ip_compute_csum(hdr, datagram_len); return 0; }
static unsigned char *kexec_bn2cl(void *pg) { struct Elf32_Bhdr *bhdrp; Elf32_Nhdr *nhdrp; unsigned char *desc; unsigned char *command_line; __sum16 csum; bhdrp = (struct Elf32_Bhdr *) pg; /* * This routine is invoked for every source page, so make * sure to quietly ignore every impossible page. */ if (bhdrp->b_signature != ELF_BOOT_MAGIC || bhdrp->b_size > PAGE_SIZE) return 0; /* * If we get a checksum mismatch, warn with the checksum * so we can diagnose better. */ csum = ip_compute_csum(pg, bhdrp->b_size); if (csum != 0) { pr_warning("%s: bad checksum %#x (size %d)\n", __func__, csum, bhdrp->b_size); return 0; } nhdrp = (Elf32_Nhdr *) (bhdrp + 1); while (nhdrp->n_type != EBN_COMMAND_LINE) { desc = (unsigned char *) (nhdrp + 1); desc += roundupsz(nhdrp->n_descsz); nhdrp = (Elf32_Nhdr *) desc; /* still in bounds? */ if ((unsigned char *) (nhdrp + 1) > ((unsigned char *) pg) + bhdrp->b_size) { pr_info("%s: out of bounds\n", __func__); return 0; } } command_line = (unsigned char *) (nhdrp + 1); desc = command_line; while (*desc != '\0') { desc++; if (((unsigned long)desc & PAGE_MASK) != (unsigned long)pg) { pr_info("%s: ran off end of page\n", __func__); return 0; } } return command_line; }
static __u16 sd_dif_ip_fn(void *data, unsigned int len) { return ip_compute_csum(data, len); }