|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* $Id: libnet_checksum.c,v 1.14 2004/11/09 07:05:07 mike Exp $
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* libnet
|
|
Packit |
03b34a |
* libnet_checksum.c - checksum routines
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
|
|
Packit |
03b34a |
* All rights reserved.
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
03b34a |
* modification, are permitted provided that the following conditions
|
|
Packit |
03b34a |
* are met:
|
|
Packit |
03b34a |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
03b34a |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
03b34a |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
03b34a |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit |
03b34a |
* documentation and/or other materials provided with the distribution.
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
Packit |
03b34a |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
03b34a |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
03b34a |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
Packit |
03b34a |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
03b34a |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
Packit |
03b34a |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
03b34a |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
Packit |
03b34a |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
Packit |
03b34a |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
Packit |
03b34a |
* SUCH DAMAGE.
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
#if (HAVE_CONFIG_H)
|
|
Packit |
03b34a |
#include "../include/config.h"
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
#if (!(_WIN32) || (__CYGWIN__))
|
|
Packit |
03b34a |
#include "../include/libnet.h"
|
|
Packit |
03b34a |
#else
|
|
Packit |
03b34a |
#include "../include/win32/libnet.h"
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/* FIXME - unit test these - 0 is debian's version, else is -RC1's */
|
|
Packit |
03b34a |
/* Note about aliasing warning:
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* http://mail.opensolaris.org/pipermail/tools-gcc/2005-August/000047.html
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* See RFC 1071, and:
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* http://mathforum.org/library/drmath/view/54379.html
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
#undef DEBIAN
|
|
Packit |
03b34a |
/* Note: len is in bytes, not 16-bit words! */
|
|
Packit |
03b34a |
int
|
|
Packit |
03b34a |
libnet_in_cksum(uint16_t *addr, int len)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
int sum;
|
|
Packit |
03b34a |
#ifdef DEBIAN
|
|
Packit |
03b34a |
uint16_t last_byte;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
sum = 0;
|
|
Packit |
03b34a |
last_byte = 0;
|
|
Packit |
03b34a |
#else
|
|
Packit |
03b34a |
union
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
uint16_t s;
|
|
Packit |
03b34a |
uint8_t b[2];
|
|
Packit |
03b34a |
}pad;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
sum = 0;
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
while (len > 1)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
sum += *addr++;
|
|
Packit |
03b34a |
len -= 2;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
#ifdef DEBIAN
|
|
Packit |
03b34a |
if (len == 1)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
*(uint8_t *)&last_byte = *(uint8_t *)addr;
|
|
Packit |
03b34a |
sum += last_byte;
|
|
Packit |
03b34a |
#else
|
|
Packit |
03b34a |
if (len == 1)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
pad.b[0] = *(uint8_t *)addr;
|
|
Packit |
03b34a |
pad.b[1] = 0;
|
|
Packit |
03b34a |
sum += pad.s;
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
return (sum);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
int
|
|
Packit |
03b34a |
libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag, int mode)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
libnet_pblock_t *p;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
p = libnet_pblock_find(l, ptag);
|
|
Packit |
03b34a |
if (p == NULL)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
/* err msg set in libnet_pblock_find() */
|
|
Packit |
03b34a |
return (-1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
if (mode == LIBNET_ON)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
return (1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
else
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
(p->flags) |= LIBNET_PBLOCK_DO_CHECKSUM;
|
|
Packit |
03b34a |
return (1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
else
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
(p->flags) &= ~LIBNET_PBLOCK_DO_CHECKSUM;
|
|
Packit |
03b34a |
return (1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
else
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
return (1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
static int check_ip_payload_size(libnet_t*l, const uint8_t *iphdr, int ip_hl, int h_len, const uint8_t * end, const char* func)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
if((iphdr+ip_hl+h_len) > end)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
|
|
Packit |
03b34a |
"%s(): ip payload not inside packet (pktsz %d, iphsz %d, payloadsz %d)\n", func,
|
|
Packit |
03b34a |
(int)(end - iphdr), ip_hl, h_len);
|
|
Packit |
03b34a |
return -1;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
return 0;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* For backwards binary compatibility. The calculations done here can easily
|
|
Packit |
03b34a |
* result in buffer overreads and overwrites. You have been warned. And no, it
|
|
Packit |
03b34a |
* is not possible to fix, the API contains no information on the buffer's
|
|
Packit |
03b34a |
* boundary. libnet itself calls the safe function, libnet_inet_checksum(). So
|
|
Packit |
03b34a |
* should you.
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
int
|
|
Packit |
03b34a |
libnet_do_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
uint16_t ip_len = 0;
|
|
Packit |
03b34a |
struct libnet_ipv4_hdr* ip4 = (struct libnet_ipv4_hdr *)iphdr;
|
|
Packit |
03b34a |
struct libnet_ipv6_hdr* ip6 = (struct libnet_ipv6_hdr *)iphdr;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
if(ip4->ip_v == 6) {
|
|
Packit |
03b34a |
ip_len = ntohs(ip6->ip_len);
|
|
Packit |
03b34a |
} else {
|
|
Packit |
03b34a |
ip_len = ntohs(ip4->ip_len);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
return libnet_inet_checksum(l, iphdr, protocol, h_len,
|
|
Packit |
03b34a |
iphdr, iphdr + ip_len
|
|
Packit |
03b34a |
);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
#define CHECK_IP_PAYLOAD_SIZE() do { \
|
|
Packit |
03b34a |
int e=check_ip_payload_size(l,iphdr,ip_hl, h_len, end, __func__);\
|
|
Packit |
03b34a |
if(e) return e;\
|
|
Packit |
03b34a |
} while(0)
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* We are checksumming pblock "q"
|
|
Packit |
03b34a |
*
|
|
Packit |
03b34a |
* iphdr is the pointer to it's encapsulating IP header
|
|
Packit |
03b34a |
* protocol describes the type of "q", expressed as an IPPROTO_ value
|
|
Packit |
03b34a |
* h_len is the h_len from "q"
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
int
|
|
Packit |
03b34a |
libnet_inet_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len, const uint8_t *beg, const uint8_t * end)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
/* will need to update this for ipv6 at some point */
|
|
Packit |
03b34a |
struct libnet_ipv4_hdr *iph_p = (struct libnet_ipv4_hdr *)iphdr;
|
|
Packit |
03b34a |
struct libnet_ipv6_hdr *ip6h_p = NULL; /* default to not using IPv6 */
|
|
Packit |
03b34a |
int ip_hl = 0;
|
|
Packit |
03b34a |
int sum = 0;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/* Check for memory under/over reads/writes. */
|
|
Packit |
03b34a |
if(iphdr < beg || (iphdr+sizeof(*iph_p)) > end)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
|
|
Packit |
03b34a |
"%s(): ipv4 hdr not inside packet (where %d, size %d)\n", __func__,
|
|
Packit |
03b34a |
(int)(iphdr-beg), (int)(end-beg));
|
|
Packit |
03b34a |
return -1;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* Figure out which IP version we're dealing with. We'll assume v4
|
|
Packit |
03b34a |
* and overlay a header structure to yank out the version.
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
if (iph_p->ip_v == 6)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
ip6h_p = (struct libnet_ipv6_hdr *)iph_p;
|
|
Packit |
03b34a |
iph_p = NULL;
|
|
Packit |
03b34a |
ip_hl = 40;
|
|
Packit |
03b34a |
if((uint8_t*)(ip6h_p+1) > end)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
|
|
Packit |
03b34a |
"%s(): ipv6 hdr not inside packet\n", __func__);
|
|
Packit |
03b34a |
return -1;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
else
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
ip_hl = iph_p->ip_hl << 2;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
if((iphdr+ip_hl) > end)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
|
|
Packit |
03b34a |
"%s(): ip hdr len not inside packet\n", __func__);
|
|
Packit |
03b34a |
return -1;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* Dug Song came up with this very cool checksuming implementation
|
|
Packit |
03b34a |
* eliminating the need for explicit psuedoheader use. Check it out.
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
switch (protocol)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
case IPPROTO_TCP:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_tcp_hdr *tcph_p =
|
|
Packit |
03b34a |
(struct libnet_tcp_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
h_len = end - (uint8_t*) tcph_p; /* ignore h_len, sum the packet we've coalesced */
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
#if (STUPID_SOLARIS_CHECKSUM_BUG)
|
|
Packit |
03b34a |
tcph_p->th_sum = tcph_p->th_off << 2;
|
|
Packit |
03b34a |
return (1);
|
|
Packit |
03b34a |
#endif /* STUPID_SOLARIS_CHECKSUM_BUG */
|
|
Packit |
03b34a |
#if (HAVE_HPUX11)
|
|
Packit |
03b34a |
if (l->injection_type != LIBNET_LINK)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* Similiar to the Solaris Checksum bug - but need to add
|
|
Packit |
03b34a |
* the size of the TCP payload (only for raw sockets).
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
tcph_p->th_sum = (tcph_p->th_off << 2) +
|
|
Packit |
03b34a |
(h_len - (tcph_p->th_off << 2));
|
|
Packit |
03b34a |
return (1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
/* TCP checksum is over the IP pseudo header:
|
|
Packit |
03b34a |
* ip src
|
|
Packit |
03b34a |
* ip dst
|
|
Packit |
03b34a |
* tcp protocol (IPPROTO_TCP)
|
|
Packit |
03b34a |
* tcp length, including the header
|
|
Packit |
03b34a |
* + the TCP header (with checksum set to zero) and data
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
tcph_p->th_sum = 0;
|
|
Packit |
03b34a |
if (ip6h_p)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
else
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
/* 8 = src and dst */
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)&iph_p->ip_src, 8);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
sum += ntohs(IPPROTO_TCP + h_len);
|
|
Packit |
03b34a |
sum += libnet_in_cksum((uint16_t *)tcph_p, h_len);
|
|
Packit |
03b34a |
tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
#if 0
|
|
Packit |
03b34a |
printf("tcp sum calculated: %#x/%d h_len %d\n",
|
|
Packit |
03b34a |
ntohs(tcph_p->th_sum),
|
|
Packit |
03b34a |
ntohs(tcph_p->th_sum),
|
|
Packit |
03b34a |
h_len
|
|
Packit |
03b34a |
);
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_UDP:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_udp_hdr *udph_p =
|
|
Packit |
03b34a |
(struct libnet_udp_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
h_len = end - (uint8_t*) udph_p; /* ignore h_len, sum the packet we've coalesced */
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
udph_p->uh_sum = 0;
|
|
Packit |
03b34a |
if (ip6h_p)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
else
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)&iph_p->ip_src, 8);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
sum += ntohs(IPPROTO_UDP + h_len);
|
|
Packit |
03b34a |
sum += libnet_in_cksum((uint16_t *)udph_p, h_len);
|
|
Packit |
03b34a |
udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_ICMP:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_icmpv4_hdr *icmph_p =
|
|
Packit |
03b34a |
(struct libnet_icmpv4_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
h_len = end - (uint8_t*) icmph_p; /* ignore h_len, sum the packet we've coalesced */
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
icmph_p->icmp_sum = 0;
|
|
Packit |
03b34a |
/* Hm, is this valid? Is the checksum algorithm for ICMPv6 encapsulated in IPv4
|
|
Packit |
03b34a |
* actually defined?
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
if (ip6h_p)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
|
|
Packit |
03b34a |
sum += ntohs(IPPROTO_ICMP6 + h_len);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
sum += libnet_in_cksum((uint16_t *)icmph_p, h_len);
|
|
Packit |
03b34a |
icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_ICMPV6:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_icmpv6_hdr *icmph_p =
|
|
Packit |
03b34a |
(struct libnet_icmpv6_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
h_len = end - (uint8_t*) icmph_p; /* ignore h_len, sum the packet we've coalesced */
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
icmph_p->icmp_sum = 0;
|
|
Packit |
03b34a |
if (ip6h_p)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32);
|
|
Packit |
03b34a |
sum += ntohs(IPPROTO_ICMP6 + h_len);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
sum += libnet_in_cksum((uint16_t *)icmph_p, h_len);
|
|
Packit |
03b34a |
icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_IGMP:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_igmp_hdr *igmph_p =
|
|
Packit |
03b34a |
(struct libnet_igmp_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
h_len = end - (uint8_t*) igmph_p; /* ignore h_len, sum the packet we've coalesced */
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
igmph_p->igmp_sum = 0;
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)igmph_p, h_len);
|
|
Packit |
03b34a |
igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_GRE:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
/* checksum is always at the same place in GRE header
|
|
Packit |
03b34a |
* in the multiple RFC version of the protocol ... ouf !!!
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
struct libnet_gre_hdr *greh_p =
|
|
Packit |
03b34a |
(struct libnet_gre_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
uint16_t fv = ntohs(greh_p->flags_ver);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||
|
|
Packit |
03b34a |
!(fv & (GRE_CSUM|GRE_VERSION_1)))
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
|
|
Packit |
03b34a |
"%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n", __func__, fv);
|
|
Packit |
03b34a |
return (-1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)greh_p, h_len);
|
|
Packit |
03b34a |
greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_OSPF:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_ospf_hdr *oh_p =
|
|
Packit |
03b34a |
(struct libnet_ospf_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
oh_p->ospf_sum = 0;
|
|
Packit |
03b34a |
sum += libnet_in_cksum((uint16_t *)oh_p, h_len);
|
|
Packit |
03b34a |
oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_OSPF_LSA:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_ospf_hdr *oh_p =
|
|
Packit |
03b34a |
(struct libnet_ospf_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
struct libnet_lsa_hdr *lsa_p =
|
|
Packit |
03b34a |
(struct libnet_lsa_hdr *)(iphdr +
|
|
Packit |
03b34a |
ip_hl + oh_p->ospf_len);
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/* FIXME need additional length check, to account for ospf_len */
|
|
Packit |
03b34a |
lsa_p->lsa_sum = 0;
|
|
Packit |
03b34a |
sum += libnet_in_cksum((uint16_t *)lsa_p, h_len);
|
|
Packit |
03b34a |
lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
#if 0
|
|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* Reworked fletcher checksum taken from RFC 1008.
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
int c0, c1;
|
|
Packit |
03b34a |
struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;
|
|
Packit |
03b34a |
uint8_t *p, *p1, *p2, *p3;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
c0 = 0;
|
|
Packit |
03b34a |
c1 = 0;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
lsa_p->lsa_cksum = 0;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
p = buf;
|
|
Packit |
03b34a |
p1 = buf;
|
|
Packit |
03b34a |
p3 = buf + len; /* beginning and end of buf */
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
while (p1 < p3)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
p2 = p1 + LIBNET_MODX;
|
|
Packit |
03b34a |
if (p2 > p3)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
p2 = p3;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
for (p = p1; p < p2; p++)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
c0 += (*p);
|
|
Packit |
03b34a |
c1 += c0;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
c0 %= 255;
|
|
Packit |
03b34a |
c1 %= 255; /* modular 255 */
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
p1 = p2;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
#if AWR_PLEASE_REWORK_THIS
|
|
Packit |
03b34a |
lsa_p->lsa_cksum[0] = (((len - 17) * c0 - c1) % 255);
|
|
Packit |
03b34a |
if (lsa_p->lsa_cksum[0] <= 0)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
lsa_p->lsa_cksum[0] += 255;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
lsa_p->lsa_cksum[1] = (510 - c0 - lsa_p->lsa_cksum[0]);
|
|
Packit |
03b34a |
if (lsa_p->lsa_cksum[1] > 255)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
lsa_p->lsa_cksum[1] -= 255;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_IP:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
if(!iph_p) {
|
|
Packit |
03b34a |
/* IPv6 doesn't have a checksum */
|
|
Packit |
03b34a |
} else {
|
|
Packit |
03b34a |
iph_p->ip_sum = 0;
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)iph_p, ip_hl);
|
|
Packit |
03b34a |
iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case IPPROTO_VRRP:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
struct libnet_vrrp_hdr *vrrph_p =
|
|
Packit |
03b34a |
(struct libnet_vrrp_hdr *)(iphdr + ip_hl);
|
|
Packit |
03b34a |
CHECK_IP_PAYLOAD_SIZE();
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
vrrph_p->vrrp_sum = 0;
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)vrrph_p, h_len);
|
|
Packit |
03b34a |
vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case LIBNET_PROTO_CDP:
|
|
Packit |
03b34a |
{ /* XXX - Broken: how can we easily get the entire packet size? */
|
|
Packit |
03b34a |
/* FIXME you can't, checksumming non-IP protocols was not supported by libnet */
|
|
Packit |
03b34a |
struct libnet_cdp_hdr *cdph_p =
|
|
Packit |
03b34a |
(struct libnet_cdp_hdr *)iphdr;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
if((iphdr+h_len) > end)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
|
|
Packit |
03b34a |
"%s(): cdp payload not inside packet\n", __func__);
|
|
Packit |
03b34a |
return -1;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
cdph_p->cdp_sum = 0;
|
|
Packit |
03b34a |
sum = libnet_in_cksum((uint16_t *)cdph_p, h_len);
|
|
Packit |
03b34a |
cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);
|
|
Packit |
03b34a |
break;
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
case LIBNET_PROTO_ISL:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
#if 0
|
|
Packit |
03b34a |
struct libnet_isl_hdr *islh_p =
|
|
Packit |
03b34a |
(struct libnet_isl_hdr *)buf;
|
|
Packit |
03b34a |
#endif
|
|
Packit |
03b34a |
/*
|
|
Packit |
03b34a |
* Need to compute 4 byte CRC for the ethernet frame and for
|
|
Packit |
03b34a |
* the ISL frame itself. Use the libnet_crc function.
|
|
Packit |
03b34a |
*/
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
default:
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
|
|
Packit |
03b34a |
"%s(): unsupported protocol %d\n", __func__, protocol);
|
|
Packit |
03b34a |
return (-1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
return (1);
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
uint16_t
|
|
Packit |
03b34a |
libnet_ip_check(uint16_t *addr, int len)
|
|
Packit |
03b34a |
{
|
|
Packit |
03b34a |
int sum;
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
sum = libnet_in_cksum(addr, len);
|
|
Packit |
03b34a |
return (LIBNET_CKSUM_CARRY(sum));
|
|
Packit |
03b34a |
}
|
|
Packit |
03b34a |
|
|
Packit |
03b34a |
/* EOF */
|