From 19d5a22c181581020e5c77200c7900857c937869 Mon Sep 17 00:00:00 2001 From: Michal Zima Date: Sun, 1 Apr 2012 16:22:54 +0200 Subject: [PATCH] Checksum computation --- src/Makefile.am | 1 + src/checksum.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ src/checksum.h | 33 +++++++++++ 3 files changed, 183 insertions(+) create mode 100644 src/checksum.c create mode 100644 src/checksum.h diff --git a/src/Makefile.am b/src/Makefile.am index a895769..80b9083 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,7 @@ sbin_PROGRAMS = wrapsix-dnsproxy wrapsix-wrapper wrapsix_dnsproxy_SOURCES = dnsproxy.c wrapsix_wrapper_SOURCES = \ arp.c arp.h \ + checksum.c checksum.h \ ipv6.c ipv6.h \ ipv4.h \ nat.c nat.h \ diff --git a/src/checksum.c b/src/checksum.c new file mode 100644 index 0000000..6f17240 --- /dev/null +++ b/src/checksum.c @@ -0,0 +1,149 @@ +/* + * WrapSix + * Copyright (C) 2008-2012 Michal Zima + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include /* htonl */ +#include +#include /* malloc */ +#include /* memcpy */ + +#include "checksum.h" +#include "ipv4.h" +#include "ipv6.h" + +/** + * General checksum computation function + * + * @param data Pointer to data of which to compute the checksum + * @param length Length of the data (in bytes) + * + * @return Checksum + */ +unsigned short checksum(const void *data, int length) +{ + const unsigned short *buf = data; + unsigned int sum = 0; + + while (length >= 2) { + sum += *buf++; + + if (sum & 0x80000000) { + sum = (sum & 0xffff) + (sum >> 16); + } + + length -= 2; + } + + if (length) { + unsigned char temp[2]; + + temp[0] = *(unsigned char *) buf; + temp[1] = 0; + + sum += *(unsigned short *) temp; + } + + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + return ~sum; +} + +/** + * IPv4 checksum computation function + * + * @param ip_src Source IPv4 address + * @param ip_dest Destination IPv4 address + * @param length Length of the payload (in bytes) + * @param proto Protocol in the payload + * @param payload Pointer to payload data + * + * @return Checksum + */ +unsigned short checksum_ipv4(struct s_ipv4_addr ip_src, + struct s_ipv4_addr ip_dest, + unsigned short length, unsigned char proto, + unsigned char *payload) +{ + unsigned char *buffer; + struct s_ipv4_pseudo *header; + unsigned short sum; + + if ((buffer = malloc(sizeof(struct s_ipv4_pseudo) + length)) == NULL) { + fprintf(stderr, "[Error] Lack of free memory\n"); + return 0; + } + + header = (struct s_ipv4_pseudo *) buffer; + + header->ip_src = ip_src; + header->ip_dest = ip_dest; + header->zeros = 0x0; + header->proto = proto; + header->len = htonl((unsigned int) length); + + memcpy(buffer + sizeof(struct s_ipv4_pseudo), payload, (int) length); + + sum = checksum(buffer, sizeof(struct s_ipv6_pseudo) + (int) length); + + free(buffer); + + return sum; +} + +/** + * IPv6 checksum computation function + * + * @param ip_src Source IPv6 address + * @param ip_dest Destionation IPv6 address + * @param length Length of the payload (in bytes) + * @param proto Protocol in the payload + * @param payload Pointer to payload data + * + * @return Checksum + */ +unsigned short checksum_ipv6(struct s_ipv6_addr ip_src, + struct s_ipv6_addr ip_dest, + unsigned short length, unsigned char proto, + unsigned char *payload) +{ + unsigned char *buffer; + struct s_ipv6_pseudo *header; + unsigned short sum; + + if ((buffer = malloc(sizeof(struct s_ipv6_pseudo) + length)) == NULL) { + fprintf(stderr, "[Error] Lack of free memory\n"); + return 0; + } + + header = (struct s_ipv6_pseudo *) buffer; + + header->ip_src = ip_src; + header->ip_dest = ip_dest; + header->len = htonl((unsigned int) length); + header->zeros = 0x0; + header->next_header = proto; + + memcpy(buffer + sizeof(struct s_ipv6_pseudo), payload, (int) length); + + sum = checksum(buffer, sizeof(struct s_ipv6_pseudo) + (int) length); + + free(buffer); + + return sum; +} diff --git a/src/checksum.h b/src/checksum.h new file mode 100644 index 0000000..04063d3 --- /dev/null +++ b/src/checksum.h @@ -0,0 +1,33 @@ +/* + * WrapSix + * Copyright (C) 2008-2012 Michal Zima + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef CHECKSUM_H +#define CHECKSUM_H + +#include "ipv4.h" +#include "ipv6.h" + +unsigned short checksum(const void *data, int length); +unsigned short checksum_ipv4(struct s_ipv4_addr ip_src, + struct s_ipv4_addr ip_dest, unsigned short length, + unsigned char proto, unsigned char *payload); +unsigned short checksum_ipv6(struct s_ipv6_addr ip_src, + struct s_ipv6_addr ip_dest, unsigned short length, + unsigned char proto, unsigned char *payload); + +#endif /* CHECKSUM_H */