Esempio n. 1
0
static int
sctp_dnat_handler(struct sk_buff *skb,
                  struct ip_vs_protocol *pp, struct ip_vs_conn *cp)
{
    sctp_sctphdr_t *sctph;
    unsigned int sctphoff;
    struct sk_buff *iter;
    __be32 crc32;

#ifdef CONFIG_IP_VS_IPV6
    if (cp->af == AF_INET6)
        sctphoff = sizeof(struct ipv6hdr);
    else
#endif
        sctphoff = ip_hdrlen(skb);

    /* csum_check requires unshared skb */
    if (!skb_make_writable(skb, sctphoff + sizeof(*sctph)))
        return 0;

    if (unlikely(cp->app != NULL)) {
        /* Some checks before mangling */
        if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
            return 0;

        /* Call application helper if needed */
        if (!ip_vs_app_pkt_in(cp, skb))
            return 0;
    }

    sctph = (void *) skb_network_header(skb) + sctphoff;
    sctph->dest = cp->dport;

    /* Calculate the checksum */
    crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
    skb_walk_frags(skb, iter)
    crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter),
                              crc32);
    crc32 = sctp_end_cksum(crc32);
    sctph->checksum = crc32;

    return 1;
}
Esempio n. 2
0
static int
tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
		 struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
{
	struct tcphdr *tcph;
	unsigned int tcphoff = iph->len;
	int oldlen;
	int payload_csum = 0;

#ifdef CONFIG_IP_VS_IPV6
	if (cp->af == AF_INET6 && iph->fragoffs)
		return 1;
#endif
	oldlen = skb->len - tcphoff;

	/* csum_check requires unshared skb */
	if (!skb_make_writable(skb, tcphoff+sizeof(*tcph)))
		return 0;

	if (unlikely(cp->app != NULL)) {
		int ret;

		/* Some checks before mangling */
		if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
			return 0;

		/*
		 *	Attempt ip_vs_app call.
		 *	It will fix ip_vs_conn and iph ack_seq stuff
		 */
		if (!(ret = ip_vs_app_pkt_in(cp, skb)))
			return 0;
		/* ret=2: csum update is needed after payload mangling */
		if (ret == 1)
			oldlen = skb->len - tcphoff;
		else
			payload_csum = 1;
	}

	tcph = (void *)skb_network_header(skb) + tcphoff;
	tcph->dest = cp->dport;

	/*
	 *	Adjust TCP checksums
	 */
	if (skb->ip_summed == CHECKSUM_PARTIAL) {
		tcp_partial_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
					htons(oldlen),
					htons(skb->len - tcphoff));
	} else if (!payload_csum) {
		/* Only port and addr are changed, do fast csum update */
		tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr,
				     cp->vport, cp->dport);
		if (skb->ip_summed == CHECKSUM_COMPLETE)
			skb->ip_summed = (cp->app && pp->csum_check) ?
					 CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
	} else {
		/* full checksum calculation */
		tcph->check = 0;
		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
#ifdef CONFIG_IP_VS_IPV6
		if (cp->af == AF_INET6)
			tcph->check = csum_ipv6_magic(&cp->caddr.in6,
						      &cp->daddr.in6,
						      skb->len - tcphoff,
						      cp->protocol, skb->csum);
		else
#endif
			tcph->check = csum_tcpudp_magic(cp->caddr.ip,
							cp->daddr.ip,
							skb->len - tcphoff,
							cp->protocol,
							skb->csum);
		skb->ip_summed = CHECKSUM_UNNECESSARY;
	}
	return 1;
}