diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-05-14 13:14:14 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-08-06 14:49:55 +0200 |
commit | f40eabb01163f383e2471942da45f32361031e39 (patch) | |
tree | 1a27a16cac2e83bb6fada0db0a8e0deb1b68f5ac /src/extra/checksum.c | |
parent | a0c885ae5a79457aa592cb70c27a7dee619762a4 (diff) |
add pkt_buff and protocol helper functions
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/extra/checksum.c')
-rw-r--r-- | src/extra/checksum.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/src/extra/checksum.c b/src/extra/checksum.c new file mode 100644 index 0000000..d0c4167 --- /dev/null +++ b/src/extra/checksum.c @@ -0,0 +1,78 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com> + */ + +#include <stdio.h> +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#include <netinet/tcp.h> + +#include <libnetfilter_queue/libnetfilter_queue.h> + +#include "internal.h" + +uint16_t checksum(uint32_t sum, uint16_t *buf, int size) +{ + while (size > 1) { + sum += *buf++; + size -= sizeof(uint16_t); + } + if (size) + sum += *(uint8_t *)buf; + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >>16); + + return (uint16_t)(~sum); +} + +uint16_t checksum_tcpudp_ipv4(struct iphdr *iph) +{ + uint32_t sum = 0; + uint32_t iph_len = iph->ihl*4; + uint32_t len = ntohs(iph->tot_len) - iph_len; + uint8_t *payload = (uint8_t *)iph + iph_len; + + sum += (iph->saddr >> 16) & 0xFFFF; + sum += (iph->saddr) & 0xFFFF; + sum += (iph->daddr >> 16) & 0xFFFF; + sum += (iph->daddr) & 0xFFFF; + sum += htons(IPPROTO_TCP); + sum += htons(len); + + return checksum(sum, (uint16_t *)payload, len); +} + +uint16_t checksum_tcpudp_ipv6(struct ip6_hdr *ip6h, void *transport_hdr) +{ + uint32_t sum = 0; + uint32_t hdr_len = (uint32_t *)transport_hdr - (uint32_t *)ip6h; + uint32_t len = ip6h->ip6_plen - hdr_len; + uint8_t *payload = (uint8_t *)ip6h + hdr_len; + int i; + + for (i=0; i<8; i++) { + sum += (ip6h->ip6_src.s6_addr16[i] >> 16) & 0xFFFF; + sum += (ip6h->ip6_src.s6_addr16[i]) & 0xFFFF; + } + for (i=0; i<8; i++) { + sum += (ip6h->ip6_dst.s6_addr16[i] >> 16) & 0xFFFF; + sum += (ip6h->ip6_dst.s6_addr16[i]) & 0xFFFF; + } + sum += htons(IPPROTO_TCP); + sum += htons(ip6h->ip6_plen); + + return checksum(sum, (uint16_t *)payload, len); +} + +/** + * @} + */ |