mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 07:38:19 +00:00

* origin/topic/vladg/dhcp: DHCP: Adding unit tests. DHCP: Rework the DHCP analyzer to make it compatible again.
181 lines
4.1 KiB
C++
181 lines
4.1 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "config.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include "Reporter.h"
|
|
#include "net_util.h"
|
|
#include "IPAddr.h"
|
|
#include "IP.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 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;
|
|
}
|
|
|
|
#ifdef ENABLE_MOBILE_IPV6
|
|
int mobility_header_checksum(const IP_Hdr* ip)
|
|
{
|
|
const ip6_mobility* mh = ip->MobilityHeader();
|
|
|
|
if ( ! mh ) return 0;
|
|
|
|
uint32 sum = 0;
|
|
uint8 mh_len = 8 + 8 * mh->ip6mob_len;
|
|
|
|
if ( mh_len % 2 == 1 )
|
|
reporter->Weird(ip->SrcAddr(), ip->DstAddr(), "odd_mobility_hdr_len");
|
|
|
|
sum = ones_complement_checksum(ip->SrcAddr(), sum);
|
|
sum = ones_complement_checksum(ip->DstAddr(), sum);
|
|
// Note, for IPv6, strictly speaking the protocol and length fields are
|
|
// 32 bits rather than 16 bits. But because the upper bits are all zero,
|
|
// we get the same checksum either way.
|
|
sum += htons(IPPROTO_MOBILITY);
|
|
sum += htons(mh_len);
|
|
sum = ones_complement_checksum(mh, mh_len, sum);
|
|
|
|
return sum;
|
|
}
|
|
#endif
|
|
|
|
int icmp6_checksum(const struct icmp* icmpp, const IP_Hdr* ip, int len)
|
|
{
|
|
// ICMP6 uses the same checksum function as ICMP4 but a different
|
|
// pseudo-header over which it is computed.
|
|
uint32 sum;
|
|
|
|
if ( len % 2 == 1 )
|
|
// Add in pad byte.
|
|
sum = htons(((const u_char*) icmpp)[len - 1] << 8);
|
|
else
|
|
sum = 0;
|
|
|
|
// Pseudo-header as for UDP over IPv6 above.
|
|
sum = ones_complement_checksum(ip->SrcAddr(), sum);
|
|
sum = ones_complement_checksum(ip->DstAddr(), sum);
|
|
uint32 l = htonl(len);
|
|
sum = ones_complement_checksum((void*) &l, 4, sum);
|
|
|
|
uint32 addl_pseudo = htons(IPPROTO_ICMPV6);
|
|
sum = ones_complement_checksum((void*) &addl_pseudo, 4, sum);
|
|
|
|
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';
|
|
}
|
|
|
|
const char* fmt_conn_id(const IPAddr& src_addr, uint32 src_port,
|
|
const IPAddr& dst_addr, uint32 dst_port)
|
|
{
|
|
static char buffer[512];
|
|
|
|
safe_snprintf(buffer, sizeof(buffer), "%s:%d > %s:%d",
|
|
string(src_addr).c_str(), src_port,
|
|
string(dst_addr).c_str(), dst_port);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
const char* fmt_conn_id(const uint32* src_addr, uint32 src_port,
|
|
const uint32* dst_addr, uint32 dst_port)
|
|
{
|
|
IPAddr src(IPv6, src_addr, IPAddr::Network);
|
|
IPAddr dst(IPv6, dst_addr, IPAddr::Network);
|
|
return fmt_conn_id(src, src_port, dst, dst_port);
|
|
}
|
|
|
|
char* fmt_mac(const unsigned char* m, int len)
|
|
{
|
|
char* buf = new char[25];
|
|
|
|
if ( len < 8 )
|
|
{
|
|
*buf = '\0';
|
|
return buf;
|
|
}
|
|
|
|
if ( m[6] == 0 && m[7] == 0 ) // EUI-48
|
|
snprintf(buf, 19, "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
m[0], m[1], m[2], m[3], m[4], m[5]);
|
|
else
|
|
snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
|
|
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7]);
|
|
|
|
return buf;
|
|
}
|
|
|
|
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;
|
|
}
|