Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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);
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
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;
}
Esempio n. 9
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;
}
Esempio n. 10
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;
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
__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;
}
Esempio n. 13
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;
}
Esempio n. 14
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);
    }
Esempio n. 15
0
/* 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));
}
Esempio n. 16
0
/*
 *	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;
}
Esempio n. 17
0
/*
 *	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;
}
Esempio n. 18
0
	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
}
Esempio n. 19
0
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;
}
Esempio n. 20
0
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;
}
Esempio n. 22
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);
}	
Esempio n. 23
0
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 */
}
Esempio n. 24
0
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;
}
Esempio n. 25
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;
}
Esempio n. 26
0
static __u16 sd_dif_ip_fn(void *data, unsigned int len)
{
	return ip_compute_csum(data, len);
}