version 1.1.1.1, 2012/02/21 22:14:23
|
version 1.1.1.2, 2013/07/22 11:54:42
|
Line 38
|
Line 38
|
#else |
#else |
#include "../include/win32/libnet.h" |
#include "../include/win32/libnet.h" |
#endif |
#endif |
|
|
|
/* FIXME - unit test these - 0 is debian's version, else is -RC1's */ |
|
/* Note about aliasing warning: |
|
* |
|
* http://mail.opensolaris.org/pipermail/tools-gcc/2005-August/000047.html |
|
* |
|
* See RFC 1071, and: |
|
* |
|
* http://mathforum.org/library/drmath/view/54379.html |
|
*/ |
|
#undef DEBIAN |
|
/* Note: len is in bytes, not 16-bit words! */ |
int |
int |
libnet_in_cksum(u_int16_t *addr, int len) | libnet_in_cksum(uint16_t *addr, int len) |
{ |
{ |
int sum; |
int sum; |
|
#ifdef DEBIAN |
|
uint16_t last_byte; |
|
|
sum = 0; |
sum = 0; |
|
last_byte = 0; |
|
#else |
|
union |
|
{ |
|
uint16_t s; |
|
uint8_t b[2]; |
|
}pad; |
|
|
|
sum = 0; |
|
#endif |
|
|
while (len > 1) |
while (len > 1) |
{ |
{ |
sum += *addr++; |
sum += *addr++; |
len -= 2; |
len -= 2; |
} |
} |
|
#ifdef DEBIAN |
if (len == 1) |
if (len == 1) |
{ |
{ |
sum += *(u_int16_t *)addr; | *(uint8_t *)&last_byte = *(uint8_t *)addr; |
| sum += last_byte; |
| #else |
| if (len == 1) |
| { |
| pad.b[0] = *(uint8_t *)addr; |
| pad.b[1] = 0; |
| sum += pad.s; |
| #endif |
} |
} |
|
|
return (sum); |
return (sum); |
Line 95 libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag
|
Line 128 libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag
|
} |
} |
} |
} |
|
|
|
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) |
|
{ |
|
if((iphdr+ip_hl+h_len) > end) |
|
{ |
|
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
|
"%s(): ip payload not inside packet (pktsz %d, iphsz %d, payloadsz %d)\n", func, |
|
(int)(end - iphdr), ip_hl, h_len); |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
/* |
|
* For backwards binary compatibility. The calculations done here can easily |
|
* result in buffer overreads and overwrites. You have been warned. And no, it |
|
* is not possible to fix, the API contains no information on the buffer's |
|
* boundary. libnet itself calls the safe function, libnet_inet_checksum(). So |
|
* should you. |
|
*/ |
int |
int |
libnet_do_checksum(libnet_t *l, u_int8_t *buf, int protocol, int len) | libnet_do_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len) |
{ |
{ |
/* will need to update this for ipv6 at some point */ | uint16_t ip_len = 0; |
struct libnet_ipv4_hdr *iph_p; | struct libnet_ipv4_hdr* ip4 = (struct libnet_ipv4_hdr *)iphdr; |
struct libnet_ipv6_hdr *ip6h_p; | struct libnet_ipv6_hdr* ip6 = (struct libnet_ipv6_hdr *)iphdr; |
int is_ipv6; | |
int ip_hl; | |
int sum; | |
|
|
is_ipv6 = 0; /* default to not using IPv6 */ | if(ip4->ip_v == 6) { |
sum = 0; | ip_len = ntohs(ip6->ip_len); |
iph_p = NULL; | } else { |
ip6h_p = NULL; | ip_len = ntohs(ip4->ip_len); |
| } |
|
|
if (len == 0) | return libnet_inet_checksum(l, iphdr, protocol, h_len, |
| iphdr, iphdr + ip_len |
| ); |
| } |
| |
| |
| #define CHECK_IP_PAYLOAD_SIZE() do { \ |
| int e=check_ip_payload_size(l,iphdr,ip_hl, h_len, end, __func__);\ |
| if(e) return e;\ |
| } while(0) |
| |
| |
| /* |
| * We are checksumming pblock "q" |
| * |
| * iphdr is the pointer to it's encapsulating IP header |
| * protocol describes the type of "q", expressed as an IPPROTO_ value |
| * h_len is the h_len from "q" |
| */ |
| int |
| libnet_inet_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len, const uint8_t *beg, const uint8_t * end) |
| { |
| /* will need to update this for ipv6 at some point */ |
| struct libnet_ipv4_hdr *iph_p = (struct libnet_ipv4_hdr *)iphdr; |
| struct libnet_ipv6_hdr *ip6h_p = NULL; /* default to not using IPv6 */ |
| int ip_hl = 0; |
| int sum = 0; |
| |
| /* Check for memory under/over reads/writes. */ |
| if(iphdr < beg || (iphdr+sizeof(*iph_p)) > end) |
{ |
{ |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
"%s(): header length can't be zero\n", __func__); | "%s(): ipv4 hdr not inside packet (where %d, size %d)\n", __func__, |
return (-1); | (int)(iphdr-beg), (int)(end-beg)); |
| return -1; |
} |
} |
|
|
/* |
/* |
* Figure out which IP version we're dealing with. We'll assume v4 |
* Figure out which IP version we're dealing with. We'll assume v4 |
* and overlay a header structure to yank out the version. |
* and overlay a header structure to yank out the version. |
*/ |
*/ |
iph_p = (struct libnet_ipv4_hdr *)buf; | if (iph_p->ip_v == 6) |
if (iph_p && iph_p->ip_v == 6) | |
{ |
{ |
ip6h_p = (struct libnet_ipv6_hdr *)buf; | ip6h_p = (struct libnet_ipv6_hdr *)iph_p; |
is_ipv6 = 1; | iph_p = NULL; |
ip_hl = 40; |
ip_hl = 40; |
|
if((uint8_t*)(ip6h_p+1) > end) |
|
{ |
|
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
|
"%s(): ipv6 hdr not inside packet\n", __func__); |
|
return -1; |
|
} |
} |
} |
else |
else |
{ |
{ |
is_ipv6 = 0; |
|
ip_hl = iph_p->ip_hl << 2; |
ip_hl = iph_p->ip_hl << 2; |
} |
} |
|
|
|
if((iphdr+ip_hl) > end) |
|
{ |
|
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
|
"%s(): ip hdr len not inside packet\n", __func__); |
|
return -1; |
|
} |
|
|
/* |
/* |
* Dug Song came up with this very cool checksuming implementation |
* Dug Song came up with this very cool checksuming implementation |
* eliminating the need for explicit psuedoheader use. Check it out. |
* eliminating the need for explicit psuedoheader use. Check it out. |
*/ |
*/ |
switch (protocol) |
switch (protocol) |
{ |
{ |
/* |
|
* Style note: normally I don't advocate declaring variables inside |
|
* blocks of control, but it makes good sense here. -- MDS |
|
*/ |
|
case IPPROTO_TCP: |
case IPPROTO_TCP: |
{ |
{ |
struct libnet_tcp_hdr *tcph_p = |
struct libnet_tcp_hdr *tcph_p = |
(struct libnet_tcp_hdr *)(buf + ip_hl); | (struct libnet_tcp_hdr *)(iphdr + ip_hl); |
|
|
|
h_len = end - (uint8_t*) tcph_p; /* ignore h_len, sum the packet we've coalesced */ |
|
|
|
CHECK_IP_PAYLOAD_SIZE(); |
|
|
#if (STUPID_SOLARIS_CHECKSUM_BUG) |
#if (STUPID_SOLARIS_CHECKSUM_BUG) |
tcph_p->th_sum = tcph_p->th_off << 2; |
tcph_p->th_sum = tcph_p->th_off << 2; |
return (1); |
return (1); |
Line 162 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
Line 254 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
* the size of the TCP payload (only for raw sockets). |
* the size of the TCP payload (only for raw sockets). |
*/ |
*/ |
tcph_p->th_sum = (tcph_p->th_off << 2) + |
tcph_p->th_sum = (tcph_p->th_off << 2) + |
(len - (tcph_p->th_off << 2)); | (h_len - (tcph_p->th_off << 2)); |
return (1); |
return (1); |
} |
} |
#endif |
#endif |
|
/* TCP checksum is over the IP pseudo header: |
|
* ip src |
|
* ip dst |
|
* tcp protocol (IPPROTO_TCP) |
|
* tcp length, including the header |
|
* + the TCP header (with checksum set to zero) and data |
|
*/ |
tcph_p->th_sum = 0; |
tcph_p->th_sum = 0; |
if (is_ipv6) | if (ip6h_p) |
{ |
{ |
sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32); | sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32); |
} |
} |
else |
else |
{ |
{ |
sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8); | /* 8 = src and dst */ |
| sum = libnet_in_cksum((uint16_t *)&iph_p->ip_src, 8); |
} |
} |
sum += ntohs(IPPROTO_TCP + len); | sum += ntohs(IPPROTO_TCP + h_len); |
sum += libnet_in_cksum((u_int16_t *)tcph_p, len); | sum += libnet_in_cksum((uint16_t *)tcph_p, h_len); |
tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum); |
tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum); |
|
#if 0 |
|
printf("tcp sum calculated: %#x/%d h_len %d\n", |
|
ntohs(tcph_p->th_sum), |
|
ntohs(tcph_p->th_sum), |
|
h_len |
|
); |
|
#endif |
break; |
break; |
} |
} |
case IPPROTO_UDP: |
case IPPROTO_UDP: |
{ |
{ |
struct libnet_udp_hdr *udph_p = |
struct libnet_udp_hdr *udph_p = |
(struct libnet_udp_hdr *)(buf + ip_hl); | (struct libnet_udp_hdr *)(iphdr + ip_hl); |
| |
| h_len = end - (uint8_t*) udph_p; /* ignore h_len, sum the packet we've coalesced */ |
| |
| CHECK_IP_PAYLOAD_SIZE(); |
| |
udph_p->uh_sum = 0; |
udph_p->uh_sum = 0; |
if (is_ipv6) | if (ip6h_p) |
{ |
{ |
sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32); | sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32); |
} |
} |
else |
else |
{ |
{ |
sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8); | sum = libnet_in_cksum((uint16_t *)&iph_p->ip_src, 8); |
} |
} |
sum += ntohs(IPPROTO_UDP + len); | sum += ntohs(IPPROTO_UDP + h_len); |
sum += libnet_in_cksum((u_int16_t *)udph_p, len); | sum += libnet_in_cksum((uint16_t *)udph_p, h_len); |
udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum); |
udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
} |
} |
case IPPROTO_ICMP: |
case IPPROTO_ICMP: |
{ |
{ |
struct libnet_icmpv4_hdr *icmph_p = |
struct libnet_icmpv4_hdr *icmph_p = |
(struct libnet_icmpv4_hdr *)(buf + ip_hl); | (struct libnet_icmpv4_hdr *)(iphdr + ip_hl); |
|
|
|
h_len = end - (uint8_t*) icmph_p; /* ignore h_len, sum the packet we've coalesced */ |
|
|
|
CHECK_IP_PAYLOAD_SIZE(); |
|
|
icmph_p->icmp_sum = 0; |
icmph_p->icmp_sum = 0; |
if (is_ipv6) | /* Hm, is this valid? Is the checksum algorithm for ICMPv6 encapsulated in IPv4 |
| * actually defined? |
| */ |
| if (ip6h_p) |
{ |
{ |
sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32); | sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32); |
sum += ntohs(IPPROTO_ICMP6 + len); | sum += ntohs(IPPROTO_ICMP6 + h_len); |
} |
} |
sum += libnet_in_cksum((u_int16_t *)icmph_p, len); | sum += libnet_in_cksum((uint16_t *)icmph_p, h_len); |
icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum); |
icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
} |
} |
|
case IPPROTO_ICMPV6: |
|
{ |
|
struct libnet_icmpv6_hdr *icmph_p = |
|
(struct libnet_icmpv6_hdr *)(iphdr + ip_hl); |
|
|
|
h_len = end - (uint8_t*) icmph_p; /* ignore h_len, sum the packet we've coalesced */ |
|
|
|
CHECK_IP_PAYLOAD_SIZE(); |
|
|
|
icmph_p->icmp_sum = 0; |
|
if (ip6h_p) |
|
{ |
|
sum = libnet_in_cksum((uint16_t *)&ip6h_p->ip_src, 32); |
|
sum += ntohs(IPPROTO_ICMP6 + h_len); |
|
} |
|
sum += libnet_in_cksum((uint16_t *)icmph_p, h_len); |
|
icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum); |
|
break; |
|
} |
case IPPROTO_IGMP: |
case IPPROTO_IGMP: |
{ |
{ |
struct libnet_igmp_hdr *igmph_p = |
struct libnet_igmp_hdr *igmph_p = |
(struct libnet_igmp_hdr *)(buf + ip_hl); | (struct libnet_igmp_hdr *)(iphdr + ip_hl); |
|
|
|
h_len = end - (uint8_t*) igmph_p; /* ignore h_len, sum the packet we've coalesced */ |
|
|
|
CHECK_IP_PAYLOAD_SIZE(); |
|
|
igmph_p->igmp_sum = 0; |
igmph_p->igmp_sum = 0; |
sum = libnet_in_cksum((u_int16_t *)igmph_p, len); | sum = libnet_in_cksum((uint16_t *)igmph_p, h_len); |
igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum); |
igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
} |
} |
Line 229 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
Line 371 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
* in the multiple RFC version of the protocol ... ouf !!! |
* in the multiple RFC version of the protocol ... ouf !!! |
*/ |
*/ |
struct libnet_gre_hdr *greh_p = |
struct libnet_gre_hdr *greh_p = |
(struct libnet_gre_hdr *)(buf + ip_hl); | (struct libnet_gre_hdr *)(iphdr + ip_hl); |
u_int16_t fv = ntohs(greh_p->flags_ver); | uint16_t fv = ntohs(greh_p->flags_ver); |
| |
| CHECK_IP_PAYLOAD_SIZE(); |
| |
if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) || |
if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) || |
!(fv & (GRE_CSUM|GRE_VERSION_1))) |
!(fv & (GRE_CSUM|GRE_VERSION_1))) |
{ |
{ |
Line 238 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
Line 383 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
"%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n", __func__, fv); |
"%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n", __func__, fv); |
return (-1); |
return (-1); |
} |
} |
sum = libnet_in_cksum((u_int16_t *)greh_p, len); | sum = libnet_in_cksum((uint16_t *)greh_p, h_len); |
greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum); |
greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
} |
} |
case IPPROTO_OSPF: |
case IPPROTO_OSPF: |
{ |
{ |
struct libnet_ospf_hdr *oh_p = |
struct libnet_ospf_hdr *oh_p = |
(struct libnet_ospf_hdr *)(buf + ip_hl); | (struct libnet_ospf_hdr *)(iphdr + ip_hl); |
|
|
|
CHECK_IP_PAYLOAD_SIZE(); |
|
|
oh_p->ospf_sum = 0; |
oh_p->ospf_sum = 0; |
sum += libnet_in_cksum((u_int16_t *)oh_p, len); | sum += libnet_in_cksum((uint16_t *)oh_p, h_len); |
oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum); |
oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
} |
} |
case IPPROTO_OSPF_LSA: |
case IPPROTO_OSPF_LSA: |
{ |
{ |
struct libnet_ospf_hdr *oh_p = |
struct libnet_ospf_hdr *oh_p = |
(struct libnet_ospf_hdr *)(buf + ip_hl); | (struct libnet_ospf_hdr *)(iphdr + ip_hl); |
struct libnet_lsa_hdr *lsa_p = |
struct libnet_lsa_hdr *lsa_p = |
(struct libnet_lsa_hdr *)(buf + | (struct libnet_lsa_hdr *)(iphdr + |
ip_hl + oh_p->ospf_len); |
ip_hl + oh_p->ospf_len); |
|
|
|
/* FIXME need additional length check, to account for ospf_len */ |
lsa_p->lsa_sum = 0; |
lsa_p->lsa_sum = 0; |
sum += libnet_in_cksum((u_int16_t *)lsa_p, len); | sum += libnet_in_cksum((uint16_t *)lsa_p, h_len); |
lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum); |
lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
#if 0 |
#if 0 |
Line 270 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
Line 418 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
*/ |
*/ |
int c0, c1; |
int c0, c1; |
struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf; |
struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf; |
u_int8_t *p, *p1, *p2, *p3; | uint8_t *p, *p1, *p2, *p3; |
|
|
c0 = 0; |
c0 = 0; |
c1 = 0; |
c1 = 0; |
Line 319 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
Line 467 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
} |
} |
case IPPROTO_IP: |
case IPPROTO_IP: |
{ |
{ |
iph_p->ip_sum = 0; | if(!iph_p) { |
sum = libnet_in_cksum((u_int16_t *)iph_p, ip_hl); | /* IPv6 doesn't have a checksum */ |
iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum); | } else { |
| iph_p->ip_sum = 0; |
| sum = libnet_in_cksum((uint16_t *)iph_p, ip_hl); |
| iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum); |
| } |
break; |
break; |
} |
} |
case IPPROTO_VRRP: |
case IPPROTO_VRRP: |
{ |
{ |
struct libnet_vrrp_hdr *vrrph_p = |
struct libnet_vrrp_hdr *vrrph_p = |
(struct libnet_vrrp_hdr *)(buf + ip_hl); | (struct libnet_vrrp_hdr *)(iphdr + ip_hl); |
| CHECK_IP_PAYLOAD_SIZE(); |
|
|
vrrph_p->vrrp_sum = 0; |
vrrph_p->vrrp_sum = 0; |
sum = libnet_in_cksum((u_int16_t *)vrrph_p, len); | sum = libnet_in_cksum((uint16_t *)vrrph_p, h_len); |
vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum); |
vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
} |
} |
case LIBNET_PROTO_CDP: |
case LIBNET_PROTO_CDP: |
{ /* XXX - Broken: how can we easily get the entire packet size? */ |
{ /* XXX - Broken: how can we easily get the entire packet size? */ |
|
/* FIXME you can't, checksumming non-IP protocols was not supported by libnet */ |
struct libnet_cdp_hdr *cdph_p = |
struct libnet_cdp_hdr *cdph_p = |
(struct libnet_cdp_hdr *)buf; | (struct libnet_cdp_hdr *)iphdr; |
|
|
|
if((iphdr+h_len) > end) |
|
{ |
|
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
|
"%s(): cdp payload not inside packet\n", __func__); |
|
return -1; |
|
} |
|
|
cdph_p->cdp_sum = 0; |
cdph_p->cdp_sum = 0; |
sum = libnet_in_cksum((u_int16_t *)cdph_p, len); | sum = libnet_in_cksum((uint16_t *)cdph_p, h_len); |
cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum); |
cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum); |
break; |
break; |
} |
} |
case LIBNET_PROTO_ISL: |
case LIBNET_PROTO_ISL: |
{ |
{ |
// struct libnet_isl_hdr *islh_p = | #if 0 |
// (struct libnet_isl_hdr *)buf; | struct libnet_isl_hdr *islh_p = |
| (struct libnet_isl_hdr *)buf; |
| #endif |
/* |
/* |
* Need to compute 4 byte CRC for the ethernet frame and for |
* Need to compute 4 byte CRC for the ethernet frame and for |
* the ISL frame itself. Use the libnet_crc function. |
* the ISL frame itself. Use the libnet_crc function. |
Line 356 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
Line 519 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
default: |
default: |
{ |
{ |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, |
"%s(): unsuported protocol %d\n", __func__, protocol); | "%s(): unsupported protocol %d\n", __func__, protocol); |
return (-1); |
return (-1); |
} |
} |
} |
} |
Line 364 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
Line 527 libnet_do_checksum(libnet_t *l, u_int8_t *buf, int pro
|
} |
} |
|
|
|
|
u_int16_t | uint16_t |
libnet_ip_check(u_int16_t *addr, int len) | libnet_ip_check(uint16_t *addr, int len) |
{ |
{ |
int sum; |
int sum; |
|
|