// See the file "COPYING" in the main distribution directory for copyright. #include "config.h" #include #include #include #include #include "Reporter.h" #include "net_util.h" #include "IPAddr.h" // - adapted from tcpdump // Returns the ones-complement checksum of a chunk of b short-aligned bytes. int ones_complement_checksum(const void* p, int b, uint32 sum) { const u_short* sp = (u_short*) p; // better be aligned! b /= 2; // convert to count of short's /* No need for endian conversions. */ while ( --b >= 0 ) sum += *sp++; while ( sum > 0xffff ) sum = (sum & 0xffff) + (sum >> 16); return sum; } int ones_complement_checksum(const IPAddr& a, uint32 sum) { const uint32* bytes; int len = a.GetBytes(&bytes); return ones_complement_checksum(bytes, len*4, sum); } int tcp_checksum(const struct ip* ip, const struct tcphdr* tp, int len) { // ### Note, this is only correct for IPv4. This routine is only // used by the connection compressor (which we turn off for IPv6 // traffic). int tcp_len = tp->th_off * 4 + len; uint32 sum; if ( len % 2 == 1 ) // Add in pad byte. sum = htons(((const u_char*) tp)[tcp_len - 1] << 8); else sum = 0; sum = ones_complement_checksum((void*) &ip->ip_src.s_addr, 4, sum); sum = ones_complement_checksum((void*) &ip->ip_dst.s_addr, 4, sum); uint32 addl_pseudo = (htons(IPPROTO_TCP) << 16) | htons((unsigned short) tcp_len); sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum); sum = ones_complement_checksum((void*) tp, tcp_len, sum); return sum; } int udp_checksum(const struct ip* ip, const struct udphdr* up, int len) { uint32 sum; if ( len % 2 == 1 ) // Add in pad byte. sum = htons(((const u_char*) up)[len - 1] << 8); else sum = 0; sum = ones_complement_checksum((void*) &ip->ip_src.s_addr, 4, sum); sum = ones_complement_checksum((void*) &ip->ip_dst.s_addr, 4, sum); uint32 addl_pseudo = (htons(IPPROTO_UDP) << 16) | htons((unsigned short) len); sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum); sum = ones_complement_checksum((void*) up, len, sum); return sum; } int udp6_checksum(const struct ip6_hdr* ip6, const struct udphdr* up, int len) { uint32 sum; if ( len % 2 == 1 ) // Add in pad byte. sum = htons(((const u_char*) up)[len - 1] << 8); else sum = 0; sum = ones_complement_checksum((void*) ip6->ip6_src.s6_addr, 16, sum); sum = ones_complement_checksum((void*) ip6->ip6_dst.s6_addr, 16, sum); uint32 l = htonl(len); sum = ones_complement_checksum((void*) &l, 4, sum); uint32 addl_pseudo = htons(IPPROTO_UDP); sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum); sum = ones_complement_checksum((void*) up, len, sum); return sum; } int icmp_checksum(const struct icmp* icmpp, int len) { uint32 sum; if ( len % 2 == 1 ) // Add in pad byte. sum = htons(((const u_char*) icmpp)[len - 1] << 8); else sum = 0; sum = ones_complement_checksum((void*) icmpp, len, sum); return sum; } #define CLASS_A 0x00000000 #define CLASS_B 0x80000000 #define CLASS_C 0xc0000000 #define CLASS_D 0xe0000000 #define CLASS_E 0xf0000000 #define CHECK_CLASS(addr,class) (((addr) & (class)) == (class)) char addr_to_class(uint32 addr) { if ( CHECK_CLASS(addr, CLASS_E) ) return 'E'; else if ( CHECK_CLASS(addr, CLASS_D) ) return 'D'; else if ( CHECK_CLASS(addr, CLASS_C) ) return 'C'; else if ( CHECK_CLASS(addr, CLASS_B) ) return 'B'; else return 'A'; } uint32 extract_uint32(const u_char* data) { uint32 val; val = data[0] << 24; val |= data[1] << 16; val |= data[2] << 8; val |= data[3]; return val; }