mirror of
https://github.com/zeek/zeek.git
synced 2025-10-08 17:48:21 +00:00
Merge remote-tracking branch 'origin/master' into topic/seth/pppoe
This commit is contained in:
commit
012acb22e9
1326 changed files with 60201 additions and 14196 deletions
|
@ -17,7 +17,7 @@ ARP_Analyzer::~ARP_Analyzer()
|
|||
{
|
||||
}
|
||||
|
||||
bool ARP_Analyzer::IsARP(const u_char* pkt, int hdr_size) const
|
||||
bool ARP_Analyzer::IsARP(const u_char* pkt, int hdr_size)
|
||||
{
|
||||
unsigned short network_protocol =
|
||||
*(unsigned short*) (pkt + hdr_size - 2);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <sys/ethernet.h>
|
||||
#elif defined(HAVE_NETINET_IF_ETHER_H)
|
||||
#include <netinet/if_ether.h>
|
||||
#elif defined(HAVE_NET_ETHERTYPES_H)
|
||||
#include <net/ethertypes.h>
|
||||
#endif
|
||||
|
||||
#ifndef arp_pkthdr
|
||||
|
@ -29,9 +31,6 @@ public:
|
|||
ARP_Analyzer();
|
||||
virtual ~ARP_Analyzer();
|
||||
|
||||
// Whether a packet is of interest for ARP analysis.
|
||||
bool IsARP(const u_char* pkt, int hdr_size) const;
|
||||
|
||||
void NextPacket(double t, const struct pcap_pkthdr* hdr,
|
||||
const u_char* const pkt, int hdr_size);
|
||||
|
||||
|
@ -39,6 +38,10 @@ public:
|
|||
void RREvent(EventHandlerPtr e, const u_char* src, const u_char* dst,
|
||||
const char* spa, const char* sha,
|
||||
const char* tpa, const char* tha);
|
||||
|
||||
// Whether a packet is of interest for ARP analysis.
|
||||
static bool IsARP(const u_char* pkt, int hdr_size);
|
||||
|
||||
protected:
|
||||
AddrVal* ConstructAddrVal(const void* addr);
|
||||
StringVal* EthAddrToStr(const u_char* addr);
|
||||
|
|
24
src/AYIYA.cc
Normal file
24
src/AYIYA.cc
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "AYIYA.h"
|
||||
|
||||
AYIYA_Analyzer::AYIYA_Analyzer(Connection* conn)
|
||||
: Analyzer(AnalyzerTag::AYIYA, conn)
|
||||
{
|
||||
interp = new binpac::AYIYA::AYIYA_Conn(this);
|
||||
}
|
||||
|
||||
AYIYA_Analyzer::~AYIYA_Analyzer()
|
||||
{
|
||||
delete interp;
|
||||
}
|
||||
|
||||
void AYIYA_Analyzer::Done()
|
||||
{
|
||||
Analyzer::Done();
|
||||
Event(udp_session_done);
|
||||
}
|
||||
|
||||
void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen)
|
||||
{
|
||||
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
|
||||
interp->NewData(orig, data, data + len);
|
||||
}
|
29
src/AYIYA.h
Normal file
29
src/AYIYA.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef AYIYA_h
|
||||
#define AYIYA_h
|
||||
|
||||
#include "ayiya_pac.h"
|
||||
|
||||
class AYIYA_Analyzer : public Analyzer {
|
||||
public:
|
||||
AYIYA_Analyzer(Connection* conn);
|
||||
virtual ~AYIYA_Analyzer();
|
||||
|
||||
virtual void Done();
|
||||
virtual void DeliverPacket(int len, const u_char* data, bool orig,
|
||||
int seq, const IP_Hdr* ip, int caplen);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new AYIYA_Analyzer(conn); }
|
||||
|
||||
static bool Available()
|
||||
{ return BifConst::Tunnel::enable_ayiya &&
|
||||
BifConst::Tunnel::max_depth > 0; }
|
||||
|
||||
protected:
|
||||
friend class AnalyzerTimer;
|
||||
void ExpireTimer(double t);
|
||||
|
||||
binpac::AYIYA::AYIYA_Conn* interp;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include "PIA.h"
|
||||
#include "Event.h"
|
||||
|
||||
#include "AYIYA.h"
|
||||
#include "BackDoor.h"
|
||||
#include "BitTorrent.h"
|
||||
#include "BitTorrentTracker.h"
|
||||
|
@ -33,9 +34,11 @@
|
|||
#include "NFS.h"
|
||||
#include "Portmap.h"
|
||||
#include "POP3.h"
|
||||
#include "SOCKS.h"
|
||||
#include "SSH.h"
|
||||
#include "SSL-binpac.h"
|
||||
#include "SSL.h"
|
||||
#include "Syslog-binpac.h"
|
||||
#include "Teredo.h"
|
||||
#include "ConnSizeAnalyzer.h"
|
||||
|
||||
// Keep same order here as in AnalyzerTag definition!
|
||||
|
@ -49,18 +52,6 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
|
|||
|
||||
{ AnalyzerTag::ICMP, "ICMP", ICMP_Analyzer::InstantiateAnalyzer,
|
||||
ICMP_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::ICMP_TimeExceeded, "ICMP_TIMEEXCEEDED",
|
||||
ICMP_TimeExceeded_Analyzer::InstantiateAnalyzer,
|
||||
ICMP_TimeExceeded_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::ICMP_Unreachable, "ICMP_UNREACHABLE",
|
||||
ICMP_Unreachable_Analyzer::InstantiateAnalyzer,
|
||||
ICMP_Unreachable_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::ICMP_Echo, "ICMP_ECHO",
|
||||
ICMP_Echo_Analyzer::InstantiateAnalyzer,
|
||||
ICMP_Echo_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::ICMP_Redir, "ICMP_REDIR",
|
||||
ICMP_Redir_Analyzer::InstantiateAnalyzer,
|
||||
ICMP_Redir_Analyzer::Available, 0, false },
|
||||
|
||||
{ AnalyzerTag::TCP, "TCP", TCP_Analyzer::InstantiateAnalyzer,
|
||||
TCP_Analyzer::Available, 0, false },
|
||||
|
@ -133,12 +124,22 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
|
|||
HTTP_Analyzer_binpac::InstantiateAnalyzer,
|
||||
HTTP_Analyzer_binpac::Available, 0, false },
|
||||
{ AnalyzerTag::SSL, "SSL",
|
||||
SSL_Analyzer_binpac::InstantiateAnalyzer,
|
||||
SSL_Analyzer_binpac::Available, 0, false },
|
||||
SSL_Analyzer::InstantiateAnalyzer,
|
||||
SSL_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::SYSLOG_BINPAC, "SYSLOG_BINPAC",
|
||||
Syslog_Analyzer_binpac::InstantiateAnalyzer,
|
||||
Syslog_Analyzer_binpac::Available, 0, false },
|
||||
|
||||
{ AnalyzerTag::AYIYA, "AYIYA",
|
||||
AYIYA_Analyzer::InstantiateAnalyzer,
|
||||
AYIYA_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::SOCKS, "SOCKS",
|
||||
SOCKS_Analyzer::InstantiateAnalyzer,
|
||||
SOCKS_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::Teredo, "TEREDO",
|
||||
Teredo_Analyzer::InstantiateAnalyzer,
|
||||
Teredo_Analyzer::Available, 0, false },
|
||||
|
||||
{ AnalyzerTag::File, "FILE", File_Analyzer::InstantiateAnalyzer,
|
||||
File_Analyzer::Available, 0, false },
|
||||
{ AnalyzerTag::Backdoor, "BACKDOOR",
|
||||
|
@ -170,6 +171,7 @@ const Analyzer::Config Analyzer::analyzer_configs[] = {
|
|||
{ AnalyzerTag::Contents_SMB, "CONTENTS_SMB", 0, 0, 0, false },
|
||||
{ AnalyzerTag::Contents_RPC, "CONTENTS_RPC", 0, 0, 0, false },
|
||||
{ AnalyzerTag::Contents_NFS, "CONTENTS_NFS", 0, 0, 0, false },
|
||||
{ AnalyzerTag::FTP_ADAT, "FTP_ADAT", 0, 0, 0, false },
|
||||
};
|
||||
|
||||
AnalyzerTimer::~AnalyzerTimer()
|
||||
|
|
|
@ -215,6 +215,11 @@ public:
|
|||
// analyzer, even if the method is called multiple times.
|
||||
virtual void ProtocolConfirmation();
|
||||
|
||||
// Return whether the analyzer previously called ProtocolConfirmation()
|
||||
// at least once before.
|
||||
bool ProtocolConfirmed() const
|
||||
{ return protocol_confirmed; }
|
||||
|
||||
// Report that we found a significant protocol violation which might
|
||||
// indicate that the analyzed data is in fact not the expected
|
||||
// protocol. The protocol_violation event is raised once per call to
|
||||
|
@ -338,6 +343,10 @@ private:
|
|||
for ( analyzer_list::iterator var = the_kids.begin(); \
|
||||
var != the_kids.end(); var++ )
|
||||
|
||||
#define LOOP_OVER_GIVEN_CONST_CHILDREN(var, the_kids) \
|
||||
for ( analyzer_list::const_iterator var = the_kids.begin(); \
|
||||
var != the_kids.end(); var++ )
|
||||
|
||||
class SupportAnalyzer : public Analyzer {
|
||||
public:
|
||||
SupportAnalyzer(AnalyzerTag::Tag tag, Connection* conn, bool arg_orig)
|
||||
|
|
|
@ -20,9 +20,7 @@ namespace AnalyzerTag {
|
|||
PIA_TCP, PIA_UDP,
|
||||
|
||||
// Transport-layer analyzers.
|
||||
ICMP,
|
||||
ICMP_TimeExceeded, ICMP_Unreachable, ICMP_Echo, ICMP_Redir,
|
||||
TCP, UDP,
|
||||
ICMP, TCP, UDP,
|
||||
|
||||
// Application-layer analyzers (hand-written).
|
||||
BitTorrent, BitTorrentTracker,
|
||||
|
@ -35,15 +33,20 @@ namespace AnalyzerTag {
|
|||
DHCP_BINPAC, DNS_TCP_BINPAC, DNS_UDP_BINPAC,
|
||||
HTTP_BINPAC, SSL, SYSLOG_BINPAC,
|
||||
|
||||
// Decapsulation analyzers.
|
||||
AYIYA,
|
||||
SOCKS,
|
||||
Teredo,
|
||||
|
||||
// Other
|
||||
File, Backdoor, InterConn, SteppingStone, TCPStats,
|
||||
ConnSize,
|
||||
|
||||
|
||||
// Support-analyzers
|
||||
Contents, ContentLine, NVT, Zip, Contents_DNS, Contents_NCP,
|
||||
Contents_NetbiosSSN, Contents_Rlogin, Contents_Rsh,
|
||||
Contents_DCE_RPC, Contents_SMB, Contents_RPC, Contents_NFS,
|
||||
FTP_ADAT,
|
||||
// End-marker.
|
||||
LastAnalyzer
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "util.h"
|
||||
#include "net_util.h"
|
||||
#include "md5.h"
|
||||
#include "Anon.h"
|
||||
#include "Val.h"
|
||||
#include "NetVar.h"
|
||||
|
@ -153,7 +152,9 @@ void AnonymizeIPAddr_A50::init()
|
|||
|
||||
int AnonymizeIPAddr_A50::PreservePrefix(ipaddr32_t input, int num_bits)
|
||||
{
|
||||
DEBUG_MSG("%s/%d\n", dotted_addr(input), num_bits);
|
||||
DEBUG_MSG("%s/%d\n",
|
||||
IPAddr(IPv4, &input, IPAddr::Network).AsString().c_str(),
|
||||
num_bits);
|
||||
|
||||
if ( ! before_anonymization )
|
||||
{
|
||||
|
|
50
src/Attr.cc
50
src/Attr.cc
|
@ -5,7 +5,7 @@
|
|||
#include "Attr.h"
|
||||
#include "Expr.h"
|
||||
#include "Serializer.h"
|
||||
#include "LogMgr.h"
|
||||
#include "threading/SerialTypes.h"
|
||||
|
||||
const char* attr_name(attr_tag t)
|
||||
{
|
||||
|
@ -15,9 +15,10 @@ const char* attr_name(attr_tag t)
|
|||
"&add_func", "&delete_func", "&expire_func",
|
||||
"&read_expire", "&write_expire", "&create_expire",
|
||||
"&persistent", "&synchronized", "&postprocessor",
|
||||
"&encrypt", "&match", "&disable_print_hook",
|
||||
"&encrypt", "&match",
|
||||
"&raw_output", "&mergeable", "&priority",
|
||||
"&group", "&log", "&error_handler", "(&tracked)",
|
||||
"&group", "&log", "&error_handler", "&type_column",
|
||||
"(&tracked)",
|
||||
};
|
||||
|
||||
return attr_names[int(t)];
|
||||
|
@ -60,16 +61,19 @@ void Attr::DescribeReST(ODesc* d) const
|
|||
d->Add("=");
|
||||
d->SP();
|
||||
|
||||
if ( expr->Type()->Tag() == TYPE_FUNC )
|
||||
d->Add(":bro:type:`func`");
|
||||
|
||||
else if ( expr->Type()->Tag() == TYPE_ENUM )
|
||||
if ( expr->Tag() == EXPR_NAME )
|
||||
{
|
||||
d->Add(":bro:enum:`");
|
||||
d->Add(":bro:see:`");
|
||||
expr->Describe(d);
|
||||
d->Add("`");
|
||||
}
|
||||
|
||||
else if ( expr->Type()->Tag() == TYPE_FUNC )
|
||||
{
|
||||
d->Add(":bro:type:`func`");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
d->Add("``");
|
||||
|
@ -381,11 +385,6 @@ void Attributes::CheckAttr(Attr* a)
|
|||
// FIXME: Check here for global ID?
|
||||
break;
|
||||
|
||||
case ATTR_DISABLE_PRINT_HOOK:
|
||||
if ( type->Tag() != TYPE_FILE )
|
||||
Error("&disable_print_hook only applicable to files");
|
||||
break;
|
||||
|
||||
case ATTR_RAW_OUTPUT:
|
||||
if ( type->Tag() != TYPE_FILE )
|
||||
Error("&raw_output only applicable to files");
|
||||
|
@ -413,10 +412,29 @@ void Attributes::CheckAttr(Attr* a)
|
|||
break;
|
||||
|
||||
case ATTR_LOG:
|
||||
if ( ! LogVal::IsCompatibleType(type) )
|
||||
if ( ! threading::Value::IsCompatibleType(type) )
|
||||
Error("&log applied to a type that cannot be logged");
|
||||
break;
|
||||
|
||||
case ATTR_TYPE_COLUMN:
|
||||
{
|
||||
if ( type->Tag() != TYPE_PORT )
|
||||
{
|
||||
Error("type_column tag only applicable to ports");
|
||||
break;
|
||||
}
|
||||
|
||||
BroType* atype = a->AttrExpr()->Type();
|
||||
|
||||
if ( atype->Tag() != TYPE_STRING ) {
|
||||
Error("type column needs to have a string argument");
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
BadTag("Attributes::CheckAttr", attr_name(a->Tag()));
|
||||
}
|
||||
|
@ -481,7 +499,11 @@ bool Attributes::DoSerialize(SerialInfo* info) const
|
|||
loop_over_list((*attrs), i)
|
||||
{
|
||||
Attr* a = (*attrs)[i];
|
||||
SERIALIZE_OPTIONAL(a->AttrExpr())
|
||||
|
||||
// Broccoli doesn't support expressions.
|
||||
Expr* e = (! info->broccoli_peer) ? a->AttrExpr() : 0;
|
||||
SERIALIZE_OPTIONAL(e);
|
||||
|
||||
if ( ! SERIALIZE(char(a->Tag())) )
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -28,13 +28,13 @@ typedef enum {
|
|||
ATTR_POSTPROCESSOR,
|
||||
ATTR_ENCRYPT,
|
||||
ATTR_MATCH,
|
||||
ATTR_DISABLE_PRINT_HOOK,
|
||||
ATTR_RAW_OUTPUT,
|
||||
ATTR_MERGEABLE,
|
||||
ATTR_PRIORITY,
|
||||
ATTR_GROUP,
|
||||
ATTR_LOG,
|
||||
ATTR_ERROR_HANDLER,
|
||||
ATTR_TYPE_COLUMN, // for input framework
|
||||
ATTR_TRACKED, // hidden attribute, tracked by NotifierRegistry
|
||||
#define NUM_ATTRS (int(ATTR_TRACKED) + 1)
|
||||
} attr_tag;
|
||||
|
|
|
@ -1,14 +1,27 @@
|
|||
#include "config.h"
|
||||
#include "Base64.h"
|
||||
|
||||
static int base64_table[256];
|
||||
int Base64Decoder::default_base64_table[256];
|
||||
const string Base64Decoder::default_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static void init_base64_table()
|
||||
int* Base64Decoder::InitBase64Table(const string& alphabet)
|
||||
{
|
||||
static int table_initialized = 0;
|
||||
assert(alphabet.size() == 64);
|
||||
|
||||
if ( ++table_initialized > 1 )
|
||||
return;
|
||||
static bool default_table_initialized = false;
|
||||
|
||||
if ( alphabet == default_alphabet && default_table_initialized )
|
||||
return default_base64_table;
|
||||
|
||||
int* base64_table = 0;
|
||||
|
||||
if ( alphabet == default_alphabet )
|
||||
{
|
||||
base64_table = default_base64_table;
|
||||
default_table_initialized = true;
|
||||
}
|
||||
else
|
||||
base64_table = new int[256];
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < 256; ++i )
|
||||
|
@ -16,28 +29,36 @@ static void init_base64_table()
|
|||
|
||||
for ( i = 0; i < 26; ++i )
|
||||
{
|
||||
base64_table['A' + i] = i;
|
||||
base64_table['a' + i] = i + 26;
|
||||
base64_table[int(alphabet[0 + i])] = i;
|
||||
base64_table[int(alphabet[26 + i])] = i + 26;
|
||||
}
|
||||
|
||||
for ( i = 0; i < 10; ++i )
|
||||
base64_table['0' + i] = i + 52;
|
||||
base64_table[int(alphabet[52 + i])] = i + 52;
|
||||
|
||||
// Casts to avoid compiler warnings.
|
||||
base64_table[int('+')] = 62;
|
||||
base64_table[int('/')] = 63;
|
||||
base64_table[int(alphabet[62])] = 62;
|
||||
base64_table[int(alphabet[63])] = 63;
|
||||
base64_table[int('=')] = 0;
|
||||
|
||||
return base64_table;
|
||||
}
|
||||
|
||||
Base64Decoder::Base64Decoder(Analyzer* arg_analyzer)
|
||||
Base64Decoder::Base64Decoder(Analyzer* arg_analyzer, const string& alphabet)
|
||||
{
|
||||
init_base64_table();
|
||||
base64_table = InitBase64Table(alphabet.size() ? alphabet : default_alphabet);
|
||||
base64_group_next = 0;
|
||||
base64_padding = base64_after_padding = 0;
|
||||
errored = 0;
|
||||
analyzer = arg_analyzer;
|
||||
}
|
||||
|
||||
Base64Decoder::~Base64Decoder()
|
||||
{
|
||||
if ( base64_table != default_base64_table )
|
||||
delete base64_table;
|
||||
}
|
||||
|
||||
int Base64Decoder::Decode(int len, const char* data, int* pblen, char** pbuf)
|
||||
{
|
||||
int blen;
|
||||
|
@ -142,13 +163,21 @@ int Base64Decoder::Done(int* pblen, char** pbuf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
BroString* decode_base64(const BroString* s)
|
||||
|
||||
BroString* decode_base64(const BroString* s, const BroString* a)
|
||||
{
|
||||
if ( a && a->Len() != 64 )
|
||||
{
|
||||
reporter->Error("base64 decoding alphabet is not 64 characters: %s",
|
||||
a->CheckString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buf_len = int((s->Len() + 3) / 4) * 3 + 1;
|
||||
int rlen2, rlen = buf_len;
|
||||
char* rbuf2, *rbuf = new char[rlen];
|
||||
|
||||
Base64Decoder dec(0);
|
||||
Base64Decoder dec(0, a ? a->CheckString() : "");
|
||||
if ( dec.Decode(s->Len(), (const char*) s->Bytes(), &rlen, &rbuf) == -1 )
|
||||
goto err;
|
||||
|
||||
|
|
17
src/Base64.h
17
src/Base64.h
|
@ -13,11 +13,11 @@
|
|||
|
||||
class Base64Decoder {
|
||||
public:
|
||||
// <analyzer> is used for error reporting, and it should be zero
|
||||
// when the decoder is called by the built-in function
|
||||
// decode_base64().
|
||||
Base64Decoder(Analyzer* analyzer);
|
||||
~Base64Decoder() { }
|
||||
// <analyzer> is used for error reporting, and it should be zero when
|
||||
// the decoder is called by the built-in function decode_base64().
|
||||
// Empty alphabet indicates the default base64 alphabet.
|
||||
Base64Decoder(Analyzer* analyzer, const string& alphabet = "");
|
||||
~Base64Decoder();
|
||||
|
||||
// A note on Decode():
|
||||
//
|
||||
|
@ -57,8 +57,13 @@ protected:
|
|||
int base64_after_padding;
|
||||
int errored; // if true, we encountered an error - skip further processing
|
||||
Analyzer* analyzer;
|
||||
int* base64_table;
|
||||
|
||||
static int* InitBase64Table(const string& alphabet);
|
||||
static int default_base64_table[256];
|
||||
static const string default_alphabet;
|
||||
};
|
||||
|
||||
BroString* decode_base64(const BroString* s);
|
||||
BroString* decode_base64(const BroString* s, const BroString* a = 0);
|
||||
|
||||
#endif /* base64_h */
|
||||
|
|
|
@ -66,45 +66,50 @@ void BitTorrent_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
|||
|
||||
void BitTorrent_Analyzer::Undelivered(int seq, int len, bool orig)
|
||||
{
|
||||
uint64 entry_offset = orig ?
|
||||
*interp->upflow()->next_message_offset() :
|
||||
*interp->downflow()->next_message_offset();
|
||||
uint64& this_stream_len = orig ? stream_len_orig : stream_len_resp;
|
||||
bool& this_stop = orig ? stop_orig : stop_resp;
|
||||
|
||||
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
|
||||
|
||||
this_stream_len += len;
|
||||
// TODO: Code commented out for now. I think that shoving data that
|
||||
// is definitely wrong into the parser seems like a really bad idea.
|
||||
// The way it's currently tracking the next message offset isn't
|
||||
// compatible with new 64bit int support in binpac either.
|
||||
|
||||
if ( entry_offset < this_stream_len )
|
||||
{ // entry point is somewhere in the gap
|
||||
DeliverWeird("Stopping BitTorrent analysis: cannot recover from content gap", orig);
|
||||
this_stop = true;
|
||||
if ( stop_orig && stop_resp )
|
||||
ProtocolViolation("BitTorrent: content gap and/or protocol violation");
|
||||
}
|
||||
else
|
||||
{ // fill the gap
|
||||
try
|
||||
{
|
||||
u_char gap[len];
|
||||
memset(gap, 0, len);
|
||||
interp->NewData(orig, gap, gap + len);
|
||||
}
|
||||
catch ( binpac::Exception const &e )
|
||||
{
|
||||
DeliverWeird("Stopping BitTorrent analysis: filling content gap failed", orig);
|
||||
this_stop = true;
|
||||
if ( stop_orig && stop_resp )
|
||||
ProtocolViolation("BitTorrent: content gap and/or protocol violation");
|
||||
}
|
||||
}
|
||||
//uint64 entry_offset = orig ?
|
||||
// *interp->upflow()->next_message_offset() :
|
||||
// *interp->downflow()->next_message_offset();
|
||||
//uint64& this_stream_len = orig ? stream_len_orig : stream_len_resp;
|
||||
//bool& this_stop = orig ? stop_orig : stop_resp;
|
||||
//
|
||||
//this_stream_len += len;
|
||||
//
|
||||
//if ( entry_offset < this_stream_len )
|
||||
// { // entry point is somewhere in the gap
|
||||
// DeliverWeird("Stopping BitTorrent analysis: cannot recover from content gap", orig);
|
||||
// this_stop = true;
|
||||
// if ( stop_orig && stop_resp )
|
||||
// ProtocolViolation("BitTorrent: content gap and/or protocol violation");
|
||||
// }
|
||||
//else
|
||||
// { // fill the gap
|
||||
// try
|
||||
// {
|
||||
// u_char gap[len];
|
||||
// memset(gap, 0, len);
|
||||
// interp->NewData(orig, gap, gap + len);
|
||||
// }
|
||||
// catch ( binpac::Exception const &e )
|
||||
// {
|
||||
// DeliverWeird("Stopping BitTorrent analysis: filling content gap failed", orig);
|
||||
// this_stop = true;
|
||||
// if ( stop_orig && stop_resp )
|
||||
// ProtocolViolation("BitTorrent: content gap and/or protocol violation");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void BitTorrent_Analyzer::EndpointEOF(TCP_Reassembler* endp)
|
||||
void BitTorrent_Analyzer::EndpointEOF(bool is_orig)
|
||||
{
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(endp);
|
||||
interp->FlowEOF(endp->IsOrig());
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
void BitTorrent_Analyzer::DeliverWeird(const char* msg, bool orig)
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual void EndpointEOF(TCP_Reassembler* endp);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new BitTorrent_Analyzer(conn); }
|
||||
|
|
|
@ -215,9 +215,9 @@ void BitTorrentTracker_Analyzer::Undelivered(int seq, int len, bool orig)
|
|||
stop_resp = true;
|
||||
}
|
||||
|
||||
void BitTorrentTracker_Analyzer::EndpointEOF(TCP_Reassembler* endp)
|
||||
void BitTorrentTracker_Analyzer::EndpointEOF(bool is_orig)
|
||||
{
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(endp);
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
}
|
||||
|
||||
void BitTorrentTracker_Analyzer::InitBencParser(void)
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual void EndpointEOF(TCP_Reassembler* endp);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new BitTorrentTracker_Analyzer(conn); }
|
||||
|
|
|
@ -85,12 +85,13 @@ void BroDoc::AddImport(const std::string& s)
|
|||
if ( ext_pos != std::string::npos )
|
||||
lname = lname.substr(0, ext_pos);
|
||||
|
||||
const char* full_filename = "<error>";
|
||||
const char* subpath = "<error>";
|
||||
const char* full_filename = NULL;
|
||||
const char* subpath = NULL;
|
||||
|
||||
FILE* f = search_for_file(lname.c_str(), "bro", &full_filename, true,
|
||||
&subpath);
|
||||
|
||||
if ( f )
|
||||
if ( f && full_filename && subpath )
|
||||
{
|
||||
fclose(f);
|
||||
|
||||
|
@ -126,12 +127,14 @@ void BroDoc::AddImport(const std::string& s)
|
|||
}
|
||||
|
||||
delete [] tmp;
|
||||
delete [] full_filename;
|
||||
delete [] subpath;
|
||||
}
|
||||
|
||||
else
|
||||
fprintf(stderr, "Failed to document '@load %s' in file: %s\n",
|
||||
s.c_str(), reST_filename.c_str());
|
||||
|
||||
delete [] full_filename;
|
||||
delete [] subpath;
|
||||
}
|
||||
|
||||
void BroDoc::SetPacketFilter(const std::string& s)
|
||||
|
@ -170,13 +173,26 @@ void BroDoc::WriteDocFile() const
|
|||
{
|
||||
WriteToDoc(".. Automatically generated. Do not edit.\n\n");
|
||||
|
||||
WriteToDoc(":tocdepth: 3\n\n");
|
||||
|
||||
WriteSectionHeading(doc_title.c_str(), '=');
|
||||
|
||||
WriteToDoc("\n:download:`Original Source File <%s>`\n\n",
|
||||
downloadable_filename.c_str());
|
||||
WriteStringList(".. bro:namespace:: %s\n", modules);
|
||||
|
||||
WriteSectionHeading("Overview", '-');
|
||||
WriteStringList("%s\n", "%s\n\n", summary);
|
||||
WriteToDoc("\n");
|
||||
|
||||
// WriteSectionHeading("Overview", '-');
|
||||
WriteStringList("%s\n", summary);
|
||||
|
||||
WriteToDoc("\n");
|
||||
|
||||
if ( ! modules.empty() )
|
||||
{
|
||||
WriteToDoc(":Namespace%s: ", (modules.size() > 1 ? "s" : ""));
|
||||
// WriteStringList(":bro:namespace:`%s`", modules);
|
||||
WriteStringList("``%s``, ", "``%s``", modules);
|
||||
WriteToDoc("\n");
|
||||
}
|
||||
|
||||
if ( ! imports.empty() )
|
||||
{
|
||||
|
@ -196,37 +212,38 @@ void BroDoc::WriteDocFile() const
|
|||
WriteToDoc("\n");
|
||||
}
|
||||
|
||||
WriteToDoc(":Source File: :download:`%s`\n",
|
||||
downloadable_filename.c_str());
|
||||
|
||||
WriteToDoc("\n");
|
||||
|
||||
WriteInterface("Summary", '~', '#', true, true);
|
||||
|
||||
if ( ! modules.empty() )
|
||||
{
|
||||
WriteSectionHeading("Namespaces", '~');
|
||||
WriteStringList(".. bro:namespace:: %s\n", modules);
|
||||
WriteToDoc("\n");
|
||||
}
|
||||
|
||||
if ( ! notices.empty() )
|
||||
WriteBroDocObjList(notices, "Notices", '~');
|
||||
WriteBroDocObjList(notices, "Notices", '#');
|
||||
|
||||
WriteInterface("Public Interface", '-', '~', true, false);
|
||||
if ( port_analysis.size() || packet_filter.size() )
|
||||
WriteSectionHeading("Configuration Changes", '#');
|
||||
|
||||
if ( ! port_analysis.empty() )
|
||||
{
|
||||
WriteSectionHeading("Port Analysis", '-');
|
||||
WriteToDoc(":ref:`More Information <common_port_analysis_doc>`\n\n");
|
||||
WriteStringList("%s", port_analysis);
|
||||
WriteSectionHeading("Port Analysis", '^');
|
||||
WriteToDoc("Loading this script makes the following changes to "
|
||||
":bro:see:`dpd_config`.\n\n");
|
||||
WriteStringList("%s, ", "%s", port_analysis);
|
||||
}
|
||||
|
||||
if ( ! packet_filter.empty() )
|
||||
{
|
||||
WriteSectionHeading("Packet Filter", '-');
|
||||
WriteToDoc(":ref:`More Information <common_packet_filter_doc>`\n\n");
|
||||
WriteSectionHeading("Packet Filter", '^');
|
||||
WriteToDoc("Loading this script makes the following changes to "
|
||||
":bro:see:`capture_filters`.\n\n");
|
||||
WriteToDoc("Filters added::\n\n");
|
||||
WriteToDoc("%s\n", packet_filter.c_str());
|
||||
}
|
||||
|
||||
WriteInterface("Detailed Interface", '~', '#', true, false);
|
||||
|
||||
#if 0 // Disabled for now.
|
||||
BroDocObjList::const_iterator it;
|
||||
bool hasPrivateIdentifiers = false;
|
||||
|
@ -241,7 +258,7 @@ void BroDoc::WriteDocFile() const
|
|||
}
|
||||
|
||||
if ( hasPrivateIdentifiers )
|
||||
WriteInterface("Private Interface", '-', '~', false, false);
|
||||
WriteInterface("Private Interface", '~', '#', false, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,12 @@
|
|||
#include "ID.h"
|
||||
#include "BroDocObj.h"
|
||||
|
||||
BroDocObj* BroDocObj::last = 0;
|
||||
|
||||
BroDocObj::BroDocObj(const ID* id, std::list<std::string>*& reST,
|
||||
bool is_fake)
|
||||
{
|
||||
last = this;
|
||||
broID = id;
|
||||
reST_doc_strings = reST;
|
||||
reST = 0;
|
||||
|
|
|
@ -103,6 +103,20 @@ public:
|
|||
*/
|
||||
int LongestShortDescLen() const;
|
||||
|
||||
/**
|
||||
* Adds a reST documentation string to this BroDocObj's list.
|
||||
* @param s the documentation string to append.
|
||||
*/
|
||||
void AddDocString(const std::string& s)
|
||||
{
|
||||
if ( ! reST_doc_strings )
|
||||
reST_doc_strings = new std::list<std::string>();
|
||||
reST_doc_strings->push_back(s);
|
||||
FormulateShortDesc();
|
||||
}
|
||||
|
||||
static BroDocObj* last;
|
||||
|
||||
protected:
|
||||
std::list<std::string>* reST_doc_strings;
|
||||
std::list<std::string> short_desc;
|
||||
|
|
102
src/Brofiler.cc
Normal file
102
src/Brofiler.cc
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include "Brofiler.h"
|
||||
#include "util.h"
|
||||
|
||||
Brofiler::Brofiler()
|
||||
: ignoring(0), delim('\t')
|
||||
{
|
||||
}
|
||||
|
||||
Brofiler::~Brofiler()
|
||||
{
|
||||
}
|
||||
|
||||
bool Brofiler::ReadStats()
|
||||
{
|
||||
char* bf = getenv("BRO_PROFILER_FILE");
|
||||
if ( ! bf )
|
||||
return false;
|
||||
|
||||
FILE* f = fopen(bf, "r");
|
||||
if ( ! f )
|
||||
return false;
|
||||
|
||||
char line[16384];
|
||||
string delimiter;
|
||||
delimiter = delim;
|
||||
|
||||
while( fgets(line, sizeof(line), f) )
|
||||
{
|
||||
line[strlen(line) - 1] = 0; //remove newline
|
||||
string cnt(strtok(line, delimiter.c_str()));
|
||||
string location(strtok(0, delimiter.c_str()));
|
||||
string desc(strtok(0, delimiter.c_str()));
|
||||
pair<string, string> location_desc(location, desc);
|
||||
uint64 count;
|
||||
atoi_n(cnt.size(), cnt.c_str(), 0, 10, count);
|
||||
usage_map[location_desc] = count;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Brofiler::WriteStats()
|
||||
{
|
||||
char* bf = getenv("BRO_PROFILER_FILE");
|
||||
if ( ! bf ) return false;
|
||||
|
||||
FILE* f;
|
||||
const char* p = strstr(bf, ".XXXXXX");
|
||||
|
||||
if ( p && ! p[7] )
|
||||
{
|
||||
int fd = mkstemp(bf);
|
||||
if ( fd == -1 )
|
||||
{
|
||||
reporter->Error("Failed to generate unique file name from BRO_PROFILER_FILE: %s", bf);
|
||||
return false;
|
||||
}
|
||||
f = fdopen(fd, "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
f = fopen(bf, "w");
|
||||
}
|
||||
|
||||
if ( ! f )
|
||||
{
|
||||
reporter->Error("Failed to open BRO_PROFILER_FILE destination '%s' for writing", bf);
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( list<const Stmt*>::const_iterator it = stmts.begin();
|
||||
it != stmts.end(); ++it )
|
||||
{
|
||||
ODesc location_info;
|
||||
(*it)->GetLocationInfo()->Describe(&location_info);
|
||||
ODesc desc_info;
|
||||
(*it)->Describe(&desc_info);
|
||||
string desc(desc_info.Description());
|
||||
for_each(desc.begin(), desc.end(), canonicalize_desc());
|
||||
pair<string, string> location_desc(location_info.Description(), desc);
|
||||
if ( usage_map.find(location_desc) != usage_map.end() )
|
||||
usage_map[location_desc] += (*it)->GetAccessCount();
|
||||
else
|
||||
usage_map[location_desc] = (*it)->GetAccessCount();
|
||||
}
|
||||
|
||||
map<pair<string, string>, uint64 >::const_iterator it;
|
||||
for ( it = usage_map.begin(); it != usage_map.end(); ++it )
|
||||
{
|
||||
fprintf(f, "%"PRIu64"%c%s%c%s\n", it->second, delim,
|
||||
it->first.first.c_str(), delim, it->first.second.c_str());
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
81
src/Brofiler.h
Normal file
81
src/Brofiler.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
#ifndef BROFILER_H_
|
||||
#define BROFILER_H_
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <list>
|
||||
#include <Stmt.h>
|
||||
|
||||
|
||||
/**
|
||||
* A simple class for managing stats of Bro script coverage across Bro runs.
|
||||
*/
|
||||
class Brofiler {
|
||||
public:
|
||||
Brofiler();
|
||||
virtual ~Brofiler();
|
||||
|
||||
/**
|
||||
* Imports Bro script Stmt usage information from file pointed to by
|
||||
* environment variable BRO_PROFILER_FILE.
|
||||
*
|
||||
* @return: true if usage info was read, otherwise false.
|
||||
*/
|
||||
bool ReadStats();
|
||||
|
||||
/**
|
||||
* Combines usage stats from current run with any read from ReadStats(),
|
||||
* then writes information to file pointed to by environment variable
|
||||
* BRO_PROFILER_FILE. If the value of that env. variable ends with
|
||||
* ".XXXXXX" (exactly 6 X's), then it is first passed through mkstemp
|
||||
* to get a unique file.
|
||||
*
|
||||
* @return: true when usage info is written, otherwise false.
|
||||
*/
|
||||
bool WriteStats();
|
||||
|
||||
void SetDelim(char d) { delim = d; }
|
||||
|
||||
void IncIgnoreDepth() { ignoring++; }
|
||||
void DecIgnoreDepth() { ignoring--; }
|
||||
|
||||
void AddStmt(const Stmt* s) { if ( ignoring == 0 ) stmts.push_back(s); }
|
||||
|
||||
private:
|
||||
/**
|
||||
* The current, global Brofiler instance creates this list at parse-time.
|
||||
*/
|
||||
list<const Stmt*> stmts;
|
||||
|
||||
/**
|
||||
* Indicates whether new statments will not be considered as part of
|
||||
* coverage statistics because it was marked with the @no-test tag.
|
||||
*/
|
||||
unsigned int ignoring;
|
||||
|
||||
/**
|
||||
* This maps Stmt location-desc pairs to the total number of times that
|
||||
* Stmt has been executed. The map can be initialized from a file at
|
||||
* startup time and modified at shutdown time before writing back
|
||||
* to a file.
|
||||
*/
|
||||
map<pair<string, string>, uint64> usage_map;
|
||||
|
||||
/**
|
||||
* The character to use to delimit Brofiler output files. Default is '\t'.
|
||||
*/
|
||||
char delim;
|
||||
|
||||
/**
|
||||
* A canonicalization routine for Stmt descriptions containing characters
|
||||
* that don't agree with the output format of Brofiler.
|
||||
*/
|
||||
struct canonicalize_desc {
|
||||
void operator() (char& c)
|
||||
{
|
||||
if ( c == '\n' ) c = ' ';
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* BROFILER_H_ */
|
|
@ -1,8 +1,10 @@
|
|||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
|
||||
include_directories(BEFORE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
configure_file(version.c.in ${CMAKE_CURRENT_BINARY_DIR}/version.c)
|
||||
configure_file(util-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/util-config.h)
|
||||
|
||||
# This creates a custom command to transform a bison output file (inFile)
|
||||
# into outFile in order to avoid symbol conflicts:
|
||||
|
@ -141,6 +143,7 @@ endmacro(GET_BIF_OUTPUT_FILES)
|
|||
set(BIF_SRCS
|
||||
bro.bif
|
||||
logging.bif
|
||||
input.bif
|
||||
event.bif
|
||||
const.bif
|
||||
types.bif
|
||||
|
@ -185,6 +188,9 @@ endmacro(BINPAC_TARGET)
|
|||
|
||||
binpac_target(binpac-lib.pac)
|
||||
binpac_target(binpac_bro-lib.pac)
|
||||
|
||||
binpac_target(ayiya.pac
|
||||
ayiya-protocol.pac ayiya-analyzer.pac)
|
||||
binpac_target(bittorrent.pac
|
||||
bittorrent-protocol.pac bittorrent-analyzer.pac)
|
||||
binpac_target(dce_rpc.pac
|
||||
|
@ -204,6 +210,8 @@ binpac_target(netflow.pac
|
|||
netflow-protocol.pac netflow-analyzer.pac)
|
||||
binpac_target(smb.pac
|
||||
smb-protocol.pac smb-pipe.pac smb-mailslot.pac)
|
||||
binpac_target(socks.pac
|
||||
socks-protocol.pac socks-analyzer.pac)
|
||||
binpac_target(ssl.pac
|
||||
ssl-defs.pac ssl-protocol.pac ssl-analyzer.pac)
|
||||
binpac_target(syslog.pac
|
||||
|
@ -212,6 +220,8 @@ binpac_target(syslog.pac
|
|||
########################################################################
|
||||
## bro target
|
||||
|
||||
find_package (Threads)
|
||||
|
||||
# This macro stores associated headers for any C/C++ source files given
|
||||
# as arguments (past _var) as a list in the CMake variable named "_var".
|
||||
macro(COLLECT_HEADERS _var)
|
||||
|
@ -244,7 +254,6 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/DebugCmdConstants.h
|
|||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
set(dns_SRCS nb_dns.c)
|
||||
set_source_files_properties(nb_dns.c PROPERTIES COMPILE_FLAGS
|
||||
-fno-strict-aliasing)
|
||||
|
||||
|
@ -274,6 +283,7 @@ set(bro_SRCS
|
|||
Anon.cc
|
||||
ARP.cc
|
||||
Attr.cc
|
||||
AYIYA.cc
|
||||
BackDoor.cc
|
||||
Base64.cc
|
||||
BitTorrent.cc
|
||||
|
@ -281,12 +291,12 @@ set(bro_SRCS
|
|||
BPF_Program.cc
|
||||
BroDoc.cc
|
||||
BroDocObj.cc
|
||||
Brofiler.cc
|
||||
BroString.cc
|
||||
CCL.cc
|
||||
ChunkedIO.cc
|
||||
CompHash.cc
|
||||
Conn.cc
|
||||
ConnCompressor.cc
|
||||
ConnSizeAnalyzer.cc
|
||||
ContentLine.cc
|
||||
DCE_RPC.cc
|
||||
|
@ -329,13 +339,11 @@ set(bro_SRCS
|
|||
IntSet.cc
|
||||
InterConn.cc
|
||||
IOSource.cc
|
||||
IP.cc
|
||||
IPAddr.cc
|
||||
IRC.cc
|
||||
List.cc
|
||||
Reporter.cc
|
||||
LogMgr.cc
|
||||
LogWriter.cc
|
||||
LogWriterAscii.cc
|
||||
LogWriterNone.cc
|
||||
Login.cc
|
||||
MIME.cc
|
||||
NCP.cc
|
||||
|
@ -374,8 +382,9 @@ set(bro_SRCS
|
|||
SmithWaterman.cc
|
||||
SMB.cc
|
||||
SMTP.cc
|
||||
SOCKS.cc
|
||||
SSH.cc
|
||||
SSL-binpac.cc
|
||||
SSL.cc
|
||||
Scope.cc
|
||||
SerializationFormat.cc
|
||||
SerialObj.cc
|
||||
|
@ -390,9 +399,11 @@ set(bro_SRCS
|
|||
TCP_Endpoint.cc
|
||||
TCP_Reassembler.cc
|
||||
Telnet.cc
|
||||
Teredo.cc
|
||||
Timer.cc
|
||||
Traverse.cc
|
||||
Trigger.cc
|
||||
TunnelEncapsulation.cc
|
||||
Type.cc
|
||||
UDP.cc
|
||||
Val.cc
|
||||
|
@ -400,34 +411,43 @@ set(bro_SRCS
|
|||
XDR.cc
|
||||
ZIP.cc
|
||||
bsd-getopt-long.c
|
||||
bro_inet_ntop.c
|
||||
cq.c
|
||||
md5.c
|
||||
patricia.c
|
||||
setsignal.c
|
||||
PacketDumper.cc
|
||||
strsep.c
|
||||
modp_numtoa.c
|
||||
${dns_SRCS}
|
||||
${openssl_SRCS}
|
||||
|
||||
threading/BasicThread.cc
|
||||
threading/Manager.cc
|
||||
threading/MsgThread.cc
|
||||
threading/SerialTypes.cc
|
||||
|
||||
logging/Manager.cc
|
||||
logging/WriterBackend.cc
|
||||
logging/WriterFrontend.cc
|
||||
logging/writers/Ascii.cc
|
||||
logging/writers/DataSeries.cc
|
||||
logging/writers/ElasticSearch.cc
|
||||
logging/writers/None.cc
|
||||
|
||||
input/Manager.cc
|
||||
input/ReaderBackend.cc
|
||||
input/ReaderFrontend.cc
|
||||
input/readers/Ascii.cc
|
||||
input/readers/Raw.cc
|
||||
input/readers/Benchmark.cc
|
||||
|
||||
nb_dns.c
|
||||
digest.h
|
||||
)
|
||||
|
||||
collect_headers(bro_HEADERS ${bro_SRCS})
|
||||
|
||||
add_definitions(-DBRO_SCRIPT_INSTALL_PATH="${BRO_SCRIPT_INSTALL_PATH}")
|
||||
add_definitions(-DBRO_SCRIPT_SOURCE_PATH="${BRO_SCRIPT_SOURCE_PATH}")
|
||||
add_definitions(-DBRO_BUILD_PATH="${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
add_executable(bro ${bro_SRCS} ${bro_HEADERS})
|
||||
|
||||
set(brolibs
|
||||
${BinPAC_LIBRARY}
|
||||
${PCAP_LIBRARY}
|
||||
${OpenSSL_LIBRARIES}
|
||||
${BIND_LIBRARY}
|
||||
${OPTLIBS}
|
||||
)
|
||||
|
||||
target_link_libraries(bro ${brolibs})
|
||||
target_link_libraries(bro ${brodeps} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
install(TARGETS bro DESTINATION bin)
|
||||
install(FILES ${INSTALL_BIF_OUTPUTS} DESTINATION ${BRO_SCRIPT_INSTALL_PATH}/base)
|
||||
|
|
|
@ -76,7 +76,7 @@ void ChunkedIO::DumpDebugData(const char* basefnname, bool want_reads)
|
|||
ChunkedIOFd io(fd, "dump-file");
|
||||
io.Write(*i);
|
||||
io.Flush();
|
||||
close(fd);
|
||||
safe_close(fd);
|
||||
}
|
||||
|
||||
l->clear();
|
||||
|
@ -127,7 +127,7 @@ ChunkedIOFd::~ChunkedIOFd()
|
|||
|
||||
delete [] read_buffer;
|
||||
delete [] write_buffer;
|
||||
close(fd);
|
||||
safe_close(fd);
|
||||
|
||||
if ( partial )
|
||||
{
|
||||
|
@ -686,7 +686,7 @@ ChunkedIOSSL::~ChunkedIOSSL()
|
|||
ssl = 0;
|
||||
}
|
||||
|
||||
close(socket);
|
||||
safe_close(socket);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1170,8 +1170,6 @@ void ChunkedIOSSL::Stats(char* buffer, int length)
|
|||
ChunkedIO::Stats(buffer + i, length - i);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
|
||||
bool CompressedChunkedIO::Init()
|
||||
{
|
||||
zin.zalloc = 0;
|
||||
|
@ -1348,5 +1346,3 @@ void CompressedChunkedIO::Stats(char* buffer, int length)
|
|||
io->Stats(buffer + i, length - i);
|
||||
buffer[length-1] = '\0';
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBZ */
|
||||
|
|
|
@ -287,8 +287,6 @@ private:
|
|||
static SSL_CTX* ctx;
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
// Wrapper class around a another ChunkedIO which the (un-)compresses data.
|
||||
|
@ -335,6 +333,4 @@ protected:
|
|||
unsigned long uncompressed_bytes_written;
|
||||
};
|
||||
|
||||
#endif /* HAVE_LIBZ */
|
||||
|
||||
#endif
|
||||
|
|
321
src/CompHash.cc
321
src/CompHash.cc
|
@ -107,40 +107,18 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
|
|||
|
||||
case TYPE_INTERNAL_ADDR:
|
||||
{
|
||||
// Use uint32 instead of int, because 'int' is not
|
||||
// guaranteed to be 32-bit.
|
||||
uint32* kp = AlignAndPadType<uint32>(kp0);
|
||||
#ifdef BROv6
|
||||
const addr_type av = v->AsAddr();
|
||||
kp[0] = av[0];
|
||||
kp[1] = av[1];
|
||||
kp[2] = av[2];
|
||||
kp[3] = av[3];
|
||||
v->AsAddr().CopyIPv6(kp);
|
||||
kp1 = reinterpret_cast<char*>(kp+4);
|
||||
#else
|
||||
*kp = v->AsAddr();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_SUBNET:
|
||||
{
|
||||
uint32* kp = AlignAndPadType<uint32>(kp0);
|
||||
#ifdef BROv6
|
||||
const subnet_type* sv = v->AsSubNet();
|
||||
kp[0] = sv->net[0];
|
||||
kp[1] = sv->net[1];
|
||||
kp[2] = sv->net[2];
|
||||
kp[3] = sv->net[3];
|
||||
kp[4] = sv->width;
|
||||
v->AsSubNet().Prefix().CopyIPv6(kp);
|
||||
kp[4] = v->AsSubNet().Length();
|
||||
kp1 = reinterpret_cast<char*>(kp+5);
|
||||
#else
|
||||
const subnet_type* sv = v->AsSubNet();
|
||||
kp[0] = sv->net;
|
||||
kp[1] = sv->width;
|
||||
kp1 = reinterpret_cast<char*>(kp+2);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -155,14 +133,16 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
|
|||
case TYPE_INTERNAL_VOID:
|
||||
case TYPE_INTERNAL_OTHER:
|
||||
{
|
||||
if ( v->Type()->Tag() == TYPE_FUNC )
|
||||
switch ( v->Type()->Tag() ) {
|
||||
case TYPE_FUNC:
|
||||
{
|
||||
uint32* kp = AlignAndPadType<uint32>(kp0);
|
||||
*kp = v->AsFunc()->GetUniqueFuncID();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
break;
|
||||
}
|
||||
|
||||
else if ( v->Type()->Tag() == TYPE_RECORD )
|
||||
case TYPE_RECORD:
|
||||
{
|
||||
char* kp = kp0;
|
||||
RecordVal* rv = v->AsRecordVal();
|
||||
|
@ -186,14 +166,87 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0,
|
|||
}
|
||||
|
||||
kp1 = kp;
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
int* kp = AlignAndPadType<int>(kp0);
|
||||
TableVal* tv = v->AsTableVal();
|
||||
ListVal* lv = tv->ConvertToList();
|
||||
*kp = tv->Size();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
for ( int i = 0; i < tv->Size(); ++i )
|
||||
{
|
||||
Val* key = lv->Index(i);
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1, key->Type(), key,
|
||||
false)) )
|
||||
return 0;
|
||||
|
||||
if ( ! v->Type()->IsSet() )
|
||||
{
|
||||
Val* val = tv->Lookup(key);
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1, val->Type(),
|
||||
val, false)) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
unsigned int* kp = AlignAndPadType<unsigned int>(kp0);
|
||||
VectorVal* vv = v->AsVectorVal();
|
||||
VectorType* vt = v->Type()->AsVectorType();
|
||||
vector<Val*>* indices = v->AsVector();
|
||||
*kp = vv->Size();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
for ( unsigned int i = 0; i < vv->Size(); ++i )
|
||||
{
|
||||
Val* val = vv->Lookup(i);
|
||||
unsigned int* kp = AlignAndPadType<unsigned int>(kp1);
|
||||
*kp = i;
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
kp = AlignAndPadType<unsigned int>(kp1);
|
||||
*kp = val ? 1 : 0;
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
|
||||
if ( val )
|
||||
{
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1,
|
||||
vt->YieldType(), val, false)) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LIST:
|
||||
{
|
||||
int* kp = AlignAndPadType<int>(kp0);
|
||||
ListVal* lv = v->AsListVal();
|
||||
*kp = lv->Length();
|
||||
kp1 = reinterpret_cast<char*>(kp+1);
|
||||
for ( int i = 0; i < lv->Length(); ++i )
|
||||
{
|
||||
Val* v = lv->Index(i);
|
||||
if ( ! (kp1 = SingleValHash(type_check, kp1, v->Type(), v,
|
||||
false)) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
reporter->InternalError("bad index type in CompositeHash::SingleValHash");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
break; // case TYPE_INTERNAL_VOID/OTHER
|
||||
}
|
||||
|
||||
case TYPE_INTERNAL_STRING:
|
||||
{
|
||||
|
@ -283,26 +336,16 @@ HashKey* CompositeHash::ComputeSingletonHash(const Val* v, int type_check) const
|
|||
if ( type_check && v->Type()->InternalType() != singleton_tag )
|
||||
return 0;
|
||||
|
||||
uint32 tmp_addr;
|
||||
switch ( singleton_tag ) {
|
||||
case TYPE_INTERNAL_INT:
|
||||
case TYPE_INTERNAL_UNSIGNED:
|
||||
return new HashKey(v->ForceAsInt());
|
||||
|
||||
case TYPE_INTERNAL_ADDR:
|
||||
#ifdef BROv6
|
||||
return new HashKey(v->AsAddr(), 4);
|
||||
#else
|
||||
return new HashKey(v->AsAddr());
|
||||
#endif
|
||||
return v->AsAddr().GetHashKey();
|
||||
|
||||
case TYPE_INTERNAL_SUBNET:
|
||||
#ifdef BROv6
|
||||
return new HashKey((const uint32*) v->AsSubNet(), 5);
|
||||
#else
|
||||
return new HashKey((const uint32*) v->AsSubNet(), 2);
|
||||
|
||||
#endif
|
||||
return v->AsSubNet().GetHashKey();
|
||||
|
||||
case TYPE_INTERNAL_DOUBLE:
|
||||
return new HashKey(v->InternalDouble());
|
||||
|
@ -350,22 +393,13 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
|
|||
break;
|
||||
|
||||
case TYPE_INTERNAL_ADDR:
|
||||
#ifdef BROv6
|
||||
sz = SizeAlign(sz, sizeof(uint32));
|
||||
sz += sizeof(uint32) * 3; // to make a total of 4 words
|
||||
#else
|
||||
sz = SizeAlign(sz, sizeof(uint32));
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_SUBNET:
|
||||
#ifdef BROv6
|
||||
sz = SizeAlign(sz, sizeof(uint32));
|
||||
sz += sizeof(uint32) * 4; // to make a total of 5 words
|
||||
#else
|
||||
sz = SizeAlign(sz, sizeof(uint32));
|
||||
sz += sizeof(uint32); // make room for width
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_DOUBLE:
|
||||
|
@ -375,10 +409,14 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
|
|||
case TYPE_INTERNAL_VOID:
|
||||
case TYPE_INTERNAL_OTHER:
|
||||
{
|
||||
if ( bt->Tag() == TYPE_FUNC )
|
||||
switch ( bt->Tag() ) {
|
||||
case TYPE_FUNC:
|
||||
{
|
||||
sz = SizeAlign(sz, sizeof(uint32));
|
||||
break;
|
||||
}
|
||||
|
||||
else if ( bt->Tag() == TYPE_RECORD )
|
||||
case TYPE_RECORD:
|
||||
{
|
||||
const RecordVal* rv = v ? v->AsRecordVal() : 0;
|
||||
RecordType* rt = bt->AsRecordType();
|
||||
|
@ -396,14 +434,81 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v,
|
|||
if ( ! sz )
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
if ( ! v )
|
||||
return (optional && ! calc_static_size) ? sz : 0;
|
||||
|
||||
sz = SizeAlign(sz, sizeof(int));
|
||||
TableVal* tv = const_cast<TableVal*>(v->AsTableVal());
|
||||
ListVal* lv = tv->ConvertToList();
|
||||
for ( int i = 0; i < tv->Size(); ++i )
|
||||
{
|
||||
Val* key = lv->Index(i);
|
||||
sz = SingleTypeKeySize(key->Type(), key, type_check, sz, false,
|
||||
calc_static_size);
|
||||
if ( ! sz ) return 0;
|
||||
if ( ! bt->IsSet() )
|
||||
{
|
||||
Val* val = tv->Lookup(key);
|
||||
sz = SingleTypeKeySize(val->Type(), val, type_check, sz,
|
||||
false, calc_static_size);
|
||||
if ( ! sz ) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
if ( ! v )
|
||||
return (optional && ! calc_static_size) ? sz : 0;
|
||||
|
||||
sz = SizeAlign(sz, sizeof(unsigned int));
|
||||
VectorVal* vv = const_cast<VectorVal*>(v->AsVectorVal());
|
||||
for ( unsigned int i = 0; i < vv->Size(); ++i )
|
||||
{
|
||||
Val* val = vv->Lookup(i);
|
||||
sz = SizeAlign(sz, sizeof(unsigned int));
|
||||
sz = SizeAlign(sz, sizeof(unsigned int));
|
||||
if ( val )
|
||||
sz = SingleTypeKeySize(bt->AsVectorType()->YieldType(),
|
||||
val, type_check, sz, false,
|
||||
calc_static_size);
|
||||
if ( ! sz ) return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_LIST:
|
||||
{
|
||||
sz = SizeAlign(sz, sizeof(int));
|
||||
ListVal* lv = const_cast<ListVal*>(v->AsListVal());
|
||||
for ( int i = 0; i < lv->Length(); ++i )
|
||||
{
|
||||
sz = SingleTypeKeySize(lv->Index(i)->Type(), lv->Index(i),
|
||||
type_check, sz, false, calc_static_size);
|
||||
if ( ! sz) return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
reporter->InternalError("bad index type in CompositeHash::CompositeHash");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
break; // case TYPE_INTERNAL_VOID/OTHER
|
||||
}
|
||||
|
||||
case TYPE_INTERNAL_STRING:
|
||||
if ( ! v )
|
||||
|
@ -602,16 +707,13 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
|||
case TYPE_INTERNAL_ADDR:
|
||||
{
|
||||
const uint32* const kp = AlignType<uint32>(kp0);
|
||||
#ifdef BROv6
|
||||
const_addr_type addr_val = kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+4);
|
||||
#else
|
||||
const_addr_type addr_val = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
#endif
|
||||
|
||||
IPAddr addr(IPv6, kp, IPAddr::Network);
|
||||
|
||||
switch ( tag ) {
|
||||
case TYPE_ADDR:
|
||||
pval = new AddrVal(addr_val);
|
||||
pval = new AddrVal(addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -624,19 +726,17 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
|||
|
||||
case TYPE_INTERNAL_SUBNET:
|
||||
{
|
||||
const subnet_type* const kp =
|
||||
reinterpret_cast<const subnet_type*>(
|
||||
AlignType<uint32>(kp0));
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
|
||||
pval = new SubNetVal(kp->net, kp->width);
|
||||
const uint32* const kp = AlignType<uint32>(kp0);
|
||||
kp1 = reinterpret_cast<const char*>(kp+5);
|
||||
pval = new SubNetVal(kp, kp[4]);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_VOID:
|
||||
case TYPE_INTERNAL_OTHER:
|
||||
{
|
||||
if ( t->Tag() == TYPE_FUNC )
|
||||
switch ( t->Tag() ) {
|
||||
case TYPE_FUNC:
|
||||
{
|
||||
const uint32* const kp = AlignType<uint32>(kp0);
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
|
@ -662,8 +762,9 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
|||
pval->Type()->Tag() != TYPE_FUNC )
|
||||
reporter->InternalError("inconsistent aggregate Val in CompositeHash::RecoverOneVal()");
|
||||
}
|
||||
break;
|
||||
|
||||
else if ( t->Tag() == TYPE_RECORD )
|
||||
case TYPE_RECORD:
|
||||
{
|
||||
const char* kp = kp0;
|
||||
RecordType* rt = t->AsRecordType();
|
||||
|
@ -700,11 +801,91 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0,
|
|||
pval = rv;
|
||||
kp1 = kp;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
int n;
|
||||
const int* const kp = AlignType<int>(kp0);
|
||||
n = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
TableType* tt = t->AsTableType();
|
||||
TableVal* tv = new TableVal(tt);
|
||||
vector<Val*> keys, values;
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
Val* key;
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, tt->Indices(), key, false);
|
||||
keys.push_back(key);
|
||||
if ( ! t->IsSet() )
|
||||
{
|
||||
Val* value;
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, tt->YieldType(), value,
|
||||
false);
|
||||
values.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < n; ++i )
|
||||
tv->Assign(keys[i], t->IsSet() ? 0 : values[i]);
|
||||
|
||||
pval = tv;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
unsigned int n;
|
||||
const unsigned int* kp = AlignType<unsigned int>(kp0);
|
||||
n = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
VectorType* vt = t->AsVectorType();
|
||||
VectorVal* vv = new VectorVal(vt);
|
||||
for ( unsigned int i = 0; i < n; ++i )
|
||||
{
|
||||
kp = AlignType<unsigned int>(kp1);
|
||||
unsigned int index = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
kp = AlignType<unsigned int>(kp1);
|
||||
unsigned int have_val = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
Val* value = 0;
|
||||
if ( have_val )
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, vt->YieldType(), value,
|
||||
false);
|
||||
vv->Assign(index, value, 0);
|
||||
}
|
||||
|
||||
pval = vv;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LIST:
|
||||
{
|
||||
int n;
|
||||
const int* const kp = AlignType<int>(kp0);
|
||||
n = *kp;
|
||||
kp1 = reinterpret_cast<const char*>(kp+1);
|
||||
TypeList* tl = t->AsTypeList();
|
||||
ListVal* lv = new ListVal(TYPE_ANY);
|
||||
for ( int i = 0; i < n; ++i )
|
||||
{
|
||||
Val* v;
|
||||
BroType* it = (*tl->Types())[i];
|
||||
kp1 = RecoverOneVal(k, kp1, k_end, it, v, false);
|
||||
lv->Append(v);
|
||||
}
|
||||
|
||||
pval = lv;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
reporter->InternalError("bad index type in CompositeHash::DescribeKey");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_INTERNAL_STRING:
|
||||
|
|
146
src/Conn.cc
146
src/Conn.cc
|
@ -13,32 +13,7 @@
|
|||
#include "Timer.h"
|
||||
#include "PIA.h"
|
||||
#include "binpac.h"
|
||||
|
||||
HashKey* ConnID::BuildConnKey() const
|
||||
{
|
||||
Key key;
|
||||
|
||||
// Lookup up connection based on canonical ordering, which is
|
||||
// the smaller of <src addr, src port> and <dst addr, dst port>
|
||||
// followed by the other.
|
||||
if ( is_one_way ||
|
||||
addr_port_canon_lt(src_addr, src_port, dst_addr, dst_port) )
|
||||
{
|
||||
copy_addr(src_addr, key.ip1);
|
||||
copy_addr(dst_addr, key.ip2);
|
||||
key.port1 = src_port;
|
||||
key.port2 = dst_port;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_addr(dst_addr, key.ip1);
|
||||
copy_addr(src_addr, key.ip2);
|
||||
key.port1 = dst_port;
|
||||
key.port2 = src_port;
|
||||
}
|
||||
|
||||
return new HashKey(&key, sizeof(key));
|
||||
}
|
||||
#include "TunnelEncapsulation.h"
|
||||
|
||||
void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer,
|
||||
int arg_do_expire)
|
||||
|
@ -137,17 +112,22 @@ unsigned int Connection::external_connections = 0;
|
|||
|
||||
IMPLEMENT_SERIAL(Connection, SER_CONNECTION);
|
||||
|
||||
Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id)
|
||||
Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id,
|
||||
uint32 flow, const EncapsulationStack* arg_encap)
|
||||
{
|
||||
sessions = s;
|
||||
key = k;
|
||||
start_time = last_time = t;
|
||||
|
||||
copy_addr(id->src_addr, orig_addr);
|
||||
copy_addr(id->dst_addr, resp_addr);
|
||||
orig_addr = id->src_addr;
|
||||
resp_addr = id->dst_addr;
|
||||
orig_port = id->src_port;
|
||||
resp_port = id->dst_port;
|
||||
proto = TRANSPORT_UNKNOWN;
|
||||
orig_flow_label = flow;
|
||||
resp_flow_label = 0;
|
||||
saw_first_orig_packet = 1;
|
||||
saw_first_resp_packet = 0;
|
||||
|
||||
conn_val = 0;
|
||||
login_conn = 0;
|
||||
|
@ -181,6 +161,11 @@ Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id)
|
|||
|
||||
uid = 0; // Will set later.
|
||||
|
||||
if ( arg_encap )
|
||||
encapsulation = new EncapsulationStack(*arg_encap);
|
||||
else
|
||||
encapsulation = 0;
|
||||
|
||||
if ( conn_timer_mgr )
|
||||
{
|
||||
++external_connections;
|
||||
|
@ -208,12 +193,40 @@ Connection::~Connection()
|
|||
delete key;
|
||||
delete root_analyzer;
|
||||
delete conn_timer_mgr;
|
||||
delete encapsulation;
|
||||
|
||||
--current_connections;
|
||||
if ( conn_timer_mgr )
|
||||
--external_connections;
|
||||
}
|
||||
|
||||
void Connection::CheckEncapsulation(const EncapsulationStack* arg_encap)
|
||||
{
|
||||
if ( encapsulation && arg_encap )
|
||||
{
|
||||
if ( *encapsulation != *arg_encap )
|
||||
{
|
||||
Event(tunnel_changed, 0, arg_encap->GetVectorVal());
|
||||
delete encapsulation;
|
||||
encapsulation = new EncapsulationStack(*arg_encap);
|
||||
}
|
||||
}
|
||||
|
||||
else if ( encapsulation )
|
||||
{
|
||||
EncapsulationStack empty;
|
||||
Event(tunnel_changed, 0, empty.GetVectorVal());
|
||||
delete encapsulation;
|
||||
encapsulation = 0;
|
||||
}
|
||||
|
||||
else if ( arg_encap )
|
||||
{
|
||||
Event(tunnel_changed, 0, arg_encap->GetVectorVal());
|
||||
encapsulation = new EncapsulationStack(*arg_encap);
|
||||
}
|
||||
}
|
||||
|
||||
void Connection::Done()
|
||||
{
|
||||
finished = 1;
|
||||
|
@ -349,10 +362,12 @@ RecordVal* Connection::BuildConnVal()
|
|||
RecordVal *orig_endp = new RecordVal(endpoint);
|
||||
orig_endp->Assign(0, new Val(0, TYPE_COUNT));
|
||||
orig_endp->Assign(1, new Val(0, TYPE_COUNT));
|
||||
orig_endp->Assign(4, new Val(orig_flow_label, TYPE_COUNT));
|
||||
|
||||
RecordVal *resp_endp = new RecordVal(endpoint);
|
||||
resp_endp->Assign(0, new Val(0, TYPE_COUNT));
|
||||
resp_endp->Assign(1, new Val(0, TYPE_COUNT));
|
||||
resp_endp->Assign(4, new Val(resp_flow_label, TYPE_COUNT));
|
||||
|
||||
conn_val->Assign(0, id_val);
|
||||
conn_val->Assign(1, orig_endp);
|
||||
|
@ -368,6 +383,9 @@ RecordVal* Connection::BuildConnVal()
|
|||
|
||||
char tmp[20];
|
||||
conn_val->Assign(9, new StringVal(uitoa_n(uid, tmp, sizeof(tmp), 62)));
|
||||
|
||||
if ( encapsulation && encapsulation->Depth() > 0 )
|
||||
conn_val->Assign(10, encapsulation->GetVectorVal());
|
||||
}
|
||||
|
||||
if ( root_analyzer )
|
||||
|
@ -521,7 +539,7 @@ Val* Connection::BuildVersionVal(const char* s, int len)
|
|||
return sw;
|
||||
}
|
||||
|
||||
int Connection::VersionFoundEvent(const uint32* addr, const char* s, int len,
|
||||
int Connection::VersionFoundEvent(const IPAddr& addr, const char* s, int len,
|
||||
Analyzer* analyzer)
|
||||
{
|
||||
if ( ! software_version_found && ! software_parse_error )
|
||||
|
@ -559,7 +577,7 @@ int Connection::VersionFoundEvent(const uint32* addr, const char* s, int len,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int Connection::UnparsedVersionFoundEvent(const uint32* addr,
|
||||
int Connection::UnparsedVersionFoundEvent(const IPAddr& addr,
|
||||
const char* full, int len, Analyzer* analyzer)
|
||||
{
|
||||
// Skip leading white space.
|
||||
|
@ -693,15 +711,22 @@ TimerMgr* Connection::GetTimerMgr() const
|
|||
|
||||
void Connection::FlipRoles()
|
||||
{
|
||||
uint32 tmp_addr[NUM_ADDR_WORDS];
|
||||
copy_addr(resp_addr, tmp_addr);
|
||||
copy_addr(orig_addr, resp_addr);
|
||||
copy_addr(tmp_addr, orig_addr);
|
||||
IPAddr tmp_addr = resp_addr;
|
||||
orig_addr = resp_addr;
|
||||
resp_addr = tmp_addr;
|
||||
|
||||
uint32 tmp_port = resp_port;
|
||||
resp_port = orig_port;
|
||||
orig_port = tmp_port;
|
||||
|
||||
bool tmp_bool = saw_first_resp_packet;
|
||||
saw_first_resp_packet = saw_first_orig_packet;
|
||||
saw_first_orig_packet = tmp_bool;
|
||||
|
||||
uint32 tmp_flow = resp_flow_label;
|
||||
resp_flow_label = orig_flow_label;
|
||||
orig_flow_label = tmp_flow;
|
||||
|
||||
Unref(conn_val);
|
||||
conn_val = 0;
|
||||
|
||||
|
@ -752,14 +777,14 @@ void Connection::Describe(ODesc* d) const
|
|||
}
|
||||
|
||||
d->SP();
|
||||
d->Add(dotted_addr(orig_addr));
|
||||
d->Add(orig_addr);
|
||||
d->Add(":");
|
||||
d->Add(ntohs(orig_port));
|
||||
|
||||
d->SP();
|
||||
d->AddSP("->");
|
||||
|
||||
d->Add(dotted_addr(resp_addr));
|
||||
d->Add(resp_addr);
|
||||
d->Add(":");
|
||||
d->Add(ntohs(resp_port));
|
||||
|
||||
|
@ -782,9 +807,8 @@ bool Connection::DoSerialize(SerialInfo* info) const
|
|||
|
||||
// First we write the members which are needed to
|
||||
// create the HashKey.
|
||||
for ( int j = 0; j < NUM_ADDR_WORDS; ++j )
|
||||
if ( ! SERIALIZE(orig_addr[j]) || ! SERIALIZE(resp_addr[j]) )
|
||||
return false;
|
||||
if ( ! SERIALIZE(orig_addr) || ! SERIALIZE(resp_addr) )
|
||||
return false;
|
||||
|
||||
if ( ! SERIALIZE(orig_port) || ! SERIALIZE(resp_port) )
|
||||
return false;
|
||||
|
@ -830,21 +854,21 @@ bool Connection::DoUnserialize(UnserialInfo* info)
|
|||
|
||||
// Build the hash key first. Some of the recursive *::Unserialize()
|
||||
// functions may need it.
|
||||
for ( int i = 0; i < NUM_ADDR_WORDS; ++i )
|
||||
if ( ! UNSERIALIZE(&orig_addr[i]) || ! UNSERIALIZE(&resp_addr[i]) )
|
||||
goto error;
|
||||
ConnID id;
|
||||
|
||||
if ( ! UNSERIALIZE(&orig_addr) || ! UNSERIALIZE(&resp_addr) )
|
||||
goto error;
|
||||
|
||||
if ( ! UNSERIALIZE(&orig_port) || ! UNSERIALIZE(&resp_port) )
|
||||
goto error;
|
||||
|
||||
ConnID id;
|
||||
id.src_addr = orig_addr;
|
||||
id.dst_addr = resp_addr;
|
||||
// This doesn't work for ICMP. But I guess this is not really important.
|
||||
id.src_port = orig_port;
|
||||
id.dst_port = resp_port;
|
||||
id.is_one_way = 0; // ### incorrect for ICMP
|
||||
key = id.BuildConnKey();
|
||||
key = BuildConnIDHashKey(id);
|
||||
|
||||
int len;
|
||||
if ( ! UNSERIALIZE(&len) )
|
||||
|
@ -910,3 +934,35 @@ void Connection::SetRootAnalyzer(TransportLayerAnalyzer* analyzer, PIA* pia)
|
|||
root_analyzer = analyzer;
|
||||
primary_PIA = pia;
|
||||
}
|
||||
|
||||
void Connection::CheckFlowLabel(bool is_orig, uint32 flow_label)
|
||||
{
|
||||
uint32& my_flow_label = is_orig ? orig_flow_label : resp_flow_label;
|
||||
|
||||
if ( my_flow_label != flow_label )
|
||||
{
|
||||
if ( conn_val )
|
||||
{
|
||||
RecordVal *endp = conn_val->Lookup(is_orig ? 1 : 2)->AsRecordVal();
|
||||
endp->Assign(4, new Val(flow_label, TYPE_COUNT));
|
||||
}
|
||||
|
||||
if ( connection_flow_label_changed &&
|
||||
(is_orig ? saw_first_orig_packet : saw_first_resp_packet) )
|
||||
{
|
||||
val_list* vl = new val_list(4);
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(new Val(is_orig, TYPE_BOOL));
|
||||
vl->append(new Val(my_flow_label, TYPE_COUNT));
|
||||
vl->append(new Val(flow_label, TYPE_COUNT));
|
||||
ConnectionEvent(connection_flow_label_changed, 0, vl);
|
||||
}
|
||||
|
||||
my_flow_label = flow_label;
|
||||
}
|
||||
|
||||
if ( is_orig )
|
||||
saw_first_orig_packet = 1;
|
||||
else
|
||||
saw_first_resp_packet = 1;
|
||||
}
|
||||
|
|
105
src/Conn.h
105
src/Conn.h
|
@ -12,6 +12,8 @@
|
|||
#include "PersistenceSerializer.h"
|
||||
#include "RuleMatcher.h"
|
||||
#include "AnalyzerTags.h"
|
||||
#include "IPAddr.h"
|
||||
#include "TunnelEncapsulation.h"
|
||||
|
||||
class Connection;
|
||||
class ConnectionTimer;
|
||||
|
@ -32,61 +34,34 @@ typedef enum {
|
|||
typedef void (Connection::*timer_func)(double t);
|
||||
|
||||
struct ConnID {
|
||||
const uint32* src_addr;
|
||||
const uint32* dst_addr;
|
||||
IPAddr src_addr;
|
||||
IPAddr dst_addr;
|
||||
uint32 src_port;
|
||||
uint32 dst_port;
|
||||
bool is_one_way; // if true, don't canonicalize
|
||||
|
||||
// Returns a ListVal suitable for looking up a connection in
|
||||
// a hash table. addr/ports are expected to be in network order.
|
||||
// Unless is_one_way is true, the lookup sorts src and dst,
|
||||
// so src_addr/src_port and dst_addr/dst_port just have to
|
||||
// reflect the two different sides of the connection,
|
||||
// neither has to be the particular source/destination
|
||||
// or originator/responder.
|
||||
HashKey* BuildConnKey() const;
|
||||
|
||||
// The structure used internally for hashing.
|
||||
struct Key {
|
||||
uint32 ip1[NUM_ADDR_WORDS];
|
||||
uint32 ip2[NUM_ADDR_WORDS];
|
||||
uint16 port1;
|
||||
uint16 port2;
|
||||
};
|
||||
bool is_one_way; // if true, don't canonicalize order
|
||||
};
|
||||
|
||||
static inline int addr_port_canon_lt(const uint32* a1, uint32 p1,
|
||||
const uint32* a2, uint32 p2)
|
||||
static inline int addr_port_canon_lt(const IPAddr& addr1, uint32 p1,
|
||||
const IPAddr& addr2, uint32 p2)
|
||||
{
|
||||
#ifdef BROv6
|
||||
// Because it's a canonical ordering, not a strict ordering,
|
||||
// we can choose to give more weight to the least significant
|
||||
// word than to the most significant word. This matters
|
||||
// because for the common case of IPv4 addresses embedded in
|
||||
// a IPv6 address, the top three words are identical, so we can
|
||||
// save a few cycles by first testing the bottom word.
|
||||
return a1[3] < a2[3] ||
|
||||
(a1[3] == a2[3] &&
|
||||
(a1[2] < a2[2] ||
|
||||
(a1[2] == a2[2] &&
|
||||
(a1[1] < a2[1] ||
|
||||
(a1[1] == a2[1] &&
|
||||
(a1[0] < a2[0] ||
|
||||
(a1[0] == a2[0] &&
|
||||
p1 < p2)))))));
|
||||
#else
|
||||
return *a1 < *a2 || (*a1 == *a2 && p1 < p2);
|
||||
#endif
|
||||
return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
|
||||
}
|
||||
|
||||
class Analyzer;
|
||||
|
||||
class Connection : public BroObj {
|
||||
public:
|
||||
Connection(NetSessions* s, HashKey* k, double t, const ConnID* id);
|
||||
Connection(NetSessions* s, HashKey* k, double t, const ConnID* id,
|
||||
uint32 flow, const EncapsulationStack* arg_encap);
|
||||
virtual ~Connection();
|
||||
|
||||
// Invoked when an encapsulation is discovered. It records the
|
||||
// encapsulation with the connection and raises a "tunnel_changed"
|
||||
// event if it's different from the previous encapsulation (or the
|
||||
// first encountered). encap can be null to indicate no
|
||||
// encapsulation.
|
||||
void CheckEncapsulation(const EncapsulationStack* encap);
|
||||
|
||||
// Invoked when connection is about to be removed. Use Ref(this)
|
||||
// inside Done to keep the connection object around (though it'll
|
||||
// no longer be accessible from the dictionary of active
|
||||
|
@ -119,8 +94,8 @@ public:
|
|||
double LastTime() const { return last_time; }
|
||||
void SetLastTime(double t) { last_time = t; }
|
||||
|
||||
const uint32* OrigAddr() const { return orig_addr; }
|
||||
const uint32* RespAddr() const { return resp_addr; }
|
||||
const IPAddr& OrigAddr() const { return orig_addr; }
|
||||
const IPAddr& RespAddr() const { return resp_addr; }
|
||||
|
||||
uint32 OrigPort() const { return orig_port; }
|
||||
uint32 RespPort() const { return resp_port; }
|
||||
|
@ -185,11 +160,11 @@ public:
|
|||
|
||||
// Raises a software_version_found event based on the
|
||||
// given string (returns false if it's not parseable).
|
||||
int VersionFoundEvent(const uint32* addr, const char* s, int len,
|
||||
int VersionFoundEvent(const IPAddr& addr, const char* s, int len,
|
||||
Analyzer* analyzer = 0);
|
||||
|
||||
// Raises a software_unparsed_version_found event.
|
||||
int UnparsedVersionFoundEvent(const uint32* addr,
|
||||
int UnparsedVersionFoundEvent(const IPAddr& addr,
|
||||
const char* full_descr, int len, Analyzer* analyzer);
|
||||
|
||||
void Event(EventHandlerPtr f, Analyzer* analyzer, const char* name = 0);
|
||||
|
@ -273,32 +248,15 @@ public:
|
|||
// Sets the transport protocol in use.
|
||||
void SetTransport(TransportProto arg_proto) { proto = arg_proto; }
|
||||
|
||||
// If the connection compressor is activated, we need a special memory
|
||||
// layout for connections. (See ConnCompressor.h)
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
if ( ! use_connection_compressor )
|
||||
return ::operator new(size);
|
||||
|
||||
void* c = ::operator new(size + 4);
|
||||
|
||||
// We have to turn off the is_pending bit. By setting the
|
||||
// first four bytes to zero, we'll achieve this.
|
||||
*((uint32*) c) = 0;
|
||||
|
||||
return ((char *) c) + 4;
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
if ( ! use_connection_compressor )
|
||||
::operator delete(ptr);
|
||||
else
|
||||
::operator delete(((char*) ptr) - 4);
|
||||
}
|
||||
|
||||
void SetUID(uint64 arg_uid) { uid = arg_uid; }
|
||||
|
||||
uint64 GetUID() const { return uid; }
|
||||
|
||||
const EncapsulationStack* GetEncapsulation() const
|
||||
{ return encapsulation; }
|
||||
|
||||
void CheckFlowLabel(bool is_orig, uint32 flow_label);
|
||||
|
||||
protected:
|
||||
|
||||
Connection() { persistent = 0; }
|
||||
|
@ -325,14 +283,16 @@ protected:
|
|||
TimerMgr::Tag* conn_timer_mgr;
|
||||
timer_list timers;
|
||||
|
||||
uint32 orig_addr[NUM_ADDR_WORDS]; // in network order
|
||||
uint32 resp_addr[NUM_ADDR_WORDS]; // in network order
|
||||
IPAddr orig_addr;
|
||||
IPAddr resp_addr;
|
||||
uint32 orig_port, resp_port; // in network order
|
||||
TransportProto proto;
|
||||
uint32 orig_flow_label, resp_flow_label; // most recent IPv6 flow labels
|
||||
double start_time, last_time;
|
||||
double inactivity_timeout;
|
||||
RecordVal* conn_val;
|
||||
LoginConn* login_conn; // either nil, or this
|
||||
const EncapsulationStack* encapsulation; // tunnels
|
||||
int suppress_event; // suppress certain events to once per conn.
|
||||
|
||||
unsigned int installed_status_timer:1;
|
||||
|
@ -344,6 +304,7 @@ protected:
|
|||
unsigned int record_packets:1, record_contents:1;
|
||||
unsigned int persistent:1;
|
||||
unsigned int record_current_packet:1, record_current_content:1;
|
||||
unsigned int saw_first_orig_packet:1, saw_first_resp_packet:1;
|
||||
|
||||
// Count number of connections.
|
||||
static unsigned int total_connections;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,235 +0,0 @@
|
|||
// The ConnCompressor keeps track of the first packet seen for a conn_id using
|
||||
// only a minimal amount of memory. This helps us to avoid instantiating
|
||||
// full Connection objects for never-established sessions.
|
||||
//
|
||||
// TCP only.
|
||||
|
||||
#ifndef CONNCOMPRESSOR_H
|
||||
#define CONNCOMPRESSOR_H
|
||||
|
||||
#include "Conn.h"
|
||||
#include "Dict.h"
|
||||
#include "NetVar.h"
|
||||
#include "TCP.h"
|
||||
|
||||
class ConnCompressor {
|
||||
public:
|
||||
ConnCompressor();
|
||||
~ConnCompressor();
|
||||
|
||||
// Handle next packet. Returns 0 if packet in handled internally.
|
||||
// Takes ownership of key.
|
||||
Connection* NextPacket(double t, HashKey* k, const IP_Hdr* ip_hdr,
|
||||
const struct pcap_pkthdr* hdr, const u_char* const pkt);
|
||||
|
||||
// Look up a connection. Returns non-nil for connections for
|
||||
// which a Connection object has already been instantiated.
|
||||
Connection* Lookup(HashKey* k)
|
||||
{
|
||||
ConnData* c = conns.Lookup(k);
|
||||
return c && IsConnPtr(c) ? MakeConnPtr(c) : 0;
|
||||
}
|
||||
|
||||
// Inserts connection into compressor. If another entry with this key
|
||||
// already exists, it's replaced. If that was a full connection, it is
|
||||
// also returned.
|
||||
Connection* Insert(Connection* c);
|
||||
|
||||
// Remove all state belonging to the given connection. Returns
|
||||
// true if the connection was found in the compressor's table,
|
||||
// false if not.
|
||||
bool Remove(HashKey* k);
|
||||
|
||||
// Flush state.
|
||||
void Drain();
|
||||
|
||||
struct Sizes {
|
||||
// Current number of already fully instantiated connections.
|
||||
unsigned int connections;
|
||||
|
||||
// Total number of fully instantiated connections.
|
||||
unsigned int connections_total;
|
||||
|
||||
// Current number of seen but non-yet instantiated connections.
|
||||
unsigned int pending_valid;
|
||||
|
||||
// Total number of seen but non-yet instantiated connections.
|
||||
unsigned int pending_total;
|
||||
|
||||
// Total number of all entries in pending list (some a which
|
||||
// may already been invalid, but not yet removed from memory).
|
||||
unsigned int pending_in_mem;
|
||||
|
||||
// Total number of hash table entires
|
||||
// (should equal connections + pending_valid)
|
||||
unsigned int hash_table_size;
|
||||
|
||||
// Total memory usage;
|
||||
unsigned int memory;
|
||||
};
|
||||
|
||||
const Sizes& Size()
|
||||
{ sizes.hash_table_size = conns.Length(); return sizes; }
|
||||
|
||||
unsigned int MemoryAllocation() const { return sizes.memory; }
|
||||
|
||||
// As long as we have only seen packets from one side, we just
|
||||
// store a PendingConn.
|
||||
struct PendingConn {
|
||||
// True if the block is indeed a PendingConn (see below).
|
||||
unsigned int is_pending:1;
|
||||
|
||||
// Whether roles in key are flipped.
|
||||
unsigned int ip1_is_src:1;
|
||||
|
||||
unsigned int invalid:1; // deleted
|
||||
int window_scale:4;
|
||||
unsigned int SYN:1;
|
||||
unsigned int FIN:1;
|
||||
unsigned int RST:1;
|
||||
unsigned int ACK:1;
|
||||
|
||||
double time;
|
||||
ConnID::Key key;
|
||||
uint32 seq;
|
||||
uint32 ack;
|
||||
hash_t hash;
|
||||
uint16 window;
|
||||
uint64 uid;
|
||||
|
||||
// The following are set if use_conn_size_analyzer is T.
|
||||
uint16 num_pkts;
|
||||
uint16 num_bytes_ip;
|
||||
};
|
||||
|
||||
private:
|
||||
// Helpers to extract addrs/ports from PendingConn.
|
||||
|
||||
const uint32* SrcAddr(const PendingConn* c)
|
||||
{ return c->ip1_is_src ? c->key.ip1 : c->key.ip2; }
|
||||
const uint32* DstAddr(const PendingConn* c)
|
||||
{ return c->ip1_is_src ? c->key.ip2 : c->key.ip1; }
|
||||
|
||||
uint16 SrcPort(const PendingConn* c)
|
||||
{ return c->ip1_is_src ? c->key.port1 : c->key.port2; }
|
||||
uint16 DstPort(const PendingConn* c)
|
||||
{ return c->ip1_is_src ? c->key.port2 : c->key.port1; }
|
||||
|
||||
|
||||
// Called for the first packet in a connection.
|
||||
Connection* FirstFromOrig(double t, HashKey* key,
|
||||
const IP_Hdr* ip, const tcphdr* tp);
|
||||
|
||||
// Called for more packets from the orginator w/o seeing a response.
|
||||
Connection* NextFromOrig(PendingConn* pending, double t, HashKey* key,
|
||||
const IP_Hdr* ip, const tcphdr* tp);
|
||||
|
||||
// Called for the first response packet. Instantiates a Connection.
|
||||
Connection* Response(PendingConn* pending, double t, HashKey* key,
|
||||
const IP_Hdr* ip, const tcphdr* tp);
|
||||
|
||||
// Instantiates a full TCP connection (invalidates pending connection).
|
||||
Connection* Instantiate(HashKey* key, PendingConn* pending);
|
||||
|
||||
// Same but based on packet.
|
||||
Connection* Instantiate(double t, HashKey* key, const IP_Hdr* ip);
|
||||
|
||||
// Fills the attributes of a PendingConn based on the given arguments.
|
||||
void PktHdrToPendingConn(double time, const HashKey* key,
|
||||
const IP_Hdr* ip, const struct tcphdr* tp, PendingConn* c);
|
||||
|
||||
// Fakes a TCP packet based on the available information.
|
||||
const IP_Hdr* PendingConnToPacket(const PendingConn* c);
|
||||
|
||||
// Construct a TCP-flags byte.
|
||||
uint8 MakeFlags(const PendingConn* c) const;
|
||||
|
||||
// Allocate room for a new (Ext)PendingConn.
|
||||
PendingConn* MakeNewState(double t);
|
||||
|
||||
// Expire PendingConns.
|
||||
void DoExpire(double t);
|
||||
|
||||
// Remove all state belonging to the given connection.
|
||||
void Invalidate(HashKey* k);
|
||||
|
||||
// Sends the given connection_* event. If orig_state is
|
||||
// TCP_ENDPOINT__INACTIVE, tries to guess a better one based
|
||||
// on pending. If arg in non-nil, it will be used as the
|
||||
// *first* argument of the event call (this is for conn_weird()).
|
||||
void Event(const PendingConn* pending, double t,
|
||||
const EventHandlerPtr& event, int orig_state,
|
||||
int orig_size, int resp_state, Val* arg = 0);
|
||||
|
||||
void Weird(const PendingConn* pending, double t, const char* msg)
|
||||
{
|
||||
// This will actually go through the Reporter; Event() takes
|
||||
// care of that.
|
||||
Event(pending, t, conn_weird, TCP_ENDPOINT_INACTIVE, 0,
|
||||
TCP_ENDPOINT_INACTIVE, new StringVal(msg));
|
||||
}
|
||||
|
||||
static const int BLOCK_SIZE = 16 * 1024;
|
||||
|
||||
// The memory managment for PendConns.
|
||||
struct Block {
|
||||
double time;
|
||||
Block* prev;
|
||||
Block* next;
|
||||
int bytes_used;
|
||||
unsigned char data[BLOCK_SIZE];
|
||||
};
|
||||
|
||||
// In the connection hash table, we store pointers to both PendingConns
|
||||
// and Connections. Thus, we need a way to differentiate between
|
||||
// these two types. To avoid an additional indirection, we use a little
|
||||
// hack: a pointer retrieved from the table is interpreted as a
|
||||
// PendingConn first. However, if is_pending is false, it's in fact a
|
||||
// Connection which starts at offset 4. The methods below help to
|
||||
// implement this scheme transparently. An "operator new" in
|
||||
// Connection takes care of building Connection's accordingly.
|
||||
typedef PendingConn ConnData;
|
||||
declare(PDict, ConnData);
|
||||
typedef PDict(ConnData) ConnMap;
|
||||
ConnMap conns;
|
||||
|
||||
static ConnData* MakeMapPtr(PendingConn* c)
|
||||
{ assert(c->is_pending); return c; }
|
||||
|
||||
static ConnData* MakeMapPtr(Connection* c)
|
||||
{
|
||||
ConnData* p = (ConnData*) (((char*) c) - 4);
|
||||
assert(!p->is_pending);
|
||||
return p;
|
||||
}
|
||||
|
||||
static PendingConn* MakePendingConnPtr(ConnData* c)
|
||||
{ assert(c->is_pending); return c; }
|
||||
|
||||
static Connection* MakeConnPtr(ConnData* c)
|
||||
{
|
||||
assert(!c->is_pending);
|
||||
return (Connection*) (((char*) c) + 4);
|
||||
}
|
||||
|
||||
static bool IsConnPtr(ConnData* c)
|
||||
{ return ! c->is_pending; }
|
||||
|
||||
// New blocks are inserted at the end.
|
||||
Block* first_block;
|
||||
Block* last_block;
|
||||
|
||||
// If we have already expired some entries in a block,
|
||||
// this points to the first non-expired.
|
||||
unsigned char* first_non_expired;
|
||||
|
||||
// Last "connection" that we have build.
|
||||
RecordVal* conn_val;
|
||||
|
||||
// Statistics.
|
||||
Sizes sizes;
|
||||
};
|
||||
|
||||
extern ConnCompressor* conn_compressor;
|
||||
|
||||
#endif
|
|
@ -137,12 +137,12 @@ static bool is_mapped_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr)
|
|||
|
||||
bool is_mapped_dce_rpc_endpoint(const ConnID* id, TransportProto proto)
|
||||
{
|
||||
#ifdef BROv6
|
||||
if ( ! is_v4_addr(id->dst_addr) )
|
||||
if ( id->dst_addr.GetFamily() == IPv6 )
|
||||
// TODO: Does the protocol support v6 addresses? #773
|
||||
return false;
|
||||
#endif
|
||||
|
||||
dce_rpc_endpoint_addr addr;
|
||||
addr.addr = ntohl(to_v4_addr(id->dst_addr));
|
||||
addr.addr = id->dst_addr;
|
||||
addr.port = ntohs(id->dst_port);
|
||||
addr.proto = proto;
|
||||
|
||||
|
@ -160,12 +160,7 @@ static void add_dce_rpc_endpoint(const dce_rpc_endpoint_addr& addr,
|
|||
// of the dce_rpc_endpoints table.
|
||||
// FIXME: Don't hard-code the timeout.
|
||||
|
||||
// Convert the address to a v4/v6 address (depending on how
|
||||
// Bro was configured). This is all based on the address currently
|
||||
// being a 32-bit host-order v4 address.
|
||||
AddrVal a(htonl(addr.addr));
|
||||
const addr_type at = a.AsAddr();
|
||||
dpm->ExpectConnection(0, at, addr.port, addr.proto,
|
||||
dpm->ExpectConnection(IPAddr(), addr.addr, addr.port, addr.proto,
|
||||
AnalyzerTag::DCE_RPC, 5 * 60, 0);
|
||||
}
|
||||
|
||||
|
@ -418,8 +413,8 @@ void DCE_RPC_Session::DeliverEpmapperMapResponse(
|
|||
break;
|
||||
|
||||
case binpac::DCE_RPC_Simple::EPM_PROTOCOL_IP:
|
||||
mapped.addr.addr =
|
||||
floor->rhs()->data()->ip();
|
||||
uint32 hostip = floor->rhs()->data()->ip();
|
||||
mapped.addr.addr = IPAddr(IPv4, &hostip, IPAddr::Host);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +428,7 @@ void DCE_RPC_Session::DeliverEpmapperMapResponse(
|
|||
vl->append(analyzer->BuildConnVal());
|
||||
vl->append(new StringVal(mapped.uuid.to_string()));
|
||||
vl->append(new PortVal(mapped.addr.port, mapped.addr.proto));
|
||||
vl->append(new AddrVal(htonl(mapped.addr.addr)));
|
||||
vl->append(new AddrVal(mapped.addr.addr));
|
||||
|
||||
analyzer->ConnectionEvent(epm_map_response, vl);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "NetVar.h"
|
||||
#include "TCP.h"
|
||||
#include "IPAddr.h"
|
||||
|
||||
#include "dce_rpc_simple_pac.h"
|
||||
|
||||
|
@ -34,19 +35,19 @@ const char* uuid_to_string(const u_char* uuid_data);
|
|||
|
||||
struct dce_rpc_endpoint_addr {
|
||||
// All fields are in host byteorder.
|
||||
uint32 addr;
|
||||
IPAddr addr;
|
||||
u_short port;
|
||||
TransportProto proto;
|
||||
|
||||
dce_rpc_endpoint_addr()
|
||||
{
|
||||
addr = 0;
|
||||
addr = IPAddr();
|
||||
port = 0;
|
||||
proto = TRANSPORT_UNKNOWN;
|
||||
}
|
||||
|
||||
bool is_valid_addr() const
|
||||
{ return addr != 0 && port != 0 && proto != TRANSPORT_UNKNOWN; }
|
||||
{ return addr != IPAddr() && port != 0 && proto != TRANSPORT_UNKNOWN; }
|
||||
|
||||
bool operator<(dce_rpc_endpoint_addr const &e) const
|
||||
{
|
||||
|
@ -64,7 +65,7 @@ struct dce_rpc_endpoint_addr {
|
|||
{
|
||||
static char buf[128];
|
||||
snprintf(buf, sizeof(buf), "%s/%d/%s",
|
||||
dotted_addr(htonl(addr)), port,
|
||||
addr.AsString().c_str(), port,
|
||||
proto == TRANSPORT_TCP ? "tcp" :
|
||||
(proto == TRANSPORT_UDP ? "udp" : "?"));
|
||||
|
||||
|
|
15
src/DFA.cc
15
src/DFA.cc
|
@ -2,9 +2,10 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#include "EquivClass.h"
|
||||
#include "DFA.h"
|
||||
#include "md5.h"
|
||||
|
||||
int dfa_state_cache_size = 10000;
|
||||
|
||||
|
@ -312,8 +313,8 @@ DFA_State* DFA_State_Cache::Lookup(const NFA_state_list& nfas,
|
|||
{
|
||||
// We assume that state ID's don't exceed 10 digits, plus
|
||||
// we allow one more character for the delimiter.
|
||||
md5_byte_t id_tag[nfas.length() * 11 + 1];
|
||||
md5_byte_t* p = id_tag;
|
||||
u_char id_tag[nfas.length() * 11 + 1];
|
||||
u_char* p = id_tag;
|
||||
|
||||
for ( int i = 0; i < nfas.length(); ++i )
|
||||
{
|
||||
|
@ -335,12 +336,8 @@ DFA_State* DFA_State_Cache::Lookup(const NFA_state_list& nfas,
|
|||
|
||||
// We use the short MD5 instead of the full string for the
|
||||
// HashKey because the data is copied into the key.
|
||||
md5_state_t state;
|
||||
md5_byte_t digest[16];
|
||||
|
||||
md5_init(&state);
|
||||
md5_append(&state, id_tag, p - id_tag);
|
||||
md5_finish(&state, digest);
|
||||
u_char digest[16];
|
||||
MD5(id_tag, p - id_tag, digest);
|
||||
|
||||
*hash = new HashKey(&digest, sizeof(digest));
|
||||
CacheEntry* e = states.Lookup(*hash);
|
||||
|
|
|
@ -63,10 +63,10 @@ void DNS_TCP_Analyzer_binpac::Done()
|
|||
interp->FlowEOF(false);
|
||||
}
|
||||
|
||||
void DNS_TCP_Analyzer_binpac::EndpointEOF(TCP_Reassembler* endp)
|
||||
void DNS_TCP_Analyzer_binpac::EndpointEOF(bool is_orig)
|
||||
{
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(endp);
|
||||
interp->FlowEOF(endp->IsOrig());
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
void DNS_TCP_Analyzer_binpac::DeliverStream(int len, const u_char* data,
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual void EndpointEOF(TCP_Reassembler* endp);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new DNS_TCP_Analyzer_binpac(conn); }
|
||||
|
|
51
src/DNS.cc
51
src/DNS.cc
|
@ -758,62 +758,37 @@ int DNS_Interpreter::ParseRR_A(DNS_MsgInfo* msg,
|
|||
int DNS_Interpreter::ParseRR_AAAA(DNS_MsgInfo* msg,
|
||||
const u_char*& data, int& len, int rdlength)
|
||||
{
|
||||
// We need to parse an IPv6 address, high-order byte first.
|
||||
// ### Currently, we fake an A reply rather than an AAAA reply,
|
||||
// since for the latter we won't be able to express the full
|
||||
// address (unless Bro was compiled for IPv6 addresses). We do
|
||||
// this fake by using just the bottom 4 bytes of the IPv6 address.
|
||||
uint32 addr[4];
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < 4; ++i )
|
||||
for ( int i = 0; i < 4; ++i )
|
||||
{
|
||||
addr[i] = ntohl(ExtractLong(data, len));
|
||||
addr[i] = htonl(ExtractLong(data, len));
|
||||
|
||||
if ( len < 0 )
|
||||
{
|
||||
analyzer->Weird("DNS_AAAA_neg_length");
|
||||
if ( msg->atype == TYPE_AAAA )
|
||||
analyzer->Weird("DNS_AAAA_neg_length");
|
||||
else
|
||||
analyzer->Weird("DNS_A6_neg_length");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Currently, dns_AAAA_reply is treated like dns_A_reply, since
|
||||
// IPv6 addresses are not generally processed. This needs to be
|
||||
// fixed. ###
|
||||
if ( dns_A_reply && ! msg->skip_event )
|
||||
EventHandlerPtr event;
|
||||
if ( msg->atype == TYPE_AAAA )
|
||||
event = dns_AAAA_reply;
|
||||
else
|
||||
event = dns_A6_reply;
|
||||
if ( event && ! msg->skip_event )
|
||||
{
|
||||
val_list* vl = new val_list;
|
||||
|
||||
vl->append(analyzer->BuildConnVal());
|
||||
vl->append(msg->BuildHdrVal());
|
||||
vl->append(msg->BuildAnswerVal());
|
||||
vl->append(new AddrVal(htonl(addr[3])));
|
||||
|
||||
analyzer->ConnectionEvent(dns_A_reply, vl);
|
||||
}
|
||||
|
||||
#if 0
|
||||
alternative AAAA code from Chris
|
||||
if ( dns_AAAA_reply && ! msg->skip_event )
|
||||
{
|
||||
val_list* vl = new val_list;
|
||||
|
||||
vl->append(analyzer->BuildConnVal());
|
||||
vl->append(msg->BuildHdrVal());
|
||||
vl->append(msg->BuildAnswerVal());
|
||||
#ifdef BROv6
|
||||
// FIXME: might need to htonl the addr first
|
||||
vl->append(new AddrVal(addr));
|
||||
#else
|
||||
vl->append(new AddrVal((uint32)0x0000));
|
||||
#endif
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, addr, addrstr, INET6_ADDRSTRLEN);
|
||||
vl->append(new StringVal(addrstr));
|
||||
|
||||
analyzer->ConnectionEvent(dns_AAAA_reply, vl);
|
||||
analyzer->ConnectionEvent(event, vl);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
314
src/DNS_Mgr.cc
314
src/DNS_Mgr.cc
|
@ -46,13 +46,13 @@ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
|
|||
|
||||
class DNS_Mgr_Request {
|
||||
public:
|
||||
DNS_Mgr_Request(const char* h) { host = copy_string(h); addr = 0; }
|
||||
DNS_Mgr_Request(uint32 a) { addr = a; host = 0; }
|
||||
DNS_Mgr_Request(const char* h, int af) { host = copy_string(h); fam = af; }
|
||||
DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 0; fam = 0; }
|
||||
~DNS_Mgr_Request() { delete [] host; }
|
||||
|
||||
// Returns nil if this was an address request.
|
||||
const char* ReqHost() const { return host; }
|
||||
uint32 ReqAddr() const { return addr; }
|
||||
const IPAddr& ReqAddr() const { return addr; }
|
||||
|
||||
int MakeRequest(nb_dns_info* nb_dns);
|
||||
int RequestPending() const { return request_pending; }
|
||||
|
@ -61,8 +61,8 @@ public:
|
|||
|
||||
protected:
|
||||
char* host; // if non-nil, this is a host request
|
||||
uint32 addr;
|
||||
uint32 ttl;
|
||||
int fam; // address family query type for host requests
|
||||
IPAddr addr;
|
||||
int request_pending;
|
||||
};
|
||||
|
||||
|
@ -75,15 +75,20 @@ int DNS_Mgr_Request::MakeRequest(nb_dns_info* nb_dns)
|
|||
|
||||
char err[NB_DNS_ERRSIZE];
|
||||
if ( host )
|
||||
return nb_dns_host_request(nb_dns, host, (void*) this, err) >= 0;
|
||||
return nb_dns_host_request2(nb_dns, host, fam, (void*) this, err) >= 0;
|
||||
else
|
||||
return nb_dns_addr_request(nb_dns, addr, (void*) this, err) >= 0;
|
||||
{
|
||||
const uint32* bytes;
|
||||
int len = addr.GetBytes(&bytes);
|
||||
return nb_dns_addr_request2(nb_dns, (char*) bytes,
|
||||
len == 1 ? AF_INET : AF_INET6, (void*) this, err) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
class DNS_Mapping {
|
||||
public:
|
||||
DNS_Mapping(const char* host, struct hostent* h, uint32 ttl);
|
||||
DNS_Mapping(uint32 addr, struct hostent* h, uint32 ttl);
|
||||
DNS_Mapping(const IPAddr& addr, struct hostent* h, uint32 ttl);
|
||||
DNS_Mapping(FILE* f);
|
||||
|
||||
int NoMapping() const { return no_mapping; }
|
||||
|
@ -93,9 +98,11 @@ public:
|
|||
|
||||
// Returns nil if this was an address request.
|
||||
const char* ReqHost() const { return req_host; }
|
||||
uint32 ReqAddr() const { return req_addr; }
|
||||
const char* ReqStr() const
|
||||
{ return req_host ? req_host : dotted_addr(ReqAddr()); }
|
||||
IPAddr ReqAddr() const { return req_addr; }
|
||||
string ReqStr() const
|
||||
{
|
||||
return req_host ? req_host : req_addr;
|
||||
}
|
||||
|
||||
ListVal* Addrs();
|
||||
TableVal* AddrsSet(); // addresses returned as a set
|
||||
|
@ -109,7 +116,14 @@ public:
|
|||
int Valid() const { return ! failed; }
|
||||
|
||||
bool Expired() const
|
||||
{ return current_time() > (creation_time + req_ttl); }
|
||||
{
|
||||
if ( req_host && num_addrs == 0)
|
||||
return false; // nothing to expire
|
||||
|
||||
return current_time() > (creation_time + req_ttl);
|
||||
}
|
||||
|
||||
int Type() const { return map_type; }
|
||||
|
||||
protected:
|
||||
friend class DNS_Mgr;
|
||||
|
@ -121,7 +135,7 @@ protected:
|
|||
int init_failed;
|
||||
|
||||
char* req_host;
|
||||
uint32 req_addr;
|
||||
IPAddr req_addr;
|
||||
uint32 req_ttl;
|
||||
|
||||
int num_names;
|
||||
|
@ -129,11 +143,12 @@ protected:
|
|||
StringVal* host_val;
|
||||
|
||||
int num_addrs;
|
||||
uint32* addrs;
|
||||
IPAddr* addrs;
|
||||
ListVal* addrs_val;
|
||||
|
||||
int failed;
|
||||
double creation_time;
|
||||
int map_type;
|
||||
};
|
||||
|
||||
void DNS_Mgr_mapping_delete_func(void* v)
|
||||
|
@ -154,14 +169,13 @@ DNS_Mapping::DNS_Mapping(const char* host, struct hostent* h, uint32 ttl)
|
|||
{
|
||||
Init(h);
|
||||
req_host = copy_string(host);
|
||||
req_addr = 0;
|
||||
req_ttl = ttl;
|
||||
|
||||
if ( names && ! names[0] )
|
||||
names[0] = copy_string(host);
|
||||
}
|
||||
|
||||
DNS_Mapping::DNS_Mapping(uint32 addr, struct hostent* h, uint32 ttl)
|
||||
DNS_Mapping::DNS_Mapping(const IPAddr& addr, struct hostent* h, uint32 ttl)
|
||||
{
|
||||
Init(h);
|
||||
req_addr = addr;
|
||||
|
@ -175,7 +189,6 @@ DNS_Mapping::DNS_Mapping(FILE* f)
|
|||
init_failed = 1;
|
||||
|
||||
req_host = 0;
|
||||
req_addr = 0;
|
||||
|
||||
char buf[512];
|
||||
|
||||
|
@ -188,14 +201,15 @@ DNS_Mapping::DNS_Mapping(FILE* f)
|
|||
char req_buf[512+1], name_buf[512+1];
|
||||
int is_req_host;
|
||||
|
||||
if ( sscanf(buf, "%lf %d %512s %d %512s %d", &creation_time, &is_req_host,
|
||||
req_buf, &failed, name_buf, &num_addrs) != 6 )
|
||||
if ( sscanf(buf, "%lf %d %512s %d %512s %d %d %"PRIu32, &creation_time,
|
||||
&is_req_host, req_buf, &failed, name_buf, &map_type, &num_addrs,
|
||||
&req_ttl) != 8 )
|
||||
return;
|
||||
|
||||
if ( is_req_host )
|
||||
req_host = copy_string(req_buf);
|
||||
else
|
||||
req_addr = dotted_to_addr(req_buf);
|
||||
req_addr = IPAddr(req_buf);
|
||||
|
||||
num_names = 1;
|
||||
names = new char*[num_names];
|
||||
|
@ -203,7 +217,7 @@ DNS_Mapping::DNS_Mapping(FILE* f)
|
|||
|
||||
if ( num_addrs > 0 )
|
||||
{
|
||||
addrs = new uint32[num_addrs];
|
||||
addrs = new IPAddr[num_addrs];
|
||||
|
||||
for ( int i = 0; i < num_addrs; ++i )
|
||||
{
|
||||
|
@ -217,7 +231,7 @@ DNS_Mapping::DNS_Mapping(FILE* f)
|
|||
if ( newline )
|
||||
*newline = '\0';
|
||||
|
||||
addrs[i] = dotted_to_addr(buf);
|
||||
addrs[i] = IPAddr(buf);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -280,14 +294,6 @@ StringVal* DNS_Mapping::Host()
|
|||
return host_val;
|
||||
}
|
||||
|
||||
// Converts an array of 4 bytes in network order to the corresponding
|
||||
// 32-bit network long.
|
||||
static uint32 raw_bytes_to_addr(const unsigned char b[4])
|
||||
{
|
||||
uint32 l = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
|
||||
return uint32(htonl(l));
|
||||
}
|
||||
|
||||
void DNS_Mapping::Init(struct hostent* h)
|
||||
{
|
||||
no_mapping = 0;
|
||||
|
@ -296,12 +302,13 @@ void DNS_Mapping::Init(struct hostent* h)
|
|||
host_val = 0;
|
||||
addrs_val = 0;
|
||||
|
||||
if ( ! h || h->h_addrtype != AF_INET || h->h_length != 4 )
|
||||
if ( ! h )
|
||||
{
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
map_type = h->h_addrtype;
|
||||
num_names = 1; // for now, just use official name
|
||||
names = new char*[num_names];
|
||||
names[0] = h->h_name ? copy_string(h->h_name) : 0;
|
||||
|
@ -311,10 +318,14 @@ void DNS_Mapping::Init(struct hostent* h)
|
|||
|
||||
if ( num_addrs > 0 )
|
||||
{
|
||||
addrs = new uint32[num_addrs];
|
||||
addrs = new IPAddr[num_addrs];
|
||||
for ( int i = 0; i < num_addrs; ++i )
|
||||
addrs[i] = raw_bytes_to_addr(
|
||||
(unsigned char*)h->h_addr_list[i]);
|
||||
if ( h->h_addrtype == AF_INET )
|
||||
addrs[i] = IPAddr(IPv4, (uint32*)h->h_addr_list[i],
|
||||
IPAddr::Network);
|
||||
else if ( h->h_addrtype == AF_INET6 )
|
||||
addrs[i] = IPAddr(IPv6, (uint32*)h->h_addr_list[i],
|
||||
IPAddr::Network);
|
||||
}
|
||||
else
|
||||
addrs = 0;
|
||||
|
@ -330,18 +341,19 @@ void DNS_Mapping::Clear()
|
|||
host_val = 0;
|
||||
addrs_val = 0;
|
||||
no_mapping = 0;
|
||||
map_type = 0;
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
void DNS_Mapping::Save(FILE* f) const
|
||||
{
|
||||
fprintf(f, "%.0f %d %s %d %s %d\n", creation_time, req_host != 0,
|
||||
req_host ? req_host : dotted_addr(req_addr),
|
||||
fprintf(f, "%.0f %d %s %d %s %d %d %"PRIu32"\n", creation_time, req_host != 0,
|
||||
req_host ? req_host : req_addr.AsString().c_str(),
|
||||
failed, (names && names[0]) ? names[0] : "*",
|
||||
num_addrs);
|
||||
map_type, num_addrs, req_ttl);
|
||||
|
||||
for ( int i = 0; i < num_addrs; ++i )
|
||||
fprintf(f, "%s\n", dotted_addr(addrs[i]));
|
||||
fprintf(f, "%s\n", addrs[i].AsString().c_str());
|
||||
}
|
||||
|
||||
|
||||
|
@ -351,9 +363,6 @@ DNS_Mgr::DNS_Mgr(DNS_MgrMode arg_mode)
|
|||
|
||||
mode = arg_mode;
|
||||
|
||||
host_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
|
||||
addr_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
|
||||
|
||||
char err[NB_DNS_ERRSIZE];
|
||||
nb_dns = nb_dns_init(err);
|
||||
|
||||
|
@ -440,24 +449,34 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
|
|||
|
||||
if ( mode != DNS_PRIME )
|
||||
{
|
||||
DNS_Mapping* d = host_mappings.Lookup(name);
|
||||
HostMap::iterator it = host_mappings.find(name);
|
||||
|
||||
if ( d )
|
||||
if ( it != host_mappings.end() )
|
||||
{
|
||||
if ( d->Valid() )
|
||||
return d->Addrs()->ConvertToSet();
|
||||
else
|
||||
DNS_Mapping* d4 = it->second.first;
|
||||
DNS_Mapping* d6 = it->second.second;
|
||||
|
||||
if ( (d4 && d4->Failed()) || (d6 && d6->Failed()) )
|
||||
{
|
||||
reporter->Warning("no such host: %s", name);
|
||||
return empty_addr_set();
|
||||
}
|
||||
else if ( d4 && d6 )
|
||||
{
|
||||
TableVal* tv4 = d4->AddrsSet();
|
||||
TableVal* tv6 = d6->AddrsSet();
|
||||
tv4->AddTo(tv6, false);
|
||||
Unref(tv4);
|
||||
return tv6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, or priming.
|
||||
switch ( mode ) {
|
||||
case DNS_PRIME:
|
||||
requests.append(new DNS_Mgr_Request(name));
|
||||
requests.append(new DNS_Mgr_Request(name, AF_INET));
|
||||
requests.append(new DNS_Mgr_Request(name, AF_INET6));
|
||||
return empty_addr_set();
|
||||
|
||||
case DNS_FORCE:
|
||||
|
@ -465,7 +484,8 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
|
|||
return 0;
|
||||
|
||||
case DNS_DEFAULT:
|
||||
requests.append(new DNS_Mgr_Request(name));
|
||||
requests.append(new DNS_Mgr_Request(name, AF_INET));
|
||||
requests.append(new DNS_Mgr_Request(name, AF_INET6));
|
||||
Resolve();
|
||||
return LookupHost(name);
|
||||
|
||||
|
@ -475,24 +495,25 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
|
|||
}
|
||||
}
|
||||
|
||||
Val* DNS_Mgr::LookupAddr(uint32 addr)
|
||||
Val* DNS_Mgr::LookupAddr(const IPAddr& addr)
|
||||
{
|
||||
if ( ! did_init )
|
||||
Init();
|
||||
|
||||
if ( mode != DNS_PRIME )
|
||||
{
|
||||
HashKey h(&addr, 1);
|
||||
DNS_Mapping* d = addr_mappings.Lookup(&h);
|
||||
AddrMap::iterator it = addr_mappings.find(addr);
|
||||
|
||||
if ( d )
|
||||
if ( it != addr_mappings.end() )
|
||||
{
|
||||
DNS_Mapping* d = it->second;
|
||||
if ( d->Valid() )
|
||||
return d->Host();
|
||||
else
|
||||
{
|
||||
reporter->Warning("can't resolve IP address: %s", dotted_addr(addr));
|
||||
return new StringVal(dotted_addr(addr));
|
||||
string s(addr);
|
||||
reporter->Warning("can't resolve IP address: %s", s.c_str());
|
||||
return new StringVal(s.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -505,7 +526,7 @@ Val* DNS_Mgr::LookupAddr(uint32 addr)
|
|||
|
||||
case DNS_FORCE:
|
||||
reporter->FatalError("can't find DNS entry for %s in cache",
|
||||
dotted_addr(addr));
|
||||
addr.AsString().c_str());
|
||||
return 0;
|
||||
|
||||
case DNS_DEFAULT:
|
||||
|
@ -595,8 +616,6 @@ void DNS_Mgr::Resolve()
|
|||
}
|
||||
else
|
||||
--num_pending;
|
||||
|
||||
delete dr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,7 +693,7 @@ Val* DNS_Mgr::BuildMappingVal(DNS_Mapping* dm)
|
|||
void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
|
||||
{
|
||||
struct hostent* h = (r && r->host_errno == 0) ? r->hostent : 0;
|
||||
u_int32_t ttl = r->ttl;
|
||||
u_int32_t ttl = (r && r->host_errno == 0) ? r->ttl : 0;
|
||||
|
||||
DNS_Mapping* new_dm;
|
||||
DNS_Mapping* prev_dm;
|
||||
|
@ -683,28 +702,53 @@ void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
|
|||
if ( dr->ReqHost() )
|
||||
{
|
||||
new_dm = new DNS_Mapping(dr->ReqHost(), h, ttl);
|
||||
prev_dm = host_mappings.Insert(dr->ReqHost(), new_dm);
|
||||
prev_dm = 0;
|
||||
|
||||
HostMap::iterator it = host_mappings.find(dr->ReqHost());
|
||||
if ( it == host_mappings.end() )
|
||||
{
|
||||
host_mappings[dr->ReqHost()].first =
|
||||
new_dm->Type() == AF_INET ? new_dm : 0;
|
||||
host_mappings[dr->ReqHost()].second =
|
||||
new_dm->Type() == AF_INET ? 0 : new_dm;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( new_dm->Type() == AF_INET )
|
||||
{
|
||||
prev_dm = it->second.first;
|
||||
it->second.first = new_dm;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_dm = it->second.second;
|
||||
it->second.second = new_dm;
|
||||
}
|
||||
}
|
||||
|
||||
if ( new_dm->Failed() && prev_dm && prev_dm->Valid() )
|
||||
{
|
||||
// Put previous, valid entry back - CompareMappings
|
||||
// will generate a corresponding warning.
|
||||
(void) host_mappings.Insert(dr->ReqHost(), prev_dm);
|
||||
if ( prev_dm->Type() == AF_INET )
|
||||
host_mappings[dr->ReqHost()].first = prev_dm;
|
||||
else
|
||||
host_mappings[dr->ReqHost()].second = prev_dm;
|
||||
|
||||
++keep_prev;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_dm = new DNS_Mapping(dr->ReqAddr(), h, ttl);
|
||||
uint32 tmp_addr = dr->ReqAddr();
|
||||
HashKey k(&tmp_addr, 1);
|
||||
prev_dm = addr_mappings.Insert(&k, new_dm);
|
||||
AddrMap::iterator it = addr_mappings.find(dr->ReqAddr());
|
||||
prev_dm = (it == addr_mappings.end()) ? 0 : it->second;
|
||||
addr_mappings[dr->ReqAddr()] = new_dm;
|
||||
|
||||
if ( new_dm->Failed() && prev_dm && prev_dm->Valid() )
|
||||
{
|
||||
uint32 tmp_addr = dr->ReqAddr();
|
||||
HashKey k2(&tmp_addr, 1);
|
||||
(void) addr_mappings.Insert(&k2, prev_dm);
|
||||
addr_mappings[dr->ReqAddr()] = prev_dm;
|
||||
++keep_prev;
|
||||
}
|
||||
}
|
||||
|
@ -776,17 +820,13 @@ ListVal* DNS_Mgr::AddrListDelta(ListVal* al1, ListVal* al2)
|
|||
|
||||
for ( int i = 0; i < al1->Length(); ++i )
|
||||
{
|
||||
addr_type al1_i = al1->Index(i)->AsAddr();
|
||||
const IPAddr& al1_i = al1->Index(i)->AsAddr();
|
||||
|
||||
int j;
|
||||
for ( j = 0; j < al2->Length(); ++j )
|
||||
{
|
||||
addr_type al2_j = al2->Index(j)->AsAddr();
|
||||
#ifdef BROv6
|
||||
if ( addr_eq(al1_i, al2_j) )
|
||||
#else
|
||||
const IPAddr& al2_j = al2->Index(j)->AsAddr();
|
||||
if ( al1_i == al2_j )
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -802,8 +842,8 @@ void DNS_Mgr::DumpAddrList(FILE* f, ListVal* al)
|
|||
{
|
||||
for ( int i = 0; i < al->Length(); ++i )
|
||||
{
|
||||
addr_type al_i = al->Index(i)->AsAddr();
|
||||
fprintf(f, "%s%s", i > 0 ? "," : "", dotted_addr(al_i));
|
||||
const IPAddr& al_i = al->Index(i)->AsAddr();
|
||||
fprintf(f, "%s%s", i > 0 ? "," : "", al_i.AsString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -816,12 +856,20 @@ void DNS_Mgr::LoadCache(FILE* f)
|
|||
for ( ; ! m->NoMapping() && ! m->InitFailed(); m = new DNS_Mapping(f) )
|
||||
{
|
||||
if ( m->ReqHost() )
|
||||
host_mappings.Insert(m->ReqHost(), m);
|
||||
{
|
||||
if ( host_mappings.find(m->ReqHost()) == host_mappings.end() )
|
||||
{
|
||||
host_mappings[m->ReqHost()].first = 0;
|
||||
host_mappings[m->ReqHost()].second = 0;
|
||||
}
|
||||
if ( m->Type() == AF_INET )
|
||||
host_mappings[m->ReqHost()].first = m;
|
||||
else
|
||||
host_mappings[m->ReqHost()].second = m;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 tmp_addr = m->ReqAddr();
|
||||
HashKey h(&tmp_addr, 1);
|
||||
addr_mappings.Insert(&h, m);
|
||||
addr_mappings[m->ReqAddr()] = m;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -832,26 +880,41 @@ void DNS_Mgr::LoadCache(FILE* f)
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
void DNS_Mgr::Save(FILE* f, PDict(DNS_Mapping)& m)
|
||||
void DNS_Mgr::Save(FILE* f, const AddrMap& m)
|
||||
{
|
||||
IterCookie* cookie = m.InitForIteration();
|
||||
DNS_Mapping* dm;
|
||||
|
||||
while ( (dm = m.NextEntry(cookie)) )
|
||||
dm->Save(f);
|
||||
for ( AddrMap::const_iterator it = m.begin(); it != m.end(); ++it )
|
||||
{
|
||||
if ( it->second )
|
||||
it->second->Save(f);
|
||||
}
|
||||
}
|
||||
|
||||
const char* DNS_Mgr::LookupAddrInCache(dns_mgr_addr_type addr)
|
||||
void DNS_Mgr::Save(FILE* f, const HostMap& m)
|
||||
{
|
||||
HashKey h(&addr, 1);
|
||||
DNS_Mapping* d = dns_mgr->addr_mappings.Lookup(&h);
|
||||
HostMap::const_iterator it;
|
||||
|
||||
if ( ! d )
|
||||
for ( it = m.begin(); it != m.end(); ++it )
|
||||
{
|
||||
if ( it->second.first )
|
||||
it->second.first->Save(f);
|
||||
|
||||
if ( it->second.second )
|
||||
it->second.second->Save(f);
|
||||
}
|
||||
}
|
||||
|
||||
const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr)
|
||||
{
|
||||
AddrMap::iterator it = dns_mgr->addr_mappings.find(addr);
|
||||
|
||||
if ( it == addr_mappings.end() )
|
||||
return 0;
|
||||
|
||||
DNS_Mapping* d = it->second;
|
||||
|
||||
if ( d->Expired() )
|
||||
{
|
||||
dns_mgr->addr_mappings.Remove(&h);
|
||||
dns_mgr->addr_mappings.erase(it);
|
||||
delete d;
|
||||
return 0;
|
||||
}
|
||||
|
@ -863,23 +926,32 @@ const char* DNS_Mgr::LookupAddrInCache(dns_mgr_addr_type addr)
|
|||
|
||||
TableVal* DNS_Mgr::LookupNameInCache(string name)
|
||||
{
|
||||
DNS_Mapping* d = dns_mgr->host_mappings.Lookup(name.c_str());
|
||||
|
||||
if ( ! d || ! d->names )
|
||||
HostMap::iterator it = dns_mgr->host_mappings.find(name);
|
||||
if ( it == dns_mgr->host_mappings.end() )
|
||||
return 0;
|
||||
|
||||
if ( d->Expired() )
|
||||
DNS_Mapping* d4 = it->second.first;
|
||||
DNS_Mapping* d6 = it->second.second;
|
||||
|
||||
if ( ! d4 || ! d4->names || ! d6 || ! d6->names )
|
||||
return 0;
|
||||
|
||||
if ( d4->Expired() || d6->Expired() )
|
||||
{
|
||||
HashKey h(name.c_str());
|
||||
dns_mgr->host_mappings.Remove(&h);
|
||||
delete d;
|
||||
dns_mgr->host_mappings.erase(it);
|
||||
delete d4;
|
||||
delete d6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return d->AddrsSet();
|
||||
TableVal* tv4 = d4->AddrsSet();
|
||||
TableVal* tv6 = d6->AddrsSet();
|
||||
tv4->AddTo(tv6, false);
|
||||
Unref(tv4);
|
||||
return tv6;
|
||||
}
|
||||
|
||||
void DNS_Mgr::AsyncLookupAddr(dns_mgr_addr_type host, LookupCallback* callback)
|
||||
void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback)
|
||||
{
|
||||
if ( ! did_init )
|
||||
Init();
|
||||
|
@ -958,10 +1030,15 @@ void DNS_Mgr::IssueAsyncRequests()
|
|||
++num_requests;
|
||||
|
||||
DNS_Mgr_Request* dr;
|
||||
DNS_Mgr_Request* dr6 = 0;
|
||||
|
||||
if ( req->IsAddrReq() )
|
||||
dr = new DNS_Mgr_Request(req->host);
|
||||
else
|
||||
dr = new DNS_Mgr_Request(req->name.c_str());
|
||||
{
|
||||
dr = new DNS_Mgr_Request(req->name.c_str(), AF_INET);
|
||||
dr6 = new DNS_Mgr_Request(req->name.c_str(), AF_INET6);
|
||||
}
|
||||
|
||||
if ( ! dr->MakeRequest(nb_dns) )
|
||||
{
|
||||
|
@ -971,6 +1048,14 @@ void DNS_Mgr::IssueAsyncRequests()
|
|||
continue;
|
||||
}
|
||||
|
||||
if ( dr6 && ! dr6->MakeRequest(nb_dns) )
|
||||
{
|
||||
reporter->Warning("can't issue DNS request");
|
||||
++failed;
|
||||
req->Timeout();
|
||||
continue;
|
||||
}
|
||||
|
||||
req->time = current_time();
|
||||
asyncs_timeouts.push(req);
|
||||
|
||||
|
@ -989,7 +1074,7 @@ double DNS_Mgr::NextTimestamp(double* network_time)
|
|||
return asyncs_timeouts.size() ? timer_mgr->Time() : -1.0;
|
||||
}
|
||||
|
||||
void DNS_Mgr::CheckAsyncAddrRequest(dns_mgr_addr_type addr, bool timeout)
|
||||
void DNS_Mgr::CheckAsyncAddrRequest(const IPAddr& addr, bool timeout)
|
||||
{
|
||||
// Note that this code is a mirror of that for CheckAsyncHostRequest.
|
||||
|
||||
|
@ -1062,11 +1147,18 @@ void DNS_Mgr::Flush()
|
|||
{
|
||||
DoProcess(false);
|
||||
|
||||
IterCookie* cookie = addr_mappings.InitForIteration();
|
||||
DNS_Mapping* dm;
|
||||
HostMap::iterator it;
|
||||
for ( it = host_mappings.begin(); it != host_mappings.end(); ++it )
|
||||
{
|
||||
delete it->second.first;
|
||||
delete it->second.second;
|
||||
}
|
||||
|
||||
host_mappings.Clear();
|
||||
addr_mappings.Clear();
|
||||
for ( AddrMap::iterator it2 = addr_mappings.begin(); it2 != addr_mappings.end(); ++it2 )
|
||||
delete it2->second;
|
||||
|
||||
host_mappings.clear();
|
||||
addr_mappings.clear();
|
||||
}
|
||||
|
||||
void DNS_Mgr::Process()
|
||||
|
@ -1109,6 +1201,14 @@ void DNS_Mgr::DoProcess(bool flush)
|
|||
else if ( status > 0 )
|
||||
{
|
||||
DNS_Mgr_Request* dr = (DNS_Mgr_Request*) r.cookie;
|
||||
|
||||
bool do_host_timeout = true;
|
||||
if ( dr->ReqHost() &&
|
||||
host_mappings.find(dr->ReqHost()) == host_mappings.end() )
|
||||
// Don't timeout when this is the first result in an expected pair
|
||||
// (one result each for A and AAAA queries).
|
||||
do_host_timeout = false;
|
||||
|
||||
if ( dr->RequestPending() )
|
||||
{
|
||||
AddResult(dr, &r);
|
||||
|
@ -1118,7 +1218,7 @@ void DNS_Mgr::DoProcess(bool flush)
|
|||
if ( ! dr->ReqHost() )
|
||||
CheckAsyncAddrRequest(dr->ReqAddr(), true);
|
||||
else
|
||||
CheckAsyncHostRequest(dr->ReqHost(), true);
|
||||
CheckAsyncHostRequest(dr->ReqHost(), do_host_timeout);
|
||||
|
||||
IssueAsyncRequests();
|
||||
|
||||
|
@ -1169,7 +1269,7 @@ void DNS_Mgr::GetStats(Stats* stats)
|
|||
stats->successful = successful;
|
||||
stats->failed = failed;
|
||||
stats->pending = asyncs_pending;
|
||||
stats->cached_hosts = host_mappings.Length();
|
||||
stats->cached_addresses = addr_mappings.Length();
|
||||
stats->cached_hosts = host_mappings.size();
|
||||
stats->cached_addresses = addr_mappings.size();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
#include "util.h"
|
||||
#include "BroList.h"
|
||||
#include "Dict.h"
|
||||
#include "EventHandler.h"
|
||||
#include "IOSource.h"
|
||||
#include "IPAddr.h"
|
||||
|
||||
class Val;
|
||||
class ListVal;
|
||||
|
@ -27,7 +29,6 @@ struct nb_dns_result;
|
|||
declare(PDict,ListVal);
|
||||
|
||||
class DNS_Mapping;
|
||||
declare(PDict,DNS_Mapping);
|
||||
|
||||
enum DNS_MgrMode {
|
||||
DNS_PRIME, // used to prime the cache
|
||||
|
@ -39,10 +40,6 @@ enum DNS_MgrMode {
|
|||
// Number of seconds we'll wait for a reply.
|
||||
#define DNS_TIMEOUT 5
|
||||
|
||||
// ### For now, we don't support IPv6 lookups. When we do, this
|
||||
// should become addr_type.
|
||||
typedef uint32 dns_mgr_addr_type;
|
||||
|
||||
class DNS_Mgr : public IOSource {
|
||||
public:
|
||||
DNS_Mgr(DNS_MgrMode mode);
|
||||
|
@ -55,7 +52,7 @@ public:
|
|||
// a set of addr.
|
||||
TableVal* LookupHost(const char* host);
|
||||
|
||||
Val* LookupAddr(uint32 addr);
|
||||
Val* LookupAddr(const IPAddr& addr);
|
||||
|
||||
// Define the directory where to store the data.
|
||||
void SetDir(const char* arg_dir) { dir = copy_string(arg_dir); }
|
||||
|
@ -64,7 +61,7 @@ public:
|
|||
void Resolve();
|
||||
int Save();
|
||||
|
||||
const char* LookupAddrInCache(dns_mgr_addr_type addr);
|
||||
const char* LookupAddrInCache(const IPAddr& addr);
|
||||
TableVal* LookupNameInCache(string name);
|
||||
|
||||
// Support for async lookups.
|
||||
|
@ -78,7 +75,7 @@ public:
|
|||
virtual void Timeout() = 0;
|
||||
};
|
||||
|
||||
void AsyncLookupAddr(dns_mgr_addr_type host, LookupCallback* callback);
|
||||
void AsyncLookupAddr(const IPAddr& host, LookupCallback* callback);
|
||||
void AsyncLookupName(string name, LookupCallback* callback);
|
||||
|
||||
struct Stats {
|
||||
|
@ -107,8 +104,11 @@ protected:
|
|||
ListVal* AddrListDelta(ListVal* al1, ListVal* al2);
|
||||
void DumpAddrList(FILE* f, ListVal* al);
|
||||
|
||||
typedef map<string, pair<DNS_Mapping*, DNS_Mapping*> > HostMap;
|
||||
typedef map<IPAddr, DNS_Mapping*> AddrMap;
|
||||
void LoadCache(FILE* f);
|
||||
void Save(FILE* f, PDict(DNS_Mapping)& m);
|
||||
void Save(FILE* f, const AddrMap& m);
|
||||
void Save(FILE* f, const HostMap& m);
|
||||
|
||||
// Selects on the fd to see if there is an answer available (timeout
|
||||
// is secs). Returns 0 on timeout, -1 on EINTR or other error, and 1
|
||||
|
@ -120,7 +120,7 @@ protected:
|
|||
|
||||
// Finish the request if we have a result. If not, time it out if
|
||||
// requested.
|
||||
void CheckAsyncAddrRequest(dns_mgr_addr_type addr, bool timeout);
|
||||
void CheckAsyncAddrRequest(const IPAddr& addr, bool timeout);
|
||||
void CheckAsyncHostRequest(const char* host, bool timeout);
|
||||
|
||||
// Process outstanding requests.
|
||||
|
@ -136,8 +136,8 @@ protected:
|
|||
|
||||
PDict(ListVal) services;
|
||||
|
||||
PDict(DNS_Mapping) host_mappings;
|
||||
PDict(DNS_Mapping) addr_mappings;
|
||||
HostMap host_mappings;
|
||||
AddrMap addr_mappings;
|
||||
|
||||
DNS_mgr_request_list requests;
|
||||
|
||||
|
@ -163,7 +163,7 @@ protected:
|
|||
|
||||
struct AsyncRequest {
|
||||
double time;
|
||||
dns_mgr_addr_type host;
|
||||
IPAddr host;
|
||||
string name;
|
||||
CallbackList callbacks;
|
||||
|
||||
|
@ -204,7 +204,7 @@ protected:
|
|||
|
||||
};
|
||||
|
||||
typedef map<dns_mgr_addr_type, AsyncRequest*> AsyncRequestAddrMap;
|
||||
typedef map<IPAddr, AsyncRequest*> AsyncRequestAddrMap;
|
||||
AsyncRequestAddrMap asyncs_addrs;
|
||||
|
||||
typedef map<string, AsyncRequest*> AsyncRequestNameMap;
|
||||
|
|
129
src/DPM.cc
129
src/DPM.cc
|
@ -11,53 +11,28 @@
|
|||
#include "ConnSizeAnalyzer.h"
|
||||
|
||||
|
||||
ExpectedConn::ExpectedConn(const uint32* _orig, const uint32* _resp,
|
||||
ExpectedConn::ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
|
||||
uint16 _resp_p, uint16 _proto)
|
||||
{
|
||||
if ( orig )
|
||||
copy_addr(_orig, orig);
|
||||
if ( _orig == IPAddr(string("0.0.0.0")) )
|
||||
// don't use the IPv4 mapping, use the literal unspecified address
|
||||
// to indicate a wildcard
|
||||
orig = IPAddr(string("::"));
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < NUM_ADDR_WORDS; ++i )
|
||||
orig[i] = 0;
|
||||
}
|
||||
|
||||
copy_addr(_resp, resp);
|
||||
|
||||
resp_p = _resp_p;
|
||||
proto = _proto;
|
||||
}
|
||||
|
||||
ExpectedConn::ExpectedConn(uint32 _orig, uint32 _resp,
|
||||
uint16 _resp_p, uint16 _proto)
|
||||
{
|
||||
#ifdef BROv6
|
||||
// Use the IPv4-within-IPv6 convention, as this is what's
|
||||
// needed when we mix uint32's (like in this construction)
|
||||
// with addr_type's (for example, when looking up expected
|
||||
// connections).
|
||||
|
||||
orig[0] = orig[1] = orig[2] = 0;
|
||||
resp[0] = resp[1] = resp[2] = 0;
|
||||
orig[3] = _orig;
|
||||
resp[3] = _resp;
|
||||
#else
|
||||
orig[0] = _orig;
|
||||
resp[0] = _resp;
|
||||
#endif
|
||||
orig = _orig;
|
||||
resp = _resp;
|
||||
resp_p = _resp_p;
|
||||
proto = _proto;
|
||||
}
|
||||
|
||||
ExpectedConn::ExpectedConn(const ExpectedConn& c)
|
||||
{
|
||||
copy_addr(c.orig, orig);
|
||||
copy_addr(c.resp, resp);
|
||||
orig = c.orig;
|
||||
resp = c.resp;
|
||||
resp_p = c.resp_p;
|
||||
proto = c.proto;
|
||||
}
|
||||
|
||||
|
||||
DPM::DPM()
|
||||
: expected_conns_queue(AssignedAnalyzer::compare)
|
||||
{
|
||||
|
@ -99,7 +74,7 @@ void DPM::PostScriptInit()
|
|||
|
||||
void DPM::AddConfig(const Analyzer::Config& cfg)
|
||||
{
|
||||
#ifdef USE_PERFTOOLS
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
HeapLeakChecker::Disabler disabler;
|
||||
#endif
|
||||
|
||||
|
@ -158,23 +133,18 @@ AnalyzerTag::Tag DPM::GetExpected(int proto, const Connection* conn)
|
|||
ExpectedConn c(conn->OrigAddr(), conn->RespAddr(),
|
||||
ntohs(conn->RespPort()), proto);
|
||||
|
||||
// Can't use sizeof(c) due to potential alignment issues.
|
||||
// FIXME: I guess this is still not portable ...
|
||||
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) +
|
||||
sizeof(c.resp_p) + sizeof(c.proto));
|
||||
|
||||
AssignedAnalyzer* a = expected_conns.Lookup(&key);
|
||||
HashKey* key = BuildExpectedConnHashKey(c);
|
||||
AssignedAnalyzer* a = expected_conns.Lookup(key);
|
||||
delete key;
|
||||
|
||||
if ( ! a )
|
||||
{
|
||||
// Wildcard for originator.
|
||||
for ( int i = 0; i < NUM_ADDR_WORDS; ++i )
|
||||
c.orig[i] = 0;
|
||||
c.orig = IPAddr(string("::"));
|
||||
|
||||
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) +
|
||||
sizeof(c.resp_p) + sizeof(c.proto));
|
||||
|
||||
a = expected_conns.Lookup(&key);
|
||||
HashKey* key = BuildExpectedConnHashKey(c);
|
||||
a = expected_conns.Lookup(key);
|
||||
delete key;
|
||||
}
|
||||
|
||||
if ( ! a )
|
||||
|
@ -215,46 +185,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
|
|||
break;
|
||||
|
||||
case TRANSPORT_ICMP: {
|
||||
const struct icmp* icmpp = (const struct icmp *) data;
|
||||
switch ( icmpp->icmp_type ) {
|
||||
|
||||
case ICMP_ECHO:
|
||||
case ICMP_ECHOREPLY:
|
||||
if ( ICMP_Echo_Analyzer::Available() )
|
||||
{
|
||||
root = icmp = new ICMP_Echo_Analyzer(conn);
|
||||
DBG_DPD(conn, "activated ICMP Echo analyzer");
|
||||
}
|
||||
break;
|
||||
|
||||
case ICMP_REDIRECT:
|
||||
if ( ICMP_Redir_Analyzer::Available() )
|
||||
{
|
||||
root = new ICMP_Redir_Analyzer(conn);
|
||||
DBG_DPD(conn, "activated ICMP Redir analyzer");
|
||||
}
|
||||
break;
|
||||
|
||||
case ICMP_UNREACH:
|
||||
if ( ICMP_Unreachable_Analyzer::Available() )
|
||||
{
|
||||
root = icmp = new ICMP_Unreachable_Analyzer(conn);
|
||||
DBG_DPD(conn, "activated ICMP Unreachable analyzer");
|
||||
}
|
||||
break;
|
||||
|
||||
case ICMP_TIMXCEED:
|
||||
if ( ICMP_TimeExceeded_Analyzer::Available() )
|
||||
{
|
||||
root = icmp = new ICMP_TimeExceeded_Analyzer(conn);
|
||||
DBG_DPD(conn, "activated ICMP Time Exceeded analyzer");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! root )
|
||||
root = icmp = new ICMP_Analyzer(conn);
|
||||
|
||||
root = icmp = new ICMP_Analyzer(conn);
|
||||
DBG_DPD(conn, "activated ICMP analyzer");
|
||||
analyzed = true;
|
||||
break;
|
||||
}
|
||||
|
@ -404,7 +336,8 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn,
|
|||
return true;
|
||||
}
|
||||
|
||||
void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
|
||||
void DPM::ExpectConnection(const IPAddr& orig, const IPAddr& resp,
|
||||
uint16 resp_p,
|
||||
TransportProto proto, AnalyzerTag::Tag analyzer,
|
||||
double timeout, void* cookie)
|
||||
{
|
||||
|
@ -416,11 +349,7 @@ void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
|
|||
{
|
||||
if ( ! a->deleted )
|
||||
{
|
||||
HashKey* key = new HashKey(&a->conn,
|
||||
sizeof(a->conn.orig) +
|
||||
sizeof(a->conn.resp) +
|
||||
sizeof(a->conn.resp_p) +
|
||||
sizeof(a->conn.proto));
|
||||
HashKey* key = BuildExpectedConnHashKey(a->conn);
|
||||
expected_conns.Remove(key);
|
||||
delete key;
|
||||
}
|
||||
|
@ -439,10 +368,9 @@ void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
|
|||
|
||||
ExpectedConn c(orig, resp, resp_p, proto);
|
||||
|
||||
HashKey key(&c, sizeof(c.orig) + sizeof(c.resp) +
|
||||
sizeof(c.resp_p) + sizeof(c.proto));
|
||||
HashKey* key = BuildExpectedConnHashKey(c);
|
||||
|
||||
AssignedAnalyzer* a = expected_conns.Lookup(&key);
|
||||
AssignedAnalyzer* a = expected_conns.Lookup(key);
|
||||
|
||||
if ( a )
|
||||
a->deleted = true;
|
||||
|
@ -454,8 +382,9 @@ void DPM::ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
|
|||
a->timeout = network_time + timeout;
|
||||
a->deleted = false;
|
||||
|
||||
expected_conns.Insert(&key, a);
|
||||
expected_conns.Insert(key, a);
|
||||
expected_conns_queue.push(a);
|
||||
delete key;
|
||||
}
|
||||
|
||||
void DPM::Done()
|
||||
|
@ -466,11 +395,7 @@ void DPM::Done()
|
|||
AssignedAnalyzer* a = expected_conns_queue.top();
|
||||
if ( ! a->deleted )
|
||||
{
|
||||
HashKey* key = new HashKey(&a->conn,
|
||||
sizeof(a->conn.orig) +
|
||||
sizeof(a->conn.resp) +
|
||||
sizeof(a->conn.resp_p) +
|
||||
sizeof(a->conn.proto));
|
||||
HashKey* key = BuildExpectedConnHashKey(a->conn);
|
||||
expected_conns.Remove(key);
|
||||
delete key;
|
||||
}
|
||||
|
|
14
src/DPM.h
14
src/DPM.h
|
@ -27,19 +27,13 @@
|
|||
// Map to assign expected connections to analyzers.
|
||||
class ExpectedConn {
|
||||
public:
|
||||
// This form can be used for IPv6 as well as IPv4.
|
||||
ExpectedConn(const uint32* _orig, const uint32* _resp,
|
||||
ExpectedConn(const IPAddr& _orig, const IPAddr& _resp,
|
||||
uint16 _resp_p, uint16 _proto);
|
||||
|
||||
// This form only works for expecting an IPv4 connection. Note
|
||||
// that we do the right thing whether we're built IPv4-only or
|
||||
// BROv6.
|
||||
ExpectedConn(uint32 _orig, uint32 _resp, uint16 _resp_p, uint16 _proto);
|
||||
|
||||
ExpectedConn(const ExpectedConn& c);
|
||||
|
||||
uint32 orig[NUM_ADDR_WORDS];
|
||||
uint32 resp[NUM_ADDR_WORDS];
|
||||
IPAddr orig;
|
||||
IPAddr resp;
|
||||
uint16 resp_p;
|
||||
uint16 proto;
|
||||
};
|
||||
|
@ -90,7 +84,7 @@ public:
|
|||
// Schedules a particular analyzer for an upcoming connection.
|
||||
// 0 acts as a wildcard for orig. (Cookie is currently unused.
|
||||
// Eventually, we may pass it on to the analyzer).
|
||||
void ExpectConnection(addr_type orig, addr_type resp, uint16 resp_p,
|
||||
void ExpectConnection(const IPAddr& orig, const IPAddr& resp, uint16 resp_p,
|
||||
TransportProto proto, AnalyzerTag::Tag analyzer,
|
||||
double timeout, void* cookie);
|
||||
|
||||
|
|
23
src/Debug.cc
23
src/Debug.cc
|
@ -142,7 +142,7 @@ int TraceState::LogTrace(const char* fmt, ...)
|
|||
|
||||
if ( ! loc.filename )
|
||||
{
|
||||
loc.filename = "<no filename>";
|
||||
loc.filename = copy_string("<no filename>");
|
||||
loc.last_line = 0;
|
||||
}
|
||||
|
||||
|
@ -721,7 +721,6 @@ static char* get_prompt(bool reset_counter = false)
|
|||
|
||||
string get_context_description(const Stmt* stmt, const Frame* frame)
|
||||
{
|
||||
char buf[1024];
|
||||
ODesc d;
|
||||
const BroFunc* func = frame->GetFunction();
|
||||
|
||||
|
@ -735,14 +734,18 @@ string get_context_description(const Stmt* stmt, const Frame* frame)
|
|||
loc = *stmt->GetLocationInfo();
|
||||
else
|
||||
{
|
||||
loc.filename = "<no filename>";
|
||||
loc.filename = copy_string("<no filename>");
|
||||
loc.last_line = 0;
|
||||
}
|
||||
|
||||
safe_snprintf(buf, sizeof(buf), "In %s at %s:%d",
|
||||
size_t buf_size = strlen(d.Description()) + strlen(loc.filename) + 1024;
|
||||
char* buf = new char[buf_size];
|
||||
safe_snprintf(buf, buf_size, "In %s at %s:%d",
|
||||
d.Description(), loc.filename, loc.last_line);
|
||||
|
||||
return string(buf);
|
||||
string retval(buf);
|
||||
delete [] buf;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int dbg_handle_debug_input()
|
||||
|
@ -924,6 +927,8 @@ bool post_execute_stmt(Stmt* stmt, Frame* f, Val* result, stmt_flow_type* flow)
|
|||
// Evaluates the given expression in the context of the currently selected
|
||||
// frame. Returns the resulting value, or nil if none (or there was an error).
|
||||
Expr* g_curr_debug_expr = 0;
|
||||
const char* g_curr_debug_error = 0;
|
||||
bool in_debug = false;
|
||||
|
||||
// ### fix this hardwired access to external variables etc.
|
||||
struct yy_buffer_state;
|
||||
|
@ -969,6 +974,11 @@ Val* dbg_eval_expr(const char* expr)
|
|||
Val* result = 0;
|
||||
if ( yyparse() )
|
||||
{
|
||||
if ( g_curr_debug_error )
|
||||
debug_msg("Parsing expression '%s' failed: %s\n", expr, g_curr_debug_error);
|
||||
else
|
||||
debug_msg("Parsing expression '%s' failed\n", expr);
|
||||
|
||||
if ( g_curr_debug_expr )
|
||||
{
|
||||
delete g_curr_debug_expr;
|
||||
|
@ -983,6 +993,9 @@ Val* dbg_eval_expr(const char* expr)
|
|||
|
||||
delete g_curr_debug_expr;
|
||||
g_curr_debug_expr = 0;
|
||||
delete [] g_curr_debug_error;
|
||||
g_curr_debug_error = 0;
|
||||
in_debug = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -553,7 +553,8 @@ int dbg_cmd_print(DebugCmd cmd, const vector<string>& args)
|
|||
for ( int i = 0; i < int(args.size()); ++i )
|
||||
{
|
||||
expr += args[i];
|
||||
expr += " ";
|
||||
if ( i < int(args.size()) - 1 )
|
||||
expr += " ";
|
||||
}
|
||||
|
||||
Val* val = dbg_eval_expr(expr.c_str());
|
||||
|
@ -566,8 +567,7 @@ int dbg_cmd_print(DebugCmd cmd, const vector<string>& args)
|
|||
}
|
||||
else
|
||||
{
|
||||
// ### Print something?
|
||||
// debug_msg("<expression has no value>\n");
|
||||
debug_msg("<expression has no value>\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -15,7 +15,8 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] = {
|
|||
{ "compressor", 0, false }, {"string", 0, false },
|
||||
{ "notifiers", 0, false }, { "main-loop", 0, false },
|
||||
{ "dpd", 0, false }, { "tm", 0, false },
|
||||
{ "logging", 0, false }
|
||||
{ "logging", 0, false }, {"input", 0, false },
|
||||
{ "threading", 0, false }
|
||||
};
|
||||
|
||||
DebugLogger::DebugLogger(const char* filename)
|
||||
|
|
|
@ -24,6 +24,8 @@ enum DebugStream {
|
|||
DBG_DPD, // Dynamic application detection framework
|
||||
DBG_TM, // Time-machine packet input via Brocolli
|
||||
DBG_LOGGING, // Logging streams
|
||||
DBG_INPUT, // Input streams
|
||||
DBG_THREADING, // Threading system
|
||||
|
||||
NUM_DBGS // Has to be last
|
||||
};
|
||||
|
|
90
src/Desc.cc
90
src/Desc.cc
|
@ -41,8 +41,7 @@ ODesc::ODesc(desc_type t, BroFile* arg_f)
|
|||
do_flush = 1;
|
||||
include_stats = 0;
|
||||
indent_with_spaces = 0;
|
||||
escape = 0;
|
||||
escape_len = 0;
|
||||
escape = false;
|
||||
}
|
||||
|
||||
ODesc::~ODesc()
|
||||
|
@ -56,10 +55,9 @@ ODesc::~ODesc()
|
|||
free(base);
|
||||
}
|
||||
|
||||
void ODesc::SetEscape(const char* arg_escape, int len)
|
||||
void ODesc::EnableEscaping()
|
||||
{
|
||||
escape = arg_escape;
|
||||
escape_len = len;
|
||||
escape = true;
|
||||
}
|
||||
|
||||
void ODesc::PushIndent()
|
||||
|
@ -159,6 +157,16 @@ void ODesc::Add(double d)
|
|||
}
|
||||
}
|
||||
|
||||
void ODesc::Add(const IPAddr& addr)
|
||||
{
|
||||
Add(addr.AsString());
|
||||
}
|
||||
|
||||
void ODesc::Add(const IPPrefix& prefix)
|
||||
{
|
||||
Add(prefix.AsString());
|
||||
}
|
||||
|
||||
void ODesc::AddCS(const char* s)
|
||||
{
|
||||
int n = strlen(s);
|
||||
|
@ -228,6 +236,25 @@ static const char* find_first_unprintable(ODesc* d, const char* bytes, unsigned
|
|||
return 0;
|
||||
}
|
||||
|
||||
pair<const char*, size_t> ODesc::FirstEscapeLoc(const char* bytes, size_t n)
|
||||
{
|
||||
pair<const char*, size_t> p(find_first_unprintable(this, bytes, n), 1);
|
||||
|
||||
string str(bytes, n);
|
||||
list<string>::const_iterator it;
|
||||
for ( it = escape_sequences.begin(); it != escape_sequences.end(); ++it )
|
||||
{
|
||||
size_t pos = str.find(*it);
|
||||
if ( pos != string::npos && (p.first == 0 || bytes + pos < p.first) )
|
||||
{
|
||||
p.first = bytes + pos;
|
||||
p.second = it->size();
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void ODesc::AddBytes(const void* bytes, unsigned int n)
|
||||
{
|
||||
if ( ! escape )
|
||||
|
@ -241,45 +268,30 @@ void ODesc::AddBytes(const void* bytes, unsigned int n)
|
|||
|
||||
while ( s < e )
|
||||
{
|
||||
const char* t1 = (const char*) memchr(s, escape[0], e - s);
|
||||
|
||||
if ( ! t1 )
|
||||
t1 = e;
|
||||
|
||||
const char* t2 = find_first_unprintable(this, s, t1 - s);
|
||||
|
||||
if ( t2 && t2 < t1 )
|
||||
pair<const char*, size_t> p = FirstEscapeLoc(s, e - s);
|
||||
if ( p.first )
|
||||
{
|
||||
AddBytesRaw(s, t2 - s);
|
||||
|
||||
char hex[6] = "\\x00";
|
||||
hex[2] = hex_chars[((*t2) & 0xf0) >> 4];
|
||||
hex[3] = hex_chars[(*t2) & 0x0f];
|
||||
AddBytesRaw(hex, 4);
|
||||
|
||||
s = t2 + 1;
|
||||
continue;
|
||||
AddBytesRaw(s, p.first - s);
|
||||
if ( p.second == 1 )
|
||||
{
|
||||
char hex[6] = "\\x00";
|
||||
hex[2] = hex_chars[((*p.first) & 0xf0) >> 4];
|
||||
hex[3] = hex_chars[(*p.first) & 0x0f];
|
||||
AddBytesRaw(hex, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
string esc_str = get_escaped_string(string(p.first, p.second), true);
|
||||
AddBytesRaw(esc_str.c_str(), esc_str.size());
|
||||
}
|
||||
s = p.first + p.second;
|
||||
}
|
||||
|
||||
if ( memcmp(t1, escape, escape_len) != 0 )
|
||||
break;
|
||||
|
||||
AddBytesRaw(s, t1 - s);
|
||||
|
||||
for ( int i = 0; i < escape_len; ++i )
|
||||
else
|
||||
{
|
||||
char hex[5] = "\\x00";
|
||||
hex[2] = hex_chars[((*t1) & 0xf0) >> 4];
|
||||
hex[3] = hex_chars[(*t1) & 0x0f];
|
||||
AddBytesRaw(hex, 4);
|
||||
++t1;
|
||||
AddBytesRaw(s, e - s);
|
||||
break;
|
||||
}
|
||||
|
||||
s = t1;
|
||||
}
|
||||
|
||||
if ( s < e )
|
||||
AddBytesRaw(s, e - s);
|
||||
}
|
||||
|
||||
void ODesc::AddBytesRaw(const void* bytes, unsigned int n)
|
||||
|
|
34
src/Desc.h
34
src/Desc.h
|
@ -4,6 +4,9 @@
|
|||
#define descriptor_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
|
||||
#include "BroString.h"
|
||||
|
||||
typedef enum {
|
||||
|
@ -19,6 +22,8 @@ typedef enum {
|
|||
} desc_style;
|
||||
|
||||
class BroFile;
|
||||
class IPAddr;
|
||||
class IPPrefix;
|
||||
|
||||
class ODesc {
|
||||
public:
|
||||
|
@ -48,8 +53,13 @@ public:
|
|||
|
||||
void SetFlush(int arg_do_flush) { do_flush = arg_do_flush; }
|
||||
|
||||
// The string passed in must remain valid as long as this object lives.
|
||||
void SetEscape(const char* escape, int len);
|
||||
void EnableEscaping();
|
||||
void AddEscapeSequence(const char* s) { escape_sequences.push_back(s); }
|
||||
void AddEscapeSequence(const char* s, size_t n)
|
||||
{ escape_sequences.push_back(string(s, n)); }
|
||||
void RemoveEscapeSequence(const char* s) { escape_sequences.remove(s); }
|
||||
void RemoveEscapeSequence(const char* s, size_t n)
|
||||
{ escape_sequences.remove(string(s, n)); }
|
||||
|
||||
void PushIndent();
|
||||
void PopIndent();
|
||||
|
@ -61,11 +71,14 @@ public:
|
|||
|
||||
void Add(const char* s, int do_indent=1);
|
||||
void AddN(const char* s, int len) { AddBytes(s, len); }
|
||||
void Add(const string& s) { AddBytes(s.data(), s.size()); }
|
||||
void Add(int i);
|
||||
void Add(uint32 u);
|
||||
void Add(int64 i);
|
||||
void Add(uint64 u);
|
||||
void Add(double d);
|
||||
void Add(const IPAddr& addr);
|
||||
void Add(const IPPrefix& prefix);
|
||||
|
||||
// Add s as a counted string.
|
||||
void AddCS(const char* s);
|
||||
|
@ -133,6 +146,19 @@ protected:
|
|||
|
||||
void OutOfMemory();
|
||||
|
||||
/**
|
||||
* Returns the location of the first place in the bytes to be hex-escaped.
|
||||
*
|
||||
* @param bytes the starting memory address to start searching for
|
||||
* escapable character.
|
||||
* @param n the maximum number of bytes to search.
|
||||
* @return a pair whose first element represents a starting memory address
|
||||
* to be escaped up to the number of characters indicated by the
|
||||
* second element. The first element may be 0 if nothing is
|
||||
* to be escaped.
|
||||
*/
|
||||
pair<const char*, size_t> FirstEscapeLoc(const char* bytes, size_t n);
|
||||
|
||||
desc_type type;
|
||||
desc_style style;
|
||||
|
||||
|
@ -140,8 +166,8 @@ protected:
|
|||
unsigned int offset; // where we are in the buffer
|
||||
unsigned int size; // size of buffer in bytes
|
||||
|
||||
int escape_len; // number of bytes in to escape sequence
|
||||
const char* escape; // bytes to escape on output
|
||||
bool escape; // escape unprintable characters in output?
|
||||
list<string> escape_sequences; // additional sequences of chars to escape
|
||||
|
||||
BroFile* f; // or the file we're using.
|
||||
|
||||
|
|
|
@ -10,11 +10,6 @@
|
|||
|
||||
Discarder::Discarder()
|
||||
{
|
||||
ip_hdr = internal_type("ip_hdr")->AsRecordType();
|
||||
tcp_hdr = internal_type("tcp_hdr")->AsRecordType();
|
||||
udp_hdr = internal_type("udp_hdr")->AsRecordType();
|
||||
icmp_hdr = internal_type("icmp_hdr")->AsRecordType();
|
||||
|
||||
check_ip = internal_func("discarder_check_ip");
|
||||
check_tcp = internal_func("discarder_check_tcp");
|
||||
check_udp = internal_func("discarder_check_udp");
|
||||
|
@ -36,12 +31,10 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
|
|||
{
|
||||
int discard_packet = 0;
|
||||
|
||||
const struct ip* ip4 = ip->IP4_Hdr();
|
||||
|
||||
if ( check_ip )
|
||||
{
|
||||
val_list* args = new val_list;
|
||||
args->append(BuildHeader(ip4));
|
||||
args->append(ip->BuildPktHdrVal());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -59,19 +52,18 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
|
|||
return discard_packet;
|
||||
}
|
||||
|
||||
int proto = ip4->ip_p;
|
||||
int proto = ip->NextProto();
|
||||
if ( proto != IPPROTO_TCP && proto != IPPROTO_UDP &&
|
||||
proto != IPPROTO_ICMP )
|
||||
// This is not a protocol we understand.
|
||||
return 0;
|
||||
|
||||
// XXX shall we only check the first packet???
|
||||
uint32 frag_field = ntohs(ip4->ip_off);
|
||||
if ( (frag_field & 0x3fff) != 0 )
|
||||
if ( ip->IsFragment() )
|
||||
// Never check any fragment.
|
||||
return 0;
|
||||
|
||||
int ip_hdr_len = ip4->ip_hl * 4;
|
||||
int ip_hdr_len = ip->HdrLen();
|
||||
len -= ip_hdr_len; // remove IP header
|
||||
caplen -= ip_hdr_len;
|
||||
|
||||
|
@ -87,7 +79,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
|
|||
|
||||
// Where the data starts - if this is a protocol we know about,
|
||||
// this gets advanced past the transport header.
|
||||
const u_char* data = ((u_char*) ip4 + ip_hdr_len);
|
||||
const u_char* data = ip->Payload();
|
||||
|
||||
if ( is_tcp )
|
||||
{
|
||||
|
@ -97,8 +89,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
|
|||
int th_len = tp->th_off * 4;
|
||||
|
||||
val_list* args = new val_list;
|
||||
args->append(BuildHeader(ip4));
|
||||
args->append(BuildHeader(tp, len));
|
||||
args->append(ip->BuildPktHdrVal());
|
||||
args->append(BuildData(data, th_len, len, caplen));
|
||||
|
||||
try
|
||||
|
@ -123,8 +114,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
|
|||
int uh_len = sizeof (struct udphdr);
|
||||
|
||||
val_list* args = new val_list;
|
||||
args->append(BuildHeader(ip4));
|
||||
args->append(BuildHeader(up));
|
||||
args->append(ip->BuildPktHdrVal());
|
||||
args->append(BuildData(data, uh_len, len, caplen));
|
||||
|
||||
try
|
||||
|
@ -148,8 +138,7 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
|
|||
const struct icmp* ih = (const struct icmp*) data;
|
||||
|
||||
val_list* args = new val_list;
|
||||
args->append(BuildHeader(ip4));
|
||||
args->append(BuildHeader(ih));
|
||||
args->append(ip->BuildPktHdrVal());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -168,62 +157,6 @@ int Discarder::NextPacket(const IP_Hdr* ip, int len, int caplen)
|
|||
return discard_packet;
|
||||
}
|
||||
|
||||
Val* Discarder::BuildHeader(const struct ip* ip)
|
||||
{
|
||||
RecordVal* hdr = new RecordVal(ip_hdr);
|
||||
|
||||
hdr->Assign(0, new Val(ip->ip_hl * 4, TYPE_COUNT));
|
||||
hdr->Assign(1, new Val(ip->ip_tos, TYPE_COUNT));
|
||||
hdr->Assign(2, new Val(ntohs(ip->ip_len), TYPE_COUNT));
|
||||
hdr->Assign(3, new Val(ntohs(ip->ip_id), TYPE_COUNT));
|
||||
hdr->Assign(4, new Val(ip->ip_ttl, TYPE_COUNT));
|
||||
hdr->Assign(5, new Val(ip->ip_p, TYPE_COUNT));
|
||||
hdr->Assign(6, new AddrVal(ip->ip_src.s_addr));
|
||||
hdr->Assign(7, new AddrVal(ip->ip_dst.s_addr));
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
Val* Discarder::BuildHeader(const struct tcphdr* tp, int tcp_len)
|
||||
{
|
||||
RecordVal* hdr = new RecordVal(tcp_hdr);
|
||||
|
||||
hdr->Assign(0, new PortVal(ntohs(tp->th_sport), TRANSPORT_TCP));
|
||||
hdr->Assign(1, new PortVal(ntohs(tp->th_dport), TRANSPORT_TCP));
|
||||
hdr->Assign(2, new Val(uint32(ntohl(tp->th_seq)), TYPE_COUNT));
|
||||
hdr->Assign(3, new Val(uint32(ntohl(tp->th_ack)), TYPE_COUNT));
|
||||
|
||||
int tcp_hdr_len = tp->th_off * 4;
|
||||
|
||||
hdr->Assign(4, new Val(tcp_hdr_len, TYPE_COUNT));
|
||||
hdr->Assign(5, new Val(tcp_len - tcp_hdr_len, TYPE_COUNT));
|
||||
|
||||
hdr->Assign(6, new Val(tp->th_flags, TYPE_COUNT));
|
||||
hdr->Assign(7, new Val(ntohs(tp->th_win), TYPE_COUNT));
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
Val* Discarder::BuildHeader(const struct udphdr* up)
|
||||
{
|
||||
RecordVal* hdr = new RecordVal(udp_hdr);
|
||||
|
||||
hdr->Assign(0, new PortVal(ntohs(up->uh_sport), TRANSPORT_UDP));
|
||||
hdr->Assign(1, new PortVal(ntohs(up->uh_dport), TRANSPORT_UDP));
|
||||
hdr->Assign(2, new Val(ntohs(up->uh_ulen), TYPE_COUNT));
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
Val* Discarder::BuildHeader(const struct icmp* icmp)
|
||||
{
|
||||
RecordVal* hdr = new RecordVal(icmp_hdr);
|
||||
|
||||
hdr->Assign(0, new Val(icmp->icmp_type, TYPE_COUNT));
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
Val* Discarder::BuildData(const u_char* data, int hdrlen, int len, int caplen)
|
||||
{
|
||||
len -= hdrlen;
|
||||
|
|
|
@ -25,17 +25,8 @@ public:
|
|||
int NextPacket(const IP_Hdr* ip, int len, int caplen);
|
||||
|
||||
protected:
|
||||
Val* BuildHeader(const struct ip* ip);
|
||||
Val* BuildHeader(const struct tcphdr* tp, int tcp_len);
|
||||
Val* BuildHeader(const struct udphdr* up);
|
||||
Val* BuildHeader(const struct icmp* icmp);
|
||||
Val* BuildData(const u_char* data, int hdrlen, int len, int caplen);
|
||||
|
||||
RecordType* ip_hdr;
|
||||
RecordType* tcp_hdr;
|
||||
RecordType* udp_hdr;
|
||||
RecordType* icmp_hdr;
|
||||
|
||||
Func* check_ip;
|
||||
Func* check_tcp;
|
||||
Func* check_udp;
|
||||
|
|
|
@ -96,7 +96,7 @@ EventHandler* EventHandler::Unserialize(UnserialInfo* info)
|
|||
{
|
||||
char* name;
|
||||
if ( ! UNSERIALIZE_STR(&name, 0) )
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
EventHandler* h = event_registry->Lookup(name);
|
||||
if ( ! h )
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "List.h"
|
||||
#include "BroList.h"
|
||||
#include "net_util.h"
|
||||
|
||||
class Func;
|
||||
class FuncType;
|
||||
|
|
252
src/Expr.cc
252
src/Expr.cc
|
@ -14,6 +14,7 @@
|
|||
#include "Net.h"
|
||||
#include "Traverse.h"
|
||||
#include "Trigger.h"
|
||||
#include "IPAddr.h"
|
||||
|
||||
const char* expr_name(BroExprTag t)
|
||||
{
|
||||
|
@ -359,7 +360,7 @@ bool NameExpr::DoUnserialize(UnserialInfo* info)
|
|||
if ( id )
|
||||
::Ref(id);
|
||||
else
|
||||
reporter->Warning("unserialized unknown global name");
|
||||
reporter->Warning("configuration changed: unserialized unknown global name from persistent state");
|
||||
|
||||
delete [] name;
|
||||
}
|
||||
|
@ -834,30 +835,30 @@ Val* BinaryExpr::StringFold(Val* v1, Val* v2) const
|
|||
|
||||
Val* BinaryExpr::AddrFold(Val* v1, Val* v2) const
|
||||
{
|
||||
addr_type a1 = v1->AsAddr();
|
||||
addr_type a2 = v2->AsAddr();
|
||||
IPAddr a1 = v1->AsAddr();
|
||||
IPAddr a2 = v2->AsAddr();
|
||||
int result = 0;
|
||||
|
||||
switch ( tag ) {
|
||||
#undef DO_FOLD
|
||||
#ifdef BROv6
|
||||
#define DO_FOLD(sense) { result = memcmp(a1, a2, 16) sense 0; break; }
|
||||
#else
|
||||
#define DO_FOLD(sense) \
|
||||
{ \
|
||||
a1 = ntohl(a1); \
|
||||
a2 = ntohl(a2); \
|
||||
result = (a1 < a2 ? -1 : (a1 == a2 ? 0 : 1)) sense 0; \
|
||||
break; \
|
||||
}
|
||||
#endif
|
||||
|
||||
case EXPR_LT: DO_FOLD(<)
|
||||
case EXPR_LE: DO_FOLD(<=)
|
||||
case EXPR_EQ: DO_FOLD(==)
|
||||
case EXPR_NE: DO_FOLD(!=)
|
||||
case EXPR_GE: DO_FOLD(>=)
|
||||
case EXPR_GT: DO_FOLD(>)
|
||||
case EXPR_LT:
|
||||
result = a1 < a2;
|
||||
break;
|
||||
case EXPR_LE:
|
||||
result = a1 < a2 || a1 == a2;
|
||||
break;
|
||||
case EXPR_EQ:
|
||||
result = a1 == a2;
|
||||
break;
|
||||
case EXPR_NE:
|
||||
result = a1 != a2;
|
||||
break;
|
||||
case EXPR_GE:
|
||||
result = ! ( a1 < a2 );
|
||||
break;
|
||||
case EXPR_GT:
|
||||
result = ( ! ( a1 < a2 ) ) && ( a1 != a2 );
|
||||
break;
|
||||
|
||||
default:
|
||||
BadTag("BinaryExpr::AddrFold", expr_name(tag));
|
||||
|
@ -868,20 +869,15 @@ Val* BinaryExpr::AddrFold(Val* v1, Val* v2) const
|
|||
|
||||
Val* BinaryExpr::SubNetFold(Val* v1, Val* v2) const
|
||||
{
|
||||
subnet_type* n1 = v1->AsSubNet();
|
||||
subnet_type* n2 = v2->AsSubNet();
|
||||
const IPPrefix& n1 = v1->AsSubNet();
|
||||
const IPPrefix& n2 = v2->AsSubNet();
|
||||
|
||||
if ( n1->width != n2->width )
|
||||
return new Val(0, TYPE_BOOL);
|
||||
bool result = ( n1 == n2 ) ? true : false;
|
||||
|
||||
#ifdef BROv6
|
||||
if ( memcmp(n1->net, n2->net, 16) )
|
||||
#else
|
||||
if ( n1->net != n2->net )
|
||||
#endif
|
||||
return new Val(0, TYPE_BOOL);
|
||||
if ( tag == EXPR_NE )
|
||||
result = ! result;
|
||||
|
||||
return new Val(1, TYPE_BOOL);
|
||||
return new Val(result, TYPE_BOOL);
|
||||
}
|
||||
|
||||
void BinaryExpr::SwapOps()
|
||||
|
@ -1041,12 +1037,10 @@ Val* IncrExpr::Eval(Frame* f) const
|
|||
{
|
||||
Val* new_elt = DoSingleEval(f, elt);
|
||||
v_vec->Assign(i, new_elt, this, OP_INCR);
|
||||
Unref(new_elt); // was Ref()'d by Assign()
|
||||
}
|
||||
else
|
||||
v_vec->Assign(i, 0, this, OP_INCR);
|
||||
}
|
||||
// FIXME: Is the next line needed?
|
||||
op->Assign(f, v_vec, OP_INCR);
|
||||
}
|
||||
|
||||
|
@ -1523,6 +1517,8 @@ RemoveFromExpr::RemoveFromExpr(Expr* arg_op1, Expr* arg_op2)
|
|||
|
||||
if ( BothArithmetic(bt1, bt2) )
|
||||
PromoteType(max_type(bt1, bt2), is_vector(op1) || is_vector(op2));
|
||||
else if ( BothInterval(bt1, bt2) )
|
||||
SetType(base_type(bt1));
|
||||
else
|
||||
ExprError("requires two arithmetic operands");
|
||||
}
|
||||
|
@ -1681,15 +1677,13 @@ DivideExpr::DivideExpr(Expr* arg_op1, Expr* arg_op2)
|
|||
|
||||
Val* DivideExpr::AddrFold(Val* v1, Val* v2) const
|
||||
{
|
||||
addr_type a1 = v1->AsAddr();
|
||||
|
||||
uint32 mask;
|
||||
if ( v2->Type()->Tag() == TYPE_COUNT )
|
||||
mask = static_cast<uint32>(v2->InternalUnsigned());
|
||||
else
|
||||
mask = static_cast<uint32>(v2->InternalInt());
|
||||
|
||||
return new SubNetVal(a1, mask);
|
||||
return new SubNetVal(v1->AsAddr(), mask);
|
||||
}
|
||||
|
||||
Expr* DivideExpr::DoSimplify()
|
||||
|
@ -2410,11 +2404,6 @@ Expr* RefExpr::MakeLvalue()
|
|||
return this;
|
||||
}
|
||||
|
||||
Val* RefExpr::Eval(Val* v) const
|
||||
{
|
||||
return Fold(v);
|
||||
}
|
||||
|
||||
void RefExpr::Assign(Frame* f, Val* v, Opcode opcode)
|
||||
{
|
||||
op->Assign(f, v, opcode);
|
||||
|
@ -2435,7 +2424,7 @@ bool RefExpr::DoUnserialize(UnserialInfo* info)
|
|||
}
|
||||
|
||||
AssignExpr::AssignExpr(Expr* arg_op1, Expr* arg_op2, int arg_is_init,
|
||||
Val* arg_val)
|
||||
Val* arg_val, attr_list* arg_attrs)
|
||||
: BinaryExpr(EXPR_ASSIGN,
|
||||
arg_is_init ? arg_op1 : arg_op1->MakeLvalue(), arg_op2)
|
||||
{
|
||||
|
@ -2455,14 +2444,14 @@ AssignExpr::AssignExpr(Expr* arg_op1, Expr* arg_op2, int arg_is_init,
|
|||
|
||||
// We discard the status from TypeCheck since it has already
|
||||
// generated error messages.
|
||||
(void) TypeCheck();
|
||||
(void) TypeCheck(arg_attrs);
|
||||
|
||||
val = arg_val ? arg_val->Ref() : 0;
|
||||
|
||||
SetLocationInfo(arg_op1->GetLocationInfo(), arg_op2->GetLocationInfo());
|
||||
}
|
||||
|
||||
bool AssignExpr::TypeCheck()
|
||||
bool AssignExpr::TypeCheck(attr_list* attrs)
|
||||
{
|
||||
TypeTag bt1 = op1->Type()->Tag();
|
||||
TypeTag bt2 = op2->Type()->Tag();
|
||||
|
@ -2494,6 +2483,21 @@ bool AssignExpr::TypeCheck()
|
|||
return true;
|
||||
}
|
||||
|
||||
if ( bt1 == TYPE_TABLE && op2->Tag() == EXPR_LIST )
|
||||
{
|
||||
attr_list* attr_copy = 0;
|
||||
|
||||
if ( attrs )
|
||||
{
|
||||
attr_copy = new attr_list;
|
||||
loop_over_list(*attrs, i)
|
||||
attr_copy->append((*attrs)[i]);
|
||||
}
|
||||
|
||||
op2 = new TableConstructorExpr(op2->AsListExpr(), attr_copy);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( bt1 == TYPE_VECTOR && bt2 == bt1 &&
|
||||
op2->Type()->AsVectorType()->IsUnspecifiedVector() )
|
||||
{
|
||||
|
@ -2657,8 +2661,6 @@ void AssignExpr::EvalIntoAggregate(const BroType* t, Val* aggr, Frame* f) const
|
|||
Error("bad table insertion");
|
||||
|
||||
TableVal* tv = aggr->AsTableVal();
|
||||
const TableType* tt = tv->Type()->AsTableType();
|
||||
const BroType* yt = tv->Type()->YieldType();
|
||||
|
||||
Val* index = op1->Eval(f);
|
||||
Val* v = op2->Eval(f);
|
||||
|
@ -3628,151 +3630,6 @@ bool FieldAssignExpr::DoUnserialize(UnserialInfo* info)
|
|||
return true;
|
||||
}
|
||||
|
||||
RecordMatchExpr::RecordMatchExpr(Expr* op1 /* record to match */,
|
||||
Expr* op2 /* cases to match against */)
|
||||
: BinaryExpr(EXPR_MATCH, op1, op2)
|
||||
{
|
||||
BroType* result_type = 0;
|
||||
|
||||
// Make sure the second argument is of a suitable type.
|
||||
if ( ! op2->Type()->IsSet() )
|
||||
{
|
||||
ExprError("matching must be done against a set of match records");
|
||||
return;
|
||||
}
|
||||
|
||||
type_list* elt_types = op2->Type()->AsSetType()->Indices()->Types();
|
||||
|
||||
if ( ! elt_types->length() ||
|
||||
(*elt_types)[0]->Tag() != TYPE_RECORD )
|
||||
{
|
||||
ExprError("matching must be done against a set of match records");
|
||||
return;
|
||||
}
|
||||
|
||||
RecordType* case_rec_type = (*elt_types)[0]->AsRecordType();
|
||||
|
||||
// NOTE: The "result" and "pred" field names are hardcoded here.
|
||||
result_field_index = case_rec_type->FieldOffset("result");
|
||||
|
||||
if ( result_field_index < 0 )
|
||||
{
|
||||
ExprError("match records must have a $result field");
|
||||
return;
|
||||
}
|
||||
|
||||
result_type = case_rec_type->FieldType("result")->Ref();
|
||||
|
||||
// Check that pred exists, and that the first argument matches it.
|
||||
if ( (pred_field_index = case_rec_type->FieldOffset("pred")) < 0 ||
|
||||
case_rec_type->FieldType("pred")->Tag() != TYPE_FUNC )
|
||||
{
|
||||
ExprError("match records must have a $pred' field of function type");
|
||||
return;
|
||||
}
|
||||
|
||||
FuncType* pred_type = case_rec_type->FieldType("pred")->AsFuncType();
|
||||
type_list* pred_arg_types = pred_type->ArgTypes()->Types();
|
||||
if ( pred_arg_types->length() != 1 ||
|
||||
! check_and_promote_expr(op1, (*pred_arg_types)[0]) )
|
||||
ExprError("record to match does not have the same type as predicate argument");
|
||||
|
||||
// NOTE: The "priority" field name is hardcoded here.
|
||||
if ( (priority_field_index = case_rec_type->FieldOffset("priority")) >= 0 &&
|
||||
! IsArithmetic(case_rec_type->FieldType("priority")->Tag()) )
|
||||
ExprError("$priority field must have a numeric type");
|
||||
|
||||
SetType(result_type);
|
||||
}
|
||||
|
||||
void RecordMatchExpr::ExprDescribe(ODesc* d) const
|
||||
{
|
||||
if ( d->IsReadable() )
|
||||
{
|
||||
d->Add("match ");
|
||||
op1->Describe(d);
|
||||
d->Add(" using ");
|
||||
op2->Describe(d);
|
||||
}
|
||||
}
|
||||
|
||||
Val* RecordMatchExpr::Fold(Val* v1, Val* v2) const
|
||||
{
|
||||
TableVal* match_set = v2->AsTableVal();
|
||||
if ( ! match_set )
|
||||
Internal("non-table in RecordMatchExpr");
|
||||
|
||||
Val* return_val = 0;
|
||||
double highest_priority = -1e100;
|
||||
|
||||
ListVal* match_recs = match_set->ConvertToList(TYPE_ANY);
|
||||
for ( int i = 0; i < match_recs->Length(); ++i )
|
||||
{
|
||||
val_list args(1);
|
||||
args.append(v1->Ref());
|
||||
|
||||
double this_priority = 0;
|
||||
|
||||
// ### Get rid of the double Index if TYPE_ANY->TYPE_RECORD.
|
||||
Val* v = match_recs->Index(i)->AsListVal()->Index(0);
|
||||
|
||||
const RecordVal* match_rec = v->AsRecordVal();
|
||||
if ( ! match_rec )
|
||||
Internal("Element of match set is not a record");
|
||||
|
||||
if ( priority_field_index >= 0 )
|
||||
{
|
||||
this_priority =
|
||||
match_rec->Lookup(priority_field_index)->CoerceToDouble();
|
||||
if ( this_priority <= highest_priority )
|
||||
{
|
||||
Unref(v1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// No try/catch here; we pass exceptions upstream.
|
||||
Val* pred_val =
|
||||
match_rec->Lookup(pred_field_index)->AsFunc()->Call(&args);
|
||||
bool is_zero = pred_val->IsZero();
|
||||
Unref(pred_val);
|
||||
|
||||
if ( ! is_zero )
|
||||
{
|
||||
Val* new_return_val =
|
||||
match_rec->Lookup(result_field_index);
|
||||
|
||||
Unref(return_val);
|
||||
return_val = new_return_val->Ref();
|
||||
|
||||
if ( priority_field_index >= 0 )
|
||||
highest_priority = this_priority;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Unref(match_recs);
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(RecordMatchExpr, SER_RECORD_MATCH_EXPR);
|
||||
|
||||
bool RecordMatchExpr::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_RECORD_MATCH_EXPR, BinaryExpr);
|
||||
return SERIALIZE(pred_field_index) && SERIALIZE(result_field_index) &&
|
||||
SERIALIZE(priority_field_index);
|
||||
}
|
||||
|
||||
bool RecordMatchExpr::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(BinaryExpr);
|
||||
return UNSERIALIZE(&pred_field_index) && UNSERIALIZE(&result_field_index) &&
|
||||
UNSERIALIZE(&priority_field_index);
|
||||
}
|
||||
|
||||
ArithCoerceExpr::ArithCoerceExpr(Expr* arg_op, TypeTag t)
|
||||
: UnaryExpr(EXPR_ARITH_COERCE, arg_op)
|
||||
{
|
||||
|
@ -4053,7 +3910,15 @@ Val* RecordCoerceExpr::Fold(Val* v) const
|
|||
val->Assign(i, rhs);
|
||||
}
|
||||
else
|
||||
val->Assign(i, 0);
|
||||
{
|
||||
const Attr* def =
|
||||
Type()->AsRecordType()->FieldDecl(i)->FindAttr(ATTR_DEFAULT);
|
||||
|
||||
if ( def )
|
||||
val->Assign(i, def->AttrExpr()->Eval(0));
|
||||
else
|
||||
val->Assign(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
|
@ -4895,6 +4760,7 @@ Val* ListExpr::Eval(Frame* f) const
|
|||
if ( ! ev )
|
||||
{
|
||||
Error("uninitialized list value");
|
||||
Unref(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
34
src/Expr.h
34
src/Expr.h
|
@ -608,10 +608,6 @@ public:
|
|||
void Assign(Frame* f, Val* v, Opcode op = OP_ASSIGN);
|
||||
Expr* MakeLvalue();
|
||||
|
||||
// Only overridden to avoid special vector handling which doesn't apply
|
||||
// for this class.
|
||||
Val* Eval(Val* v) const;
|
||||
|
||||
protected:
|
||||
friend class Expr;
|
||||
RefExpr() { }
|
||||
|
@ -623,7 +619,7 @@ class AssignExpr : public BinaryExpr {
|
|||
public:
|
||||
// If val is given, evaluating this expression will always yield the val
|
||||
// yet still perform the assignment. Used for triggers.
|
||||
AssignExpr(Expr* op1, Expr* op2, int is_init, Val* val = 0);
|
||||
AssignExpr(Expr* op1, Expr* op2, int is_init, Val* val = 0, attr_list* attrs = 0);
|
||||
virtual ~AssignExpr() { Unref(val); }
|
||||
|
||||
Expr* Simplify(SimplifyType simp_type);
|
||||
|
@ -638,7 +634,7 @@ protected:
|
|||
friend class Expr;
|
||||
AssignExpr() { }
|
||||
|
||||
bool TypeCheck();
|
||||
bool TypeCheck(attr_list* attrs = 0);
|
||||
bool TypeCheckArithmetics(TypeTag bt1, TypeTag bt2);
|
||||
|
||||
DECLARE_SERIAL(AssignExpr);
|
||||
|
@ -823,32 +819,6 @@ protected:
|
|||
string field_name;
|
||||
};
|
||||
|
||||
class RecordMatchExpr : public BinaryExpr {
|
||||
public:
|
||||
RecordMatchExpr(Expr* op1 /* record to match */,
|
||||
Expr* op2 /* cases to match against */);
|
||||
|
||||
protected:
|
||||
friend class Expr;
|
||||
RecordMatchExpr()
|
||||
{
|
||||
pred_field_index = result_field_index =
|
||||
priority_field_index = 0;
|
||||
}
|
||||
|
||||
virtual Val* Fold(Val* v1, Val* v2) const;
|
||||
void ExprDescribe(ODesc*) const;
|
||||
|
||||
DECLARE_SERIAL(RecordMatchExpr);
|
||||
|
||||
// The following are used to hold the field offset of
|
||||
// $pred, $result, $priority, so the names only need to
|
||||
// be looked up at compile-time.
|
||||
int pred_field_index;
|
||||
int result_field_index;
|
||||
int priority_field_index;
|
||||
};
|
||||
|
||||
class ArithCoerceExpr : public UnaryExpr {
|
||||
public:
|
||||
ArithCoerceExpr(Expr* op, TypeTag t);
|
||||
|
|
177
src/FTP.cc
177
src/FTP.cc
|
@ -8,6 +8,8 @@
|
|||
#include "FTP.h"
|
||||
#include "NVT.h"
|
||||
#include "Event.h"
|
||||
#include "SSL.h"
|
||||
#include "Base64.h"
|
||||
|
||||
FTP_Analyzer::FTP_Analyzer(Connection* conn)
|
||||
: TCP_ApplicationAnalyzer(AnalyzerTag::FTP, conn)
|
||||
|
@ -44,6 +46,14 @@ void FTP_Analyzer::Done()
|
|||
Weird("partial_ftp_request");
|
||||
}
|
||||
|
||||
static uint32 get_reply_code(int len, const char* line)
|
||||
{
|
||||
if ( len >= 3 && isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2]) )
|
||||
return (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0');
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig)
|
||||
{
|
||||
TCP_ApplicationAnalyzer::DeliverStream(length, data, orig);
|
||||
|
@ -93,16 +103,7 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig)
|
|||
}
|
||||
else
|
||||
{
|
||||
uint32 reply_code;
|
||||
if ( length >= 3 &&
|
||||
isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2]) )
|
||||
{
|
||||
reply_code = (line[0] - '0') * 100 +
|
||||
(line[1] - '0') * 10 +
|
||||
(line[2] - '0');
|
||||
}
|
||||
else
|
||||
reply_code = 0;
|
||||
uint32 reply_code = get_reply_code(length, line);
|
||||
|
||||
int cont_resp;
|
||||
|
||||
|
@ -143,19 +144,22 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig)
|
|||
else
|
||||
line = end_of_line;
|
||||
|
||||
if ( auth_requested.size() > 0 &&
|
||||
(reply_code == 234 || reply_code == 335) )
|
||||
// Server accepted AUTH requested,
|
||||
// which means that very likely we
|
||||
// won't be able to parse the rest
|
||||
// of the session, and thus we stop
|
||||
// here.
|
||||
SetSkip(true);
|
||||
|
||||
cont_resp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( reply_code == 334 && auth_requested.size() > 0 &&
|
||||
auth_requested == "GSSAPI" )
|
||||
{
|
||||
// Server wants to proceed with an ADAT exchange and we
|
||||
// know how to analyze the GSI mechanism, so attach analyzer
|
||||
// to look for that.
|
||||
SSL_Analyzer* ssl = new SSL_Analyzer(Conn());
|
||||
ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), true));
|
||||
ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), false));
|
||||
AddChildAnalyzer(ssl);
|
||||
}
|
||||
|
||||
vl->append(new Val(reply_code, TYPE_COUNT));
|
||||
vl->append(new StringVal(end_of_line - line, line));
|
||||
vl->append(new Val(cont_resp, TYPE_BOOL));
|
||||
|
@ -164,5 +168,140 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig)
|
|||
}
|
||||
|
||||
ConnectionEvent(f, vl);
|
||||
|
||||
ForwardStream(length, data, orig);
|
||||
}
|
||||
|
||||
void FTP_ADAT_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||
{
|
||||
// Don't know how to parse anything but the ADAT exchanges of GSI GSSAPI,
|
||||
// which is basically just TLS/SSL.
|
||||
if ( ! Parent()->GetTag() == AnalyzerTag::SSL )
|
||||
{
|
||||
Parent()->Remove();
|
||||
return;
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
const char* line = (const char*) data;
|
||||
const char* end_of_line = line + len;
|
||||
|
||||
BroString* decoded_adat = 0;
|
||||
|
||||
if ( orig )
|
||||
{
|
||||
int cmd_len;
|
||||
const char* cmd;
|
||||
line = skip_whitespace(line, end_of_line);
|
||||
get_word(len, line, cmd_len, cmd);
|
||||
|
||||
if ( strncmp(cmd, "ADAT", cmd_len) == 0 )
|
||||
{
|
||||
line = skip_whitespace(line + cmd_len, end_of_line);
|
||||
StringVal encoded(end_of_line - line, line);
|
||||
decoded_adat = decode_base64(encoded.AsString());
|
||||
|
||||
if ( first_token )
|
||||
{
|
||||
// RFC 2743 section 3.1 specifies a framing format for tokens
|
||||
// that includes an identifier for the mechanism type. The
|
||||
// framing is supposed to be required for the initial context
|
||||
// token, but GSI doesn't do that and starts right in on a
|
||||
// TLS/SSL handshake, so look for that to identify it.
|
||||
const u_char* msg = decoded_adat->Bytes();
|
||||
int msg_len = decoded_adat->Len();
|
||||
|
||||
// Just check that it looks like a viable TLS/SSL handshake
|
||||
// record from the first byte (content type of 0x16) and
|
||||
// that the fourth and fifth bytes indicating the length of
|
||||
// the record match the length of the decoded data.
|
||||
if ( msg_len < 5 || msg[0] != 0x16 ||
|
||||
msg_len - 5 != ntohs(*((uint16*)(msg + 3))) )
|
||||
{
|
||||
// Doesn't look like TLS/SSL, so done analyzing.
|
||||
done = true;
|
||||
delete decoded_adat;
|
||||
decoded_adat = 0;
|
||||
}
|
||||
}
|
||||
|
||||
first_token = false;
|
||||
}
|
||||
|
||||
else if ( strncmp(cmd, "AUTH", cmd_len) == 0 )
|
||||
// Security state will be reset by a reissued AUTH.
|
||||
done = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
uint32 reply_code = get_reply_code(len, line);
|
||||
|
||||
switch ( reply_code ) {
|
||||
case 232:
|
||||
case 234:
|
||||
// Indicates security data exchange is complete, but nothing
|
||||
// more to decode in replies.
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case 235:
|
||||
// Security data exchange complete, but may have more to decode
|
||||
// in the reply (same format at 334 and 335).
|
||||
done = true;
|
||||
|
||||
// Fall-through.
|
||||
|
||||
case 334:
|
||||
case 335:
|
||||
// Security data exchange still in progress, and there could be data
|
||||
// to decode in the reply.
|
||||
line += 3;
|
||||
if ( len > 3 && line[0] == '-' )
|
||||
line++;
|
||||
|
||||
line = skip_whitespace(line, end_of_line);
|
||||
|
||||
if ( end_of_line - line >= 5 && strncmp(line, "ADAT=", 5) == 0 )
|
||||
{
|
||||
line += 5;
|
||||
StringVal encoded(end_of_line - line, line);
|
||||
decoded_adat = decode_base64(encoded.AsString());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 421:
|
||||
case 431:
|
||||
case 500:
|
||||
case 501:
|
||||
case 503:
|
||||
case 535:
|
||||
// Server isn't going to accept named security mechanism.
|
||||
// Client has to restart back at the AUTH.
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case 631:
|
||||
case 632:
|
||||
case 633:
|
||||
// If the server is sending protected replies, the security
|
||||
// data exchange must have already succeeded. It does have
|
||||
// encoded data in the reply, but 632 and 633 are also encrypted.
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( decoded_adat )
|
||||
{
|
||||
ForwardStream(decoded_adat->Len(), decoded_adat->Bytes(), orig);
|
||||
delete decoded_adat;
|
||||
}
|
||||
|
||||
if ( done )
|
||||
Parent()->Remove();
|
||||
}
|
||||
|
|
22
src/FTP.h
22
src/FTP.h
|
@ -30,4 +30,26 @@ protected:
|
|||
string auth_requested; // AUTH method requested
|
||||
};
|
||||
|
||||
/**
|
||||
* Analyzes security data of ADAT exchanges over FTP control session (RFC 2228).
|
||||
* Currently only the GSI mechanism of GSSAPI AUTH method is understood.
|
||||
* The ADAT exchange for GSI is base64 encoded TLS/SSL handshake tokens. This
|
||||
* analyzer just decodes the tokens and passes them on to the parent, which must
|
||||
* be an SSL analyzer instance.
|
||||
*/
|
||||
class FTP_ADAT_Analyzer : public SupportAnalyzer {
|
||||
public:
|
||||
FTP_ADAT_Analyzer(Connection* conn, bool arg_orig)
|
||||
: SupportAnalyzer(AnalyzerTag::FTP_ADAT, conn, arg_orig),
|
||||
first_token(true) { }
|
||||
|
||||
void DeliverStream(int len, const u_char* data, bool orig);
|
||||
|
||||
protected:
|
||||
// Used by the client-side analyzer to tell if it needs to peek at the
|
||||
// initial context token and do sanity checking (i.e. does it look like
|
||||
// a TLS/SSL handshake token).
|
||||
bool first_token;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
59
src/File.cc
59
src/File.cc
|
@ -74,9 +74,8 @@ void RotateTimer::Dispatch(double t, int is_expire)
|
|||
|
||||
// The following could in principle be part of a "file manager" object.
|
||||
|
||||
#define MAX_FILE_CACHE_SIZE 32
|
||||
#define MAX_FILE_CACHE_SIZE 512
|
||||
static int num_files_in_cache = 0;
|
||||
static int max_files_in_cache = 0;
|
||||
static BroFile* head = 0;
|
||||
static BroFile* tail = 0;
|
||||
|
||||
|
@ -87,12 +86,9 @@ double BroFile::default_rotation_size = 0;
|
|||
// that we should use for the cache.
|
||||
static int maximize_num_fds()
|
||||
{
|
||||
#ifdef NO_HAVE_SETRLIMIT
|
||||
return MAX_FILE_CACHE_SIZE;
|
||||
#else
|
||||
struct rlimit rl;
|
||||
if ( getrlimit(RLIMIT_NOFILE, &rl) < 0 )
|
||||
reporter->InternalError("maximize_num_fds(): getrlimit failed");
|
||||
reporter->FatalError("maximize_num_fds(): getrlimit failed");
|
||||
|
||||
if ( rl.rlim_max == RLIM_INFINITY )
|
||||
{
|
||||
|
@ -108,10 +104,9 @@ static int maximize_num_fds()
|
|||
rl.rlim_cur = rl.rlim_max;
|
||||
|
||||
if ( setrlimit(RLIMIT_NOFILE, &rl) < 0 )
|
||||
reporter->InternalError("maximize_num_fds(): setrlimit failed");
|
||||
reporter->FatalError("maximize_num_fds(): setrlimit failed");
|
||||
|
||||
return rl.rlim_cur / 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,11 +138,22 @@ BroFile::BroFile(FILE* arg_f, const char* arg_name, const char* arg_access)
|
|||
BroFile::BroFile(const char* arg_name, const char* arg_access, BroType* arg_t)
|
||||
{
|
||||
Init();
|
||||
|
||||
f = 0;
|
||||
name = copy_string(arg_name);
|
||||
access = copy_string(arg_access);
|
||||
t = arg_t ? arg_t : base_type(TYPE_STRING);
|
||||
if ( ! Open() )
|
||||
|
||||
if ( streq(name, "/dev/stdin") )
|
||||
f = stdin;
|
||||
else if ( streq(name, "/dev/stdout") )
|
||||
f = stdout;
|
||||
else if ( streq(name, "/dev/stderr") )
|
||||
f = stderr;
|
||||
|
||||
if ( f )
|
||||
is_open = 1;
|
||||
|
||||
else if ( ! Open() )
|
||||
{
|
||||
reporter->Error("cannot open %s: %s", name, strerror(errno));
|
||||
is_open = 0;
|
||||
|
@ -172,7 +178,7 @@ const char* BroFile::Name() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool BroFile::Open(FILE* file)
|
||||
bool BroFile::Open(FILE* file, const char* mode)
|
||||
{
|
||||
open_time = network_time ? network_time : current_time();
|
||||
|
||||
|
@ -196,7 +202,12 @@ bool BroFile::Open(FILE* file)
|
|||
InstallRotateTimer();
|
||||
|
||||
if ( ! f )
|
||||
f = fopen(name, access);
|
||||
{
|
||||
if ( ! mode )
|
||||
f = fopen(name, access);
|
||||
else
|
||||
f = fopen(name, mode);
|
||||
}
|
||||
|
||||
SetBuf(buffered);
|
||||
|
||||
|
@ -232,7 +243,7 @@ BroFile::~BroFile()
|
|||
delete [] access;
|
||||
delete [] cipher_buffer;
|
||||
|
||||
#ifdef USE_PERFTOOLS
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
heap_checker->UnIgnoreObject(this);
|
||||
#endif
|
||||
}
|
||||
|
@ -255,7 +266,7 @@ void BroFile::Init()
|
|||
cipher_ctx = 0;
|
||||
cipher_buffer = 0;
|
||||
|
||||
#ifdef USE_PERFTOOLS
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
heap_checker->IgnoreObject(this);
|
||||
#endif
|
||||
}
|
||||
|
@ -342,8 +353,8 @@ int BroFile::Close()
|
|||
|
||||
FinishEncrypt();
|
||||
|
||||
// Do not close stdout/stderr.
|
||||
if ( f == stdout || f == stderr )
|
||||
// Do not close stdin/stdout/stderr.
|
||||
if ( f == stdin || f == stdout || f == stderr )
|
||||
return 0;
|
||||
|
||||
if ( is_in_cache )
|
||||
|
@ -503,12 +514,9 @@ void BroFile::SetAttrs(Attributes* arg_attrs)
|
|||
InitEncrypt(log_encryption_key->AsString()->CheckString());
|
||||
}
|
||||
|
||||
if ( attrs->FindAttr(ATTR_DISABLE_PRINT_HOOK) )
|
||||
DisablePrintHook();
|
||||
|
||||
if ( attrs->FindAttr(ATTR_RAW_OUTPUT) )
|
||||
EnableRawOutput();
|
||||
|
||||
|
||||
InstallRotateTimer();
|
||||
}
|
||||
|
||||
|
@ -523,6 +531,10 @@ RecordVal* BroFile::Rotate()
|
|||
if ( ! is_open )
|
||||
return 0;
|
||||
|
||||
// Do not rotate stdin/stdout/stderr.
|
||||
if ( f == stdin || f == stdout || f == stderr )
|
||||
return 0;
|
||||
|
||||
if ( okay_to_manage && ! is_in_cache )
|
||||
BringIntoCache();
|
||||
|
||||
|
@ -572,8 +584,9 @@ void BroFile::InstallRotateTimer()
|
|||
const char* base_time = log_rotate_base_time ?
|
||||
log_rotate_base_time->AsString()->CheckString() : 0;
|
||||
|
||||
double base = parse_rotate_base_time(base_time);
|
||||
double delta_t =
|
||||
calc_next_rotate(rotate_interval, base_time);
|
||||
calc_next_rotate(network_time, rotate_interval, base);
|
||||
rotate_timer = new RotateTimer(network_time + delta_t,
|
||||
this, true);
|
||||
}
|
||||
|
@ -846,8 +859,8 @@ BroFile* BroFile::Unserialize(UnserialInfo* info)
|
|||
}
|
||||
}
|
||||
|
||||
// Otherwise, open.
|
||||
if ( ! file->Open() )
|
||||
// Otherwise, open, but don't clobber.
|
||||
if ( ! file->Open(0, "a") )
|
||||
{
|
||||
info->s->Error(fmt("cannot open %s: %s",
|
||||
file->name, strerror(errno)));
|
||||
|
|
10
src/File.h
10
src/File.h
|
@ -57,7 +57,7 @@ public:
|
|||
RecordVal* Rotate();
|
||||
|
||||
// Set &rotate_interval, &rotate_size, &postprocessor,
|
||||
// &disable_print_hook, and &raw_output attributes.
|
||||
// and &raw_output attributes.
|
||||
void SetAttrs(Attributes* attrs);
|
||||
|
||||
// Returns the current size of the file, after fresh stat'ing.
|
||||
|
@ -87,7 +87,13 @@ protected:
|
|||
|
||||
BroFile() { Init(); }
|
||||
void Init();
|
||||
bool Open(FILE* f = 0); // if file is given, it's an open file to use
|
||||
|
||||
/**
|
||||
* If file is given, it's an open file to use already.
|
||||
* If file is not given and mode is, the filename will be opened with that
|
||||
* access mode.
|
||||
*/
|
||||
bool Open(FILE* f = 0, const char* mode = 0);
|
||||
|
||||
BroFile* Prev() { return prev; }
|
||||
BroFile* Next() { return next; }
|
||||
|
|
|
@ -3,23 +3,19 @@
|
|||
#include "FileAnalyzer.h"
|
||||
#include "Reporter.h"
|
||||
|
||||
#ifdef HAVE_LIBMAGIC
|
||||
magic_t File_Analyzer::magic = 0;
|
||||
magic_t File_Analyzer::magic_mime = 0;
|
||||
#endif
|
||||
|
||||
File_Analyzer::File_Analyzer(Connection* conn)
|
||||
: TCP_ApplicationAnalyzer(AnalyzerTag::File, conn)
|
||||
{
|
||||
buffer_len = 0;
|
||||
|
||||
#ifdef HAVE_LIBMAGIC
|
||||
if ( ! magic )
|
||||
{
|
||||
InitMagic(&magic, MAGIC_NONE);
|
||||
InitMagic(&magic_mime, MAGIC_MIME);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void File_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
||||
|
@ -52,13 +48,11 @@ void File_Analyzer::Identify()
|
|||
const char* descr = 0;
|
||||
const char* mime = 0;
|
||||
|
||||
#ifdef HAVE_LIBMAGIC
|
||||
if ( magic )
|
||||
descr = magic_buffer(magic, buffer, buffer_len);
|
||||
|
||||
if ( magic_mime )
|
||||
mime = magic_buffer(magic_mime, buffer, buffer_len);
|
||||
#endif
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
|
@ -68,7 +62,6 @@ void File_Analyzer::Identify()
|
|||
ConnectionEvent(file_transferred, vl);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBMAGIC
|
||||
void File_Analyzer::InitMagic(magic_t* magic, int flags)
|
||||
{
|
||||
*magic = magic_open(flags);
|
||||
|
@ -83,4 +76,3 @@ void File_Analyzer::InitMagic(magic_t* magic, int flags)
|
|||
*magic = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
|
||||
#include "TCP.h"
|
||||
|
||||
#ifdef HAVE_LIBMAGIC
|
||||
#include <magic.h>
|
||||
#endif
|
||||
|
||||
class File_Analyzer : public TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
|
@ -31,12 +29,10 @@ protected:
|
|||
char buffer[BUFFER_SIZE];
|
||||
int buffer_len;
|
||||
|
||||
#ifdef HAVE_LIBMAGIC
|
||||
static void InitMagic(magic_t* magic, int flags);
|
||||
|
||||
static magic_t magic;
|
||||
static magic_t magic_mime;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,7 +58,7 @@ void FlowSrc::Process()
|
|||
|
||||
void FlowSrc::Close()
|
||||
{
|
||||
close(selectable_fd);
|
||||
safe_close(selectable_fd);
|
||||
}
|
||||
|
||||
|
||||
|
|
88
src/Frag.cc
88
src/Frag.cc
|
@ -27,21 +27,30 @@ void FragTimer::Dispatch(double t, int /* is_expire */)
|
|||
|
||||
FragReassembler::FragReassembler(NetSessions* arg_s,
|
||||
const IP_Hdr* ip, const u_char* pkt,
|
||||
uint32 frag_field, HashKey* k, double t)
|
||||
: Reassembler(0, ip->DstAddr(), REASSEM_IP)
|
||||
HashKey* k, double t)
|
||||
: Reassembler(0, REASSEM_IP)
|
||||
{
|
||||
s = arg_s;
|
||||
key = k;
|
||||
|
||||
const struct ip* ip4 = ip->IP4_Hdr();
|
||||
proto_hdr_len = ip4->ip_hl * 4;
|
||||
proto_hdr = (struct ip*) new u_char[64]; // max IP header + slop
|
||||
// Don't do a structure copy - need to pick up options, too.
|
||||
memcpy((void*) proto_hdr, (const void*) ip4, proto_hdr_len);
|
||||
if ( ip4 )
|
||||
{
|
||||
proto_hdr_len = ip->HdrLen();
|
||||
proto_hdr = new u_char[64]; // max IP header + slop
|
||||
// Don't do a structure copy - need to pick up options, too.
|
||||
memcpy((void*) proto_hdr, (const void*) ip4, proto_hdr_len);
|
||||
}
|
||||
else
|
||||
{
|
||||
proto_hdr_len = ip->HdrLen() - 8; // minus length of fragment header
|
||||
proto_hdr = new u_char[proto_hdr_len];
|
||||
memcpy(proto_hdr, ip->IP6_Hdr(), proto_hdr_len);
|
||||
}
|
||||
|
||||
reassembled_pkt = 0;
|
||||
frag_size = 0; // flag meaning "not known"
|
||||
|
||||
AddFragment(t, ip, pkt, frag_field);
|
||||
next_proto = ip->NextProto();
|
||||
|
||||
if ( frag_timeout != 0.0 )
|
||||
{
|
||||
|
@ -50,6 +59,8 @@ FragReassembler::FragReassembler(NetSessions* arg_s,
|
|||
}
|
||||
else
|
||||
expire_timer = 0;
|
||||
|
||||
AddFragment(t, ip, pkt);
|
||||
}
|
||||
|
||||
FragReassembler::~FragReassembler()
|
||||
|
@ -60,28 +71,42 @@ FragReassembler::~FragReassembler()
|
|||
delete key;
|
||||
}
|
||||
|
||||
void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt,
|
||||
uint32 frag_field)
|
||||
void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt)
|
||||
{
|
||||
const struct ip* ip4 = ip->IP4_Hdr();
|
||||
|
||||
if ( ip4->ip_p != proto_hdr->ip_p || ip4->ip_hl != proto_hdr->ip_hl )
|
||||
if ( ip4 )
|
||||
{
|
||||
if ( ip4->ip_p != ((const struct ip*)proto_hdr)->ip_p ||
|
||||
ip4->ip_hl != ((const struct ip*)proto_hdr)->ip_hl )
|
||||
// || ip4->ip_tos != proto_hdr->ip_tos
|
||||
// don't check TOS, there's at least one stack that actually
|
||||
// uses different values, and it's hard to see an associated
|
||||
// attack.
|
||||
s->Weird("fragment_protocol_inconsistency", ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ip->NextProto() != next_proto ||
|
||||
ip->HdrLen() - 8 != proto_hdr_len )
|
||||
s->Weird("fragment_protocol_inconsistency", ip);
|
||||
// TODO: more detailed unfrag header consistency checks?
|
||||
}
|
||||
|
||||
if ( frag_field & 0x4000 )
|
||||
if ( ip->DF() )
|
||||
// Linux MTU discovery for UDP can do this, for example.
|
||||
s->Weird("fragment_with_DF", ip);
|
||||
|
||||
int offset = (ntohs(ip4->ip_off) & 0x1fff) * 8;
|
||||
int len = ntohs(ip4->ip_len);
|
||||
int hdr_len = proto_hdr->ip_hl * 4;
|
||||
int offset = ip->FragOffset();
|
||||
int len = ip->TotalLen();
|
||||
int hdr_len = ip->HdrLen();
|
||||
int upper_seq = offset + len - hdr_len;
|
||||
|
||||
if ( (frag_field & 0x2000) == 0 )
|
||||
if ( ! offset )
|
||||
// Make sure to use the first fragment header's next field.
|
||||
next_proto = ip->NextProto();
|
||||
|
||||
if ( ! ip->MF() )
|
||||
{
|
||||
// Last fragment.
|
||||
if ( frag_size == 0 )
|
||||
|
@ -125,7 +150,7 @@ void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt,
|
|||
|
||||
void FragReassembler::Overlap(const u_char* b1, const u_char* b2, int n)
|
||||
{
|
||||
IP_Hdr proto_h((const struct ip*) proto_hdr);
|
||||
IP_Hdr proto_h(proto_hdr, false, proto_hdr_len);
|
||||
|
||||
if ( memcmp((const void*) b1, (const void*) b2, n) )
|
||||
s->Weird("fragment_inconsistency", &proto_h);
|
||||
|
@ -157,7 +182,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
|
|||
// can happen for benign reasons when we're
|
||||
// intermingling parts of two fragmented packets.
|
||||
|
||||
IP_Hdr proto_h((const struct ip*) proto_hdr);
|
||||
IP_Hdr proto_h(proto_hdr, false, proto_hdr_len);
|
||||
s->Weird("fragment_size_inconsistency", &proto_h);
|
||||
|
||||
// We decide to analyze the contiguous portion now.
|
||||
|
@ -171,7 +196,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
|
|||
|
||||
else if ( last_block->upper > frag_size )
|
||||
{
|
||||
IP_Hdr proto_h((const struct ip*) proto_hdr);
|
||||
IP_Hdr proto_h(proto_hdr, false, proto_hdr_len);
|
||||
s->Weird("fragment_size_inconsistency", &proto_h);
|
||||
frag_size = last_block->upper;
|
||||
}
|
||||
|
@ -193,8 +218,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
|
|||
u_char* pkt = new u_char[n];
|
||||
memcpy((void*) pkt, (const void*) proto_hdr, proto_hdr_len);
|
||||
|
||||
struct ip* reassem4 = (struct ip*) pkt;
|
||||
reassem4->ip_len = htons(frag_size + proto_hdr_len);
|
||||
u_char* pkt_start = pkt;
|
||||
|
||||
pkt += proto_hdr_len;
|
||||
|
||||
|
@ -214,7 +238,27 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
|
|||
}
|
||||
|
||||
delete reassembled_pkt;
|
||||
reassembled_pkt = new IP_Hdr(reassem4);
|
||||
|
||||
if ( ((const struct ip*)pkt_start)->ip_v == 4 )
|
||||
{
|
||||
struct ip* reassem4 = (struct ip*) pkt_start;
|
||||
reassem4->ip_len = htons(frag_size + proto_hdr_len);
|
||||
reassembled_pkt = new IP_Hdr(reassem4, true);
|
||||
}
|
||||
|
||||
else if ( ((const struct ip*)pkt_start)->ip_v == 6 )
|
||||
{
|
||||
struct ip6_hdr* reassem6 = (struct ip6_hdr*) pkt_start;
|
||||
reassem6->ip6_plen = htons(frag_size + proto_hdr_len - 40);
|
||||
const IPv6_Hdr_Chain* chain = new IPv6_Hdr_Chain(reassem6, next_proto, n);
|
||||
reassembled_pkt = new IP_Hdr(reassem6, true, n, chain);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
reporter->InternalError("bad IP version in fragment reassembly");
|
||||
}
|
||||
|
||||
|
||||
DeleteTimer();
|
||||
}
|
||||
|
|
|
@ -20,11 +20,10 @@ typedef void (FragReassembler::*frag_timer_func)(double t);
|
|||
class FragReassembler : public Reassembler {
|
||||
public:
|
||||
FragReassembler(NetSessions* s, const IP_Hdr* ip, const u_char* pkt,
|
||||
uint32 frag_field, HashKey* k, double t);
|
||||
HashKey* k, double t);
|
||||
~FragReassembler();
|
||||
|
||||
void AddFragment(double t, const IP_Hdr* ip, const u_char* pkt,
|
||||
uint32 frag_field);
|
||||
void AddFragment(double t, const IP_Hdr* ip, const u_char* pkt);
|
||||
|
||||
void Expire(double t);
|
||||
void DeleteTimer();
|
||||
|
@ -37,11 +36,12 @@ protected:
|
|||
void BlockInserted(DataBlock* start_block);
|
||||
void Overlap(const u_char* b1, const u_char* b2, int n);
|
||||
|
||||
struct ip* proto_hdr;
|
||||
u_char* proto_hdr;
|
||||
IP_Hdr* reassembled_pkt;
|
||||
int proto_hdr_len;
|
||||
NetSessions* s;
|
||||
int frag_size; // size of fully reassembled fragment
|
||||
uint16 next_proto; // first IPv6 fragment header's next proto field
|
||||
HashKey* key;
|
||||
|
||||
FragTimer* expire_timer;
|
||||
|
|
18
src/Func.cc
18
src/Func.cc
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "md5.h"
|
||||
#include "Base64.h"
|
||||
#include "Stmt.h"
|
||||
#include "Scope.h"
|
||||
|
@ -101,7 +100,7 @@ Func* Func::Unserialize(UnserialInfo* info)
|
|||
if ( ! (id->HasVal() && id->ID_Val()->Type()->Tag() == TYPE_FUNC) )
|
||||
{
|
||||
info->s->Error(fmt("ID %s is not a built-in", name));
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Unref(f);
|
||||
|
@ -330,7 +329,17 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
|||
bodies[i].stmts->GetLocationInfo());
|
||||
|
||||
Unref(result);
|
||||
result = bodies[i].stmts->Exec(f, flow);
|
||||
|
||||
try
|
||||
{
|
||||
result = bodies[i].stmts->Exec(f, flow);
|
||||
}
|
||||
|
||||
catch ( InterpreterException& e )
|
||||
{
|
||||
// Already reported, but we continue exec'ing remaining bodies.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( f->HasDelayed() )
|
||||
{
|
||||
|
@ -523,11 +532,13 @@ void builtin_error(const char* msg, BroObj* arg)
|
|||
|
||||
#include "bro.bif.func_h"
|
||||
#include "logging.bif.func_h"
|
||||
#include "input.bif.func_h"
|
||||
#include "reporter.bif.func_h"
|
||||
#include "strings.bif.func_h"
|
||||
|
||||
#include "bro.bif.func_def"
|
||||
#include "logging.bif.func_def"
|
||||
#include "input.bif.func_def"
|
||||
#include "reporter.bif.func_def"
|
||||
#include "strings.bif.func_def"
|
||||
|
||||
|
@ -542,6 +553,7 @@ void init_builtin_funcs()
|
|||
|
||||
#include "bro.bif.func_init"
|
||||
#include "logging.bif.func_init"
|
||||
#include "input.bif.func_init"
|
||||
#include "reporter.bif.func_init"
|
||||
#include "strings.bif.func_init"
|
||||
|
||||
|
|
|
@ -42,6 +42,12 @@ Gnutella_Analyzer::Gnutella_Analyzer(Connection* conn)
|
|||
resp_msg_state = new GnutellaMsgState();
|
||||
}
|
||||
|
||||
Gnutella_Analyzer::~Gnutella_Analyzer()
|
||||
{
|
||||
delete orig_msg_state;
|
||||
delete resp_msg_state;
|
||||
}
|
||||
|
||||
void Gnutella_Analyzer::Done()
|
||||
{
|
||||
TCP_ApplicationAnalyzer::Done();
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
class Gnutella_Analyzer : public TCP_ApplicationAnalyzer {
|
||||
public:
|
||||
Gnutella_Analyzer(Connection* conn);
|
||||
~Gnutella_Analyzer();
|
||||
|
||||
virtual void Done ();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
|
|
|
@ -20,10 +20,10 @@ void HTTP_Analyzer_binpac::Done()
|
|||
interp->FlowEOF(false);
|
||||
}
|
||||
|
||||
void HTTP_Analyzer_binpac::EndpointEOF(TCP_Reassembler* endp)
|
||||
void HTTP_Analyzer_binpac::EndpointEOF(bool is_orig)
|
||||
{
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(endp);
|
||||
interp->FlowEOF(endp->IsOrig());
|
||||
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
|
||||
interp->FlowEOF(is_orig);
|
||||
}
|
||||
|
||||
void HTTP_Analyzer_binpac::DeliverStream(int len, const u_char* data, bool orig)
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
virtual void Done();
|
||||
virtual void DeliverStream(int len, const u_char* data, bool orig);
|
||||
virtual void Undelivered(int seq, int len, bool orig);
|
||||
virtual void EndpointEOF(TCP_Reassembler* endp);
|
||||
virtual void EndpointEOF(bool is_orig);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new HTTP_Analyzer_binpac(conn); }
|
||||
|
|
10
src/HTTP.cc
10
src/HTTP.cc
|
@ -43,9 +43,7 @@ HTTP_Entity::HTTP_Entity(HTTP_Message *arg_message, MIME_Entity* parent_entity,
|
|||
header_length = 0;
|
||||
deliver_body = (http_entity_data != 0);
|
||||
encoding = IDENTITY;
|
||||
#ifdef HAVE_LIBZ
|
||||
zip = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTTP_Entity::EndOfData()
|
||||
|
@ -53,7 +51,6 @@ void HTTP_Entity::EndOfData()
|
|||
if ( DEBUG_http )
|
||||
DEBUG_MSG("%.6f: end of data\n", network_time);
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
if ( zip )
|
||||
{
|
||||
zip->Done();
|
||||
|
@ -61,7 +58,6 @@ void HTTP_Entity::EndOfData()
|
|||
zip = 0;
|
||||
encoding = IDENTITY;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( body_length )
|
||||
http_message->MyHTTP_Analyzer()->
|
||||
|
@ -179,7 +175,6 @@ private:
|
|||
|
||||
void HTTP_Entity::DeliverBody(int len, const char* data, int trailing_CRLF)
|
||||
{
|
||||
#ifdef HAVE_LIBZ
|
||||
if ( encoding == GZIP || encoding == DEFLATE )
|
||||
{
|
||||
ZIP_Analyzer::Method method =
|
||||
|
@ -198,7 +193,6 @@ void HTTP_Entity::DeliverBody(int len, const char* data, int trailing_CRLF)
|
|||
zip->NextStream(len, (const u_char*) data, false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
DeliverBodyClear(len, data, trailing_CRLF);
|
||||
}
|
||||
|
||||
|
@ -450,9 +444,7 @@ void HTTP_Entity::SubmitAllHeaders()
|
|||
// content-length headers or if connection is to be closed afterwards
|
||||
// anyway.
|
||||
else if ( http_message->MyHTTP_Analyzer()->IsConnectionClose ()
|
||||
#ifdef HAVE_LIBZ
|
||||
|| encoding == GZIP || encoding == DEFLATE
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// FIXME: Using INT_MAX is kind of a hack here. Better
|
||||
|
@ -1551,7 +1543,7 @@ void HTTP_Analyzer::HTTP_Header(int is_orig, MIME_Header* h)
|
|||
}
|
||||
}
|
||||
|
||||
void HTTP_Analyzer::ParseVersion(data_chunk_t ver, const uint32* host,
|
||||
void HTTP_Analyzer::ParseVersion(data_chunk_t ver, const IPAddr& host,
|
||||
bool user_agent)
|
||||
{
|
||||
int len = ver.length;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "MIME.h"
|
||||
#include "binpac_bro.h"
|
||||
#include "ZIP.h"
|
||||
#include "IPAddr.h"
|
||||
|
||||
enum CHUNKED_TRANSFER_STATE {
|
||||
NON_CHUNKED_TRANSFER,
|
||||
|
@ -29,10 +30,8 @@ public:
|
|||
int expect_body);
|
||||
~HTTP_Entity()
|
||||
{
|
||||
#ifdef HAVE_LIBZ
|
||||
if ( zip )
|
||||
{ zip->Done(); delete zip; }
|
||||
#endif
|
||||
}
|
||||
|
||||
void EndOfData();
|
||||
|
@ -55,9 +54,7 @@ protected:
|
|||
int64_t header_length;
|
||||
int deliver_body;
|
||||
enum { IDENTITY, GZIP, COMPRESS, DEFLATE } encoding;
|
||||
#ifdef HAVE_LIBZ
|
||||
ZIP_Analyzer* zip;
|
||||
#endif
|
||||
|
||||
MIME_Entity* NewChildEntity() { return new HTTP_Entity(http_message, this, 1); }
|
||||
|
||||
|
@ -216,7 +213,7 @@ protected:
|
|||
|
||||
const BroString* UnansweredRequestMethod();
|
||||
|
||||
void ParseVersion(data_chunk_t ver, const uint32* host, bool user_agent);
|
||||
void ParseVersion(data_chunk_t ver, const IPAddr& host, bool user_agent);
|
||||
int HTTP_ReplyCode(const char* code_str);
|
||||
int ExpectReplyMessageBody();
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "BroString.h"
|
||||
|
||||
#define UHASH_KEY_SIZE 32
|
||||
#define UHASH_KEY_SIZE 36
|
||||
|
||||
typedef uint64 hash_t;
|
||||
|
||||
|
|
731
src/ICMP.cc
731
src/ICMP.cc
|
@ -9,6 +9,8 @@
|
|||
#include "Event.h"
|
||||
#include "ICMP.h"
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
ICMP_Analyzer::ICMP_Analyzer(Connection* c)
|
||||
: TransportLayerAnalyzer(AnalyzerTag::ICMP, c)
|
||||
{
|
||||
|
@ -32,7 +34,7 @@ void ICMP_Analyzer::Done()
|
|||
matcher_state.FinishEndpointMatcher();
|
||||
}
|
||||
|
||||
void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
|
||||
void ICMP_Analyzer::DeliverPacket(int len, const u_char* data,
|
||||
bool is_orig, int seq, const IP_Hdr* ip, int caplen)
|
||||
{
|
||||
assert(ip);
|
||||
|
@ -46,13 +48,32 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
|
|||
PacketContents(data + 8, min(len, caplen) - 8);
|
||||
|
||||
const struct icmp* icmpp = (const struct icmp*) data;
|
||||
len = arg_len;
|
||||
|
||||
if ( ! ignore_checksums && caplen >= len &&
|
||||
icmp_checksum(icmpp, len) != 0xffff )
|
||||
if ( ! ignore_checksums && caplen >= len )
|
||||
{
|
||||
Weird("bad_ICMP_checksum");
|
||||
return;
|
||||
int chksum = 0;
|
||||
|
||||
switch ( ip->NextProto() )
|
||||
{
|
||||
case IPPROTO_ICMP:
|
||||
chksum = icmp_checksum(icmpp, len);
|
||||
break;
|
||||
|
||||
case IPPROTO_ICMPV6:
|
||||
chksum = icmp6_checksum(icmpp, ip, len);
|
||||
break;
|
||||
|
||||
default:
|
||||
reporter->InternalError("unexpected IP proto in ICMP analyzer: %d",
|
||||
ip->NextProto());
|
||||
break;
|
||||
}
|
||||
|
||||
if ( chksum != 0xffff )
|
||||
{
|
||||
Weird("bad_ICMP_checksum");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Conn()->SetLastTime(current_timestamp);
|
||||
|
@ -77,7 +98,13 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
|
|||
else
|
||||
len_stat += len;
|
||||
|
||||
NextICMP(current_timestamp, icmpp, len, caplen, data);
|
||||
if ( ip->NextProto() == IPPROTO_ICMP )
|
||||
NextICMP4(current_timestamp, icmpp, len, caplen, data, ip);
|
||||
else if ( ip->NextProto() == IPPROTO_ICMPV6 )
|
||||
NextICMP6(current_timestamp, icmpp, len, caplen, data, ip);
|
||||
else
|
||||
reporter->InternalError("unexpected next protocol in ICMP::DeliverPacket()");
|
||||
|
||||
|
||||
if ( caplen >= len )
|
||||
ForwardPacket(len, data, is_orig, seq, ip, caplen);
|
||||
|
@ -87,26 +114,99 @@ void ICMP_Analyzer::DeliverPacket(int arg_len, const u_char* data,
|
|||
false, false, true);
|
||||
}
|
||||
|
||||
void ICMP_Analyzer::NextICMP(double /* t */, const struct icmp* /* icmpp */,
|
||||
int /* len */, int /* caplen */,
|
||||
const u_char*& /* data */)
|
||||
void ICMP_Analyzer::NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr )
|
||||
{
|
||||
ICMPEvent(icmp_sent);
|
||||
switch ( icmpp->icmp_type )
|
||||
{
|
||||
case ICMP_ECHO:
|
||||
case ICMP_ECHOREPLY:
|
||||
Echo(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
|
||||
case ICMP_UNREACH:
|
||||
case ICMP_TIMXCEED:
|
||||
Context4(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
|
||||
default:
|
||||
ICMPEvent(icmp_sent, icmpp, len, 0, ip_hdr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f)
|
||||
void ICMP_Analyzer::NextICMP6(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr )
|
||||
{
|
||||
switch ( icmpp->icmp_type )
|
||||
{
|
||||
// Echo types.
|
||||
case ICMP6_ECHO_REQUEST:
|
||||
case ICMP6_ECHO_REPLY:
|
||||
Echo(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
|
||||
// Error messages all have the same structure for their context,
|
||||
// and are handled by the same function.
|
||||
case ICMP6_PARAM_PROB:
|
||||
case ICMP6_TIME_EXCEEDED:
|
||||
case ICMP6_PACKET_TOO_BIG:
|
||||
case ICMP6_DST_UNREACH:
|
||||
Context6(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
|
||||
// Router related messages.
|
||||
case ND_REDIRECT:
|
||||
Redirect(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
case ND_ROUTER_ADVERT:
|
||||
RouterAdvert(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
case ND_NEIGHBOR_ADVERT:
|
||||
NeighborAdvert(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
case ND_NEIGHBOR_SOLICIT:
|
||||
NeighborSolicit(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
case ND_ROUTER_SOLICIT:
|
||||
RouterSolicit(t, icmpp, len, caplen, data, ip_hdr);
|
||||
break;
|
||||
case ICMP6_ROUTER_RENUMBERING:
|
||||
ICMPEvent(icmp_sent, icmpp, len, 1, ip_hdr);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
// Currently not specifically implemented.
|
||||
case MLD_LISTENER_QUERY:
|
||||
case MLD_LISTENER_REPORT:
|
||||
case MLD_LISTENER_REDUCTION:
|
||||
#endif
|
||||
default:
|
||||
// Error messages (i.e., ICMPv6 type < 128) all have
|
||||
// the same structure for their context, and are
|
||||
// handled by the same function.
|
||||
if ( icmpp->icmp_type < 128 )
|
||||
Context6(t, icmpp, len, caplen, data, ip_hdr);
|
||||
else
|
||||
ICMPEvent(icmp_sent, icmpp, len, 1, ip_hdr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICMP_Analyzer::ICMPEvent(EventHandlerPtr f, const struct icmp* icmpp,
|
||||
int len, int icmpv6, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
if ( ! f )
|
||||
return;
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal());
|
||||
|
||||
vl->append(BuildICMPVal(icmpp, len, icmpv6, ip_hdr));
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
RecordVal* ICMP_Analyzer::BuildICMPVal()
|
||||
RecordVal* ICMP_Analyzer::BuildICMPVal(const struct icmp* icmpp, int len,
|
||||
int icmpv6, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
if ( ! icmp_conn_val )
|
||||
{
|
||||
|
@ -114,9 +214,11 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
|
|||
|
||||
icmp_conn_val->Assign(0, new AddrVal(Conn()->OrigAddr()));
|
||||
icmp_conn_val->Assign(1, new AddrVal(Conn()->RespAddr()));
|
||||
icmp_conn_val->Assign(2, new Val(type, TYPE_COUNT));
|
||||
icmp_conn_val->Assign(3, new Val(code, TYPE_COUNT));
|
||||
icmp_conn_val->Assign(2, new Val(icmpp->icmp_type, TYPE_COUNT));
|
||||
icmp_conn_val->Assign(3, new Val(icmpp->icmp_code, TYPE_COUNT));
|
||||
icmp_conn_val->Assign(4, new Val(len, TYPE_COUNT));
|
||||
icmp_conn_val->Assign(5, new Val(ip_hdr->TTL(), TYPE_COUNT));
|
||||
icmp_conn_val->Assign(6, new Val(icmpv6, TYPE_BOOL));
|
||||
}
|
||||
|
||||
Ref(icmp_conn_val);
|
||||
|
@ -124,91 +226,115 @@ RecordVal* ICMP_Analyzer::BuildICMPVal()
|
|||
return icmp_conn_val;
|
||||
}
|
||||
|
||||
RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
|
||||
TransportProto ICMP_Analyzer::GetContextProtocol(const IP_Hdr* ip_hdr, uint32* src_port, uint32* dst_port)
|
||||
{
|
||||
const struct ip* ip = (const struct ip *) data;
|
||||
uint32 ip_hdr_len = ip->ip_hl * 4;
|
||||
const u_char* transport_hdr;
|
||||
uint32 ip_hdr_len = ip_hdr->HdrLen();
|
||||
bool ip4 = ip_hdr->IP4_Hdr();
|
||||
|
||||
if ( ip4 )
|
||||
transport_hdr = ((u_char *) ip_hdr->IP4_Hdr() + ip_hdr_len);
|
||||
else
|
||||
transport_hdr = ((u_char *) ip_hdr->IP6_Hdr() + ip_hdr_len);
|
||||
|
||||
TransportProto proto;
|
||||
|
||||
switch ( ip_hdr->NextProto() ) {
|
||||
case 1: proto = TRANSPORT_ICMP; break;
|
||||
case 6: proto = TRANSPORT_TCP; break;
|
||||
case 17: proto = TRANSPORT_UDP; break;
|
||||
case 58: proto = TRANSPORT_ICMP; break;
|
||||
default: proto = TRANSPORT_UNKNOWN; break;
|
||||
}
|
||||
|
||||
switch ( proto ) {
|
||||
case TRANSPORT_ICMP:
|
||||
{
|
||||
const struct icmp* icmpp =
|
||||
(const struct icmp *) transport_hdr;
|
||||
bool is_one_way; // dummy
|
||||
*src_port = ntohs(icmpp->icmp_type);
|
||||
|
||||
if ( ip4 )
|
||||
*dst_port = ntohs(ICMP4_counterpart(icmpp->icmp_type,
|
||||
icmpp->icmp_code, is_one_way));
|
||||
else
|
||||
*dst_port = ntohs(ICMP6_counterpart(icmpp->icmp_type,
|
||||
icmpp->icmp_code, is_one_way));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TRANSPORT_TCP:
|
||||
{
|
||||
const struct tcphdr* tp =
|
||||
(const struct tcphdr *) transport_hdr;
|
||||
*src_port = ntohs(tp->th_sport);
|
||||
*dst_port = ntohs(tp->th_dport);
|
||||
break;
|
||||
}
|
||||
|
||||
case TRANSPORT_UDP:
|
||||
{
|
||||
const struct udphdr* up =
|
||||
(const struct udphdr *) transport_hdr;
|
||||
*src_port = ntohs(up->uh_sport);
|
||||
*dst_port = ntohs(up->uh_dport);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
*src_port = *dst_port = ntohs(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
RecordVal* ICMP_Analyzer::ExtractICMP4Context(int len, const u_char*& data)
|
||||
{
|
||||
const IP_Hdr ip_hdr_data((const struct ip*) data, false);
|
||||
const IP_Hdr* ip_hdr = &ip_hdr_data;
|
||||
|
||||
uint32 ip_hdr_len = ip_hdr->HdrLen();
|
||||
|
||||
uint32 ip_len, frag_offset;
|
||||
TransportProto proto = TRANSPORT_UNKNOWN;
|
||||
int DF, MF, bad_hdr_len, bad_checksum;
|
||||
uint32 src_addr, dst_addr;
|
||||
IPAddr src_addr, dst_addr;
|
||||
uint32 src_port, dst_port;
|
||||
|
||||
if ( ip_hdr_len < sizeof(struct ip) || ip_hdr_len > uint32(len) )
|
||||
{ // We don't have an entire IP header.
|
||||
if ( len < (int)sizeof(struct ip) || ip_hdr_len > uint32(len) )
|
||||
{
|
||||
// We don't have an entire IP header.
|
||||
bad_hdr_len = 1;
|
||||
ip_len = frag_offset = 0;
|
||||
DF = MF = bad_checksum = 0;
|
||||
src_addr = dst_addr = 0;
|
||||
src_port = dst_port = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
bad_hdr_len = 0;
|
||||
ip_len = ntohs(ip->ip_len);
|
||||
bad_checksum = ones_complement_checksum((void*) ip, ip_hdr_len, 0) != 0xffff;
|
||||
ip_len = ip_hdr->TotalLen();
|
||||
bad_checksum = (ones_complement_checksum((void*) ip_hdr->IP4_Hdr(), ip_hdr_len, 0) != 0xffff);
|
||||
|
||||
src_addr = uint32(ip->ip_src.s_addr);
|
||||
dst_addr = uint32(ip->ip_dst.s_addr);
|
||||
src_addr = ip_hdr->SrcAddr();
|
||||
dst_addr = ip_hdr->DstAddr();
|
||||
|
||||
switch ( ip->ip_p ) {
|
||||
case 1: proto = TRANSPORT_ICMP; break;
|
||||
case 6: proto = TRANSPORT_TCP; break;
|
||||
case 17: proto = TRANSPORT_UDP; break;
|
||||
DF = ip_hdr->DF();
|
||||
MF = ip_hdr->MF();
|
||||
frag_offset = ip_hdr->FragOffset();
|
||||
|
||||
// Default uses TRANSPORT_UNKNOWN, per initialization above.
|
||||
}
|
||||
|
||||
uint32 frag_field = ntohs(ip->ip_off);
|
||||
DF = frag_field & 0x4000;
|
||||
MF = frag_field & 0x2000;
|
||||
frag_offset = frag_field & /* IP_OFFMASK not portable */ 0x1fff;
|
||||
const u_char* transport_hdr = ((u_char *) ip + ip_hdr_len);
|
||||
|
||||
if ( uint32(len) < ip_hdr_len + 4 )
|
||||
if ( uint32(len) >= ip_hdr_len + 4 )
|
||||
proto = GetContextProtocol(ip_hdr, &src_port, &dst_port);
|
||||
else
|
||||
{
|
||||
// 4 above is the magic number meaning that both
|
||||
// port numbers are included in the ICMP.
|
||||
bad_hdr_len = 1;
|
||||
src_port = dst_port = 0;
|
||||
bad_hdr_len = 1;
|
||||
}
|
||||
|
||||
switch ( proto ) {
|
||||
case TRANSPORT_ICMP:
|
||||
{
|
||||
const struct icmp* icmpp =
|
||||
(const struct icmp *) transport_hdr;
|
||||
bool is_one_way; // dummy
|
||||
src_port = ntohs(icmpp->icmp_type);
|
||||
dst_port = ntohs(ICMP_counterpart(icmpp->icmp_type,
|
||||
icmpp->icmp_code,
|
||||
is_one_way));
|
||||
}
|
||||
break;
|
||||
|
||||
case TRANSPORT_TCP:
|
||||
{
|
||||
const struct tcphdr* tp =
|
||||
(const struct tcphdr *) transport_hdr;
|
||||
src_port = ntohs(tp->th_sport);
|
||||
dst_port = ntohs(tp->th_dport);
|
||||
}
|
||||
break;
|
||||
|
||||
case TRANSPORT_UDP:
|
||||
{
|
||||
const struct udphdr* up =
|
||||
(const struct udphdr *) transport_hdr;
|
||||
src_port = ntohs(up->uh_sport);
|
||||
dst_port = ntohs(up->uh_dport);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
src_port = dst_port = ntohs(0);
|
||||
}
|
||||
}
|
||||
|
||||
RecordVal* iprec = new RecordVal(icmp_context);
|
||||
|
@ -218,8 +344,8 @@ RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
|
|||
id_val->Assign(1, new PortVal(src_port, proto));
|
||||
id_val->Assign(2, new AddrVal(dst_addr));
|
||||
id_val->Assign(3, new PortVal(dst_port, proto));
|
||||
iprec->Assign(0, id_val);
|
||||
|
||||
iprec->Assign(0, id_val);
|
||||
iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
|
||||
iprec->Assign(2, new Val(proto, TYPE_COUNT));
|
||||
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
|
||||
|
@ -231,6 +357,66 @@ RecordVal* ICMP_Analyzer::ExtractICMPContext(int len, const u_char*& data)
|
|||
return iprec;
|
||||
}
|
||||
|
||||
RecordVal* ICMP_Analyzer::ExtractICMP6Context(int len, const u_char*& data)
|
||||
{
|
||||
int DF = 0, MF = 0, bad_hdr_len = 0;
|
||||
TransportProto proto = TRANSPORT_UNKNOWN;
|
||||
|
||||
IPAddr src_addr;
|
||||
IPAddr dst_addr;
|
||||
uint32 ip_len, frag_offset = 0;
|
||||
uint32 src_port, dst_port;
|
||||
|
||||
if ( len < (int)sizeof(struct ip6_hdr) )
|
||||
{
|
||||
bad_hdr_len = 1;
|
||||
ip_len = 0;
|
||||
src_port = dst_port = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const IP_Hdr ip_hdr_data((const struct ip6_hdr*) data, false, len);
|
||||
const IP_Hdr* ip_hdr = &ip_hdr_data;
|
||||
|
||||
ip_len = ip_hdr->TotalLen();
|
||||
src_addr = ip_hdr->SrcAddr();
|
||||
dst_addr = ip_hdr->DstAddr();
|
||||
frag_offset = ip_hdr->FragOffset();
|
||||
MF = ip_hdr->MF();
|
||||
DF = ip_hdr->DF();
|
||||
|
||||
if ( uint32(len) >= uint32(ip_hdr->HdrLen() + 4) )
|
||||
proto = GetContextProtocol(ip_hdr, &src_port, &dst_port);
|
||||
else
|
||||
{
|
||||
// 4 above is the magic number meaning that both
|
||||
// port numbers are included in the ICMP.
|
||||
src_port = dst_port = 0;
|
||||
bad_hdr_len = 1;
|
||||
}
|
||||
}
|
||||
|
||||
RecordVal* iprec = new RecordVal(icmp_context);
|
||||
RecordVal* id_val = new RecordVal(conn_id);
|
||||
|
||||
id_val->Assign(0, new AddrVal(src_addr));
|
||||
id_val->Assign(1, new PortVal(src_port, proto));
|
||||
id_val->Assign(2, new AddrVal(dst_addr));
|
||||
id_val->Assign(3, new PortVal(dst_port, proto));
|
||||
|
||||
iprec->Assign(0, id_val);
|
||||
iprec->Assign(1, new Val(ip_len, TYPE_COUNT));
|
||||
iprec->Assign(2, new Val(proto, TYPE_COUNT));
|
||||
iprec->Assign(3, new Val(frag_offset, TYPE_COUNT));
|
||||
iprec->Assign(4, new Val(bad_hdr_len, TYPE_BOOL));
|
||||
// bad_checksum is always false since IPv6 layer doesn't have a checksum.
|
||||
iprec->Assign(5, new Val(0, TYPE_BOOL));
|
||||
iprec->Assign(6, new Val(MF, TYPE_BOOL));
|
||||
iprec->Assign(7, new Val(DF, TYPE_BOOL));
|
||||
|
||||
return iprec;
|
||||
}
|
||||
|
||||
bool ICMP_Analyzer::IsReuse(double /* t */, const u_char* /* pkt */)
|
||||
{
|
||||
return 0;
|
||||
|
@ -243,7 +429,7 @@ void ICMP_Analyzer::Describe(ODesc* d) const
|
|||
d->Add(Conn()->LastTime());
|
||||
d->AddSP(")");
|
||||
|
||||
d->Add(dotted_addr(Conn()->OrigAddr()));
|
||||
d->Add(Conn()->OrigAddr());
|
||||
d->Add(".");
|
||||
d->Add(type);
|
||||
d->Add(".");
|
||||
|
@ -252,7 +438,7 @@ void ICMP_Analyzer::Describe(ODesc* d) const
|
|||
d->SP();
|
||||
d->AddSP("->");
|
||||
|
||||
d->Add(dotted_addr(Conn()->RespAddr()));
|
||||
d->Add(Conn()->RespAddr());
|
||||
}
|
||||
|
||||
void ICMP_Analyzer::UpdateConnVal(RecordVal *conn_val)
|
||||
|
@ -294,15 +480,20 @@ unsigned int ICMP_Analyzer::MemoryAllocation() const
|
|||
+ (icmp_conn_val ? icmp_conn_val->MemoryAllocation() : 0);
|
||||
}
|
||||
|
||||
ICMP_Echo_Analyzer::ICMP_Echo_Analyzer(Connection* c)
|
||||
: ICMP_Analyzer(AnalyzerTag::ICMP_Echo, c)
|
||||
{
|
||||
}
|
||||
|
||||
void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data)
|
||||
void ICMP_Analyzer::Echo(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
EventHandlerPtr f = type == ICMP_ECHO ? icmp_echo_request : icmp_echo_reply;
|
||||
// For handling all Echo related ICMP messages
|
||||
EventHandlerPtr f = 0;
|
||||
|
||||
if ( ip_hdr->NextProto() == IPPROTO_ICMPV6 )
|
||||
f = (icmpp->icmp_type == ICMP6_ECHO_REQUEST)
|
||||
? icmp_echo_request : icmp_echo_reply;
|
||||
else
|
||||
f = (icmpp->icmp_type == ICMP_ECHO)
|
||||
? icmp_echo_request : icmp_echo_reply;
|
||||
|
||||
if ( ! f )
|
||||
return;
|
||||
|
||||
|
@ -313,7 +504,7 @@ void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
|
|||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal());
|
||||
vl->append(BuildICMPVal(icmpp, len, ip_hdr->NextProto() != IPPROTO_ICMP, ip_hdr));
|
||||
vl->append(new Val(iid, TYPE_COUNT));
|
||||
vl->append(new Val(iseq, TYPE_COUNT));
|
||||
vl->append(new StringVal(payload));
|
||||
|
@ -321,66 +512,384 @@ void ICMP_Echo_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
|
|||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
ICMP_Redir_Analyzer::ICMP_Redir_Analyzer(Connection* c)
|
||||
: ICMP_Analyzer(AnalyzerTag::ICMP_Redir, c)
|
||||
{
|
||||
}
|
||||
|
||||
void ICMP_Redir_Analyzer::NextICMP(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data)
|
||||
void ICMP_Analyzer::RouterAdvert(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
uint32 addr = ntohl(icmpp->icmp_hun.ih_void);
|
||||
EventHandlerPtr f = icmp_router_advertisement;
|
||||
uint32 reachable = 0, retrans = 0;
|
||||
|
||||
if ( caplen >= (int)sizeof(reachable) )
|
||||
memcpy(&reachable, data, sizeof(reachable));
|
||||
|
||||
if ( caplen >= (int)sizeof(reachable) + (int)sizeof(retrans) )
|
||||
memcpy(&retrans, data + sizeof(reachable), sizeof(retrans));
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal());
|
||||
vl->append(new AddrVal(htonl(addr)));
|
||||
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
|
||||
vl->append(new Val(icmpp->icmp_num_addrs, TYPE_COUNT)); // Cur Hop Limit
|
||||
vl->append(new Val(icmpp->icmp_wpa & 0x80, TYPE_BOOL)); // Managed
|
||||
vl->append(new Val(icmpp->icmp_wpa & 0x40, TYPE_BOOL)); // Other
|
||||
vl->append(new Val(icmpp->icmp_wpa & 0x20, TYPE_BOOL)); // Home Agent
|
||||
vl->append(new Val((icmpp->icmp_wpa & 0x18)>>3, TYPE_COUNT)); // Pref
|
||||
vl->append(new Val(icmpp->icmp_wpa & 0x04, TYPE_BOOL)); // Proxy
|
||||
vl->append(new Val(icmpp->icmp_wpa & 0x02, TYPE_COUNT)); // Reserved
|
||||
vl->append(new IntervalVal((double)ntohs(icmpp->icmp_lifetime), Seconds));
|
||||
vl->append(new IntervalVal((double)ntohl(reachable), Milliseconds));
|
||||
vl->append(new IntervalVal((double)ntohl(retrans), Milliseconds));
|
||||
|
||||
ConnectionEvent(icmp_redirect, vl);
|
||||
int opt_offset = sizeof(reachable) + sizeof(retrans);
|
||||
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
|
||||
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
|
||||
void ICMP_Context_Analyzer::NextICMP(double t, const struct icmp* icmpp,
|
||||
int len, int caplen, const u_char*& data)
|
||||
void ICMP_Analyzer::NeighborAdvert(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
EventHandlerPtr f = icmp_neighbor_advertisement;
|
||||
IPAddr tgtaddr;
|
||||
|
||||
if ( caplen >= (int)sizeof(in6_addr) )
|
||||
tgtaddr = IPAddr(*((const in6_addr*)data));
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
|
||||
vl->append(new Val(icmpp->icmp_num_addrs & 0x80, TYPE_BOOL)); // Router
|
||||
vl->append(new Val(icmpp->icmp_num_addrs & 0x40, TYPE_BOOL)); // Solicited
|
||||
vl->append(new Val(icmpp->icmp_num_addrs & 0x20, TYPE_BOOL)); // Override
|
||||
vl->append(new AddrVal(tgtaddr));
|
||||
|
||||
int opt_offset = sizeof(in6_addr);
|
||||
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
|
||||
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
|
||||
void ICMP_Analyzer::NeighborSolicit(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
EventHandlerPtr f = icmp_neighbor_solicitation;
|
||||
IPAddr tgtaddr;
|
||||
|
||||
if ( caplen >= (int)sizeof(in6_addr) )
|
||||
tgtaddr = IPAddr(*((const in6_addr*)data));
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
|
||||
vl->append(new AddrVal(tgtaddr));
|
||||
|
||||
int opt_offset = sizeof(in6_addr);
|
||||
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
|
||||
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
|
||||
void ICMP_Analyzer::Redirect(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
EventHandlerPtr f = icmp_redirect;
|
||||
IPAddr tgtaddr, dstaddr;
|
||||
|
||||
if ( caplen >= (int)sizeof(in6_addr) )
|
||||
tgtaddr = IPAddr(*((const in6_addr*)data));
|
||||
|
||||
if ( caplen >= 2 * (int)sizeof(in6_addr) )
|
||||
dstaddr = IPAddr(*((const in6_addr*)(data + sizeof(in6_addr))));
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
|
||||
vl->append(new AddrVal(tgtaddr));
|
||||
vl->append(new AddrVal(dstaddr));
|
||||
|
||||
int opt_offset = 2 * sizeof(in6_addr);
|
||||
vl->append(BuildNDOptionsVal(caplen - opt_offset, data + opt_offset));
|
||||
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
|
||||
void ICMP_Analyzer::RouterSolicit(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
EventHandlerPtr f = icmp_router_solicitation;
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
|
||||
vl->append(BuildNDOptionsVal(caplen, data));
|
||||
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
|
||||
|
||||
void ICMP_Analyzer::Context4(double t, const struct icmp* icmpp,
|
||||
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
EventHandlerPtr f = 0;
|
||||
switch ( type ) {
|
||||
case ICMP_UNREACH: f = icmp_unreachable; break;
|
||||
case ICMP_TIMXCEED: f = icmp_time_exceeded; break;
|
||||
}
|
||||
|
||||
switch ( icmpp->icmp_type )
|
||||
{
|
||||
case ICMP_UNREACH:
|
||||
f = icmp_unreachable;
|
||||
break;
|
||||
|
||||
case ICMP_TIMXCEED:
|
||||
f = icmp_time_exceeded;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( f )
|
||||
{
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal());
|
||||
vl->append(new Val(code, TYPE_COUNT));
|
||||
vl->append(ExtractICMPContext(caplen, data));
|
||||
|
||||
vl->append(BuildICMPVal(icmpp, len, 0, ip_hdr));
|
||||
vl->append(new Val(icmpp->icmp_code, TYPE_COUNT));
|
||||
vl->append(ExtractICMP4Context(caplen, data));
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
|
||||
void ICMP_Analyzer::Context6(double t, const struct icmp* icmpp,
|
||||
int len, int caplen, const u_char*& data, const IP_Hdr* ip_hdr)
|
||||
{
|
||||
EventHandlerPtr f = 0;
|
||||
|
||||
switch ( icmpp->icmp_type )
|
||||
{
|
||||
case ICMP6_DST_UNREACH:
|
||||
f = icmp_unreachable;
|
||||
break;
|
||||
|
||||
case ICMP6_PARAM_PROB:
|
||||
f = icmp_parameter_problem;
|
||||
break;
|
||||
|
||||
case ICMP6_TIME_EXCEEDED:
|
||||
f = icmp_time_exceeded;
|
||||
break;
|
||||
|
||||
case ICMP6_PACKET_TOO_BIG:
|
||||
f = icmp_packet_too_big;
|
||||
break;
|
||||
|
||||
default:
|
||||
f = icmp_error_message;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( f )
|
||||
{
|
||||
val_list* vl = new val_list;
|
||||
vl->append(BuildConnVal());
|
||||
vl->append(BuildICMPVal(icmpp, len, 1, ip_hdr));
|
||||
vl->append(new Val(icmpp->icmp_code, TYPE_COUNT));
|
||||
vl->append(ExtractICMP6Context(caplen, data));
|
||||
ConnectionEvent(f, vl);
|
||||
}
|
||||
}
|
||||
|
||||
VectorVal* ICMP_Analyzer::BuildNDOptionsVal(int caplen, const u_char* data)
|
||||
{
|
||||
static RecordType* icmp6_nd_option_type = 0;
|
||||
static RecordType* icmp6_nd_prefix_info_type = 0;
|
||||
|
||||
if ( ! icmp6_nd_option_type )
|
||||
{
|
||||
icmp6_nd_option_type = internal_type("icmp6_nd_option")->AsRecordType();
|
||||
icmp6_nd_prefix_info_type =
|
||||
internal_type("icmp6_nd_prefix_info")->AsRecordType();
|
||||
}
|
||||
|
||||
VectorVal* vv = new VectorVal(
|
||||
internal_type("icmp6_nd_options")->AsVectorType());
|
||||
|
||||
while ( caplen > 0 )
|
||||
{
|
||||
// Must have at least type & length to continue parsing options.
|
||||
if ( caplen < 2 )
|
||||
{
|
||||
Weird("truncated_ICMPv6_ND_options");
|
||||
break;
|
||||
}
|
||||
|
||||
uint8 type = *((const uint8*)data);
|
||||
uint8 length = *((const uint8*)(data + 1));
|
||||
|
||||
if ( length == 0 )
|
||||
{
|
||||
Weird("zero_length_ICMPv6_ND_option");
|
||||
break;
|
||||
}
|
||||
|
||||
RecordVal* rv = new RecordVal(icmp6_nd_option_type);
|
||||
rv->Assign(0, new Val(type, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(length, TYPE_COUNT));
|
||||
|
||||
// Adjust length to be in units of bytes, exclude type/length fields.
|
||||
length = length * 8 - 2;
|
||||
|
||||
data += 2;
|
||||
caplen -= 2;
|
||||
|
||||
bool set_payload_field = false;
|
||||
|
||||
// Only parse out known options that are there in full.
|
||||
switch ( type ) {
|
||||
case 1:
|
||||
case 2:
|
||||
// Source/Target Link-layer Address option
|
||||
{
|
||||
if ( caplen >= length )
|
||||
{
|
||||
BroString* link_addr = new BroString(data, length, 0);
|
||||
rv->Assign(2, new StringVal(link_addr));
|
||||
}
|
||||
else
|
||||
set_payload_field = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
// Prefix Information option
|
||||
{
|
||||
if ( caplen >= 30 )
|
||||
{
|
||||
RecordVal* info = new RecordVal(icmp6_nd_prefix_info_type);
|
||||
uint8 prefix_len = *((const uint8*)(data));
|
||||
bool L_flag = (*((const uint8*)(data + 1)) & 0x80) != 0;
|
||||
bool A_flag = (*((const uint8*)(data + 1)) & 0x40) != 0;
|
||||
uint32 valid_life = *((const uint32*)(data + 2));
|
||||
uint32 prefer_life = *((const uint32*)(data + 6));
|
||||
in6_addr prefix = *((const in6_addr*)(data + 14));
|
||||
info->Assign(0, new Val(prefix_len, TYPE_COUNT));
|
||||
info->Assign(1, new Val(L_flag, TYPE_BOOL));
|
||||
info->Assign(2, new Val(A_flag, TYPE_BOOL));
|
||||
info->Assign(3, new IntervalVal((double)ntohl(valid_life), Seconds));
|
||||
info->Assign(4, new IntervalVal((double)ntohl(prefer_life), Seconds));
|
||||
info->Assign(5, new AddrVal(IPAddr(prefix)));
|
||||
rv->Assign(3, info);
|
||||
}
|
||||
|
||||
else
|
||||
set_payload_field = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
// Redirected Header option
|
||||
{
|
||||
if ( caplen >= length )
|
||||
{
|
||||
const u_char* hdr = data + 6;
|
||||
rv->Assign(4, ExtractICMP6Context(length - 6, hdr));
|
||||
}
|
||||
|
||||
else
|
||||
set_payload_field = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 5:
|
||||
// MTU option
|
||||
{
|
||||
if ( caplen >= 6 )
|
||||
rv->Assign(5, new Val(ntohl(*((const uint32*)(data + 2))),
|
||||
TYPE_COUNT));
|
||||
else
|
||||
set_payload_field = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
set_payload_field = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( set_payload_field )
|
||||
{
|
||||
BroString* payload =
|
||||
new BroString(data, min((int)length, caplen), 0);
|
||||
rv->Assign(6, new StringVal(payload));
|
||||
}
|
||||
|
||||
data += length;
|
||||
caplen -= length;
|
||||
|
||||
vv->Assign(vv->Size(), rv, 0);
|
||||
}
|
||||
|
||||
return vv;
|
||||
}
|
||||
|
||||
int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
|
||||
{
|
||||
is_one_way = false;
|
||||
|
||||
// return the counterpart type if one exists. This allows us
|
||||
// Return the counterpart type if one exists. This allows us
|
||||
// to track corresponding ICMP requests/replies.
|
||||
// Note that for the two-way ICMP messages, icmp_code is
|
||||
// always 0 (RFC 792).
|
||||
switch ( icmp_type ) {
|
||||
case ICMP_ECHO: return ICMP_ECHOREPLY;
|
||||
case ICMP_ECHOREPLY: return ICMP_ECHO;
|
||||
|
||||
case ICMP_TSTAMP: return ICMP_TSTAMPREPLY;
|
||||
case ICMP_TSTAMPREPLY: return ICMP_TSTAMP;
|
||||
|
||||
case ICMP_IREQ: return ICMP_IREQREPLY;
|
||||
case ICMP_IREQREPLY: return ICMP_IREQ;
|
||||
|
||||
case ICMP_ROUTERSOLICIT: return ICMP_ROUTERADVERT;
|
||||
|
||||
case ICMP_MASKREQ: return ICMP_MASKREPLY;
|
||||
case ICMP_MASKREPLY: return ICMP_MASKREQ;
|
||||
|
||||
default: is_one_way = true; return icmp_code;
|
||||
}
|
||||
}
|
||||
|
||||
int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way)
|
||||
{
|
||||
is_one_way = false;
|
||||
|
||||
switch ( icmp_type ) {
|
||||
case ICMP6_ECHO_REQUEST: return ICMP6_ECHO_REPLY;
|
||||
case ICMP6_ECHO_REPLY: return ICMP6_ECHO_REQUEST;
|
||||
|
||||
case ND_ROUTER_SOLICIT: return ND_ROUTER_ADVERT;
|
||||
case ND_ROUTER_ADVERT: return ND_ROUTER_SOLICIT;
|
||||
|
||||
case ND_NEIGHBOR_SOLICIT: return ND_NEIGHBOR_ADVERT;
|
||||
case ND_NEIGHBOR_ADVERT: return ND_NEIGHBOR_SOLICIT;
|
||||
|
||||
case MLD_LISTENER_QUERY: return MLD_LISTENER_REPORT;
|
||||
case MLD_LISTENER_REPORT: return MLD_LISTENER_QUERY;
|
||||
|
||||
// ICMP node information query and response respectively (not defined in
|
||||
// icmp6.h)
|
||||
case 139: return 140;
|
||||
case 140: return 139;
|
||||
|
||||
// Home Agent Address Discovery Request Message and reply
|
||||
case 144: return 145;
|
||||
case 145: return 144;
|
||||
|
||||
// TODO: Add further counterparts.
|
||||
|
||||
default: is_one_way = true; return icmp_code;
|
||||
}
|
||||
}
|
||||
|
|
123
src/ICMP.h
123
src/ICMP.h
|
@ -33,21 +33,54 @@ protected:
|
|||
virtual bool IsReuse(double t, const u_char* pkt);
|
||||
virtual unsigned int MemoryAllocation() const;
|
||||
|
||||
void ICMPEvent(EventHandlerPtr f);
|
||||
void ICMPEvent(EventHandlerPtr f, const struct icmp* icmpp, int len,
|
||||
int icmpv6, const IP_Hdr* ip_hdr);
|
||||
|
||||
void Echo(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
void Context(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
void Redirect(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
void RouterAdvert(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
void NeighborAdvert(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
void NeighborSolicit(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
void RouterSolicit(double t, const struct icmp* icmpp, int len,
|
||||
int caplen, const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
|
||||
void Describe(ODesc* d) const;
|
||||
|
||||
RecordVal* BuildICMPVal();
|
||||
RecordVal* BuildICMPVal(const struct icmp* icmpp, int len, int icmpv6,
|
||||
const IP_Hdr* ip_hdr);
|
||||
|
||||
virtual void NextICMP(double t, const struct icmp* icmpp,
|
||||
int len, int caplen, const u_char*& data);
|
||||
void NextICMP4(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr );
|
||||
|
||||
RecordVal* ExtractICMPContext(int len, const u_char*& data);
|
||||
RecordVal* ExtractICMP4Context(int len, const u_char*& data);
|
||||
|
||||
void Context4(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
|
||||
TransportProto GetContextProtocol(const IP_Hdr* ip_hdr, uint32* src_port,
|
||||
uint32* dst_port);
|
||||
|
||||
void NextICMP6(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr );
|
||||
|
||||
RecordVal* ExtractICMP6Context(int len, const u_char*& data);
|
||||
|
||||
void Context6(double t, const struct icmp* icmpp, int len, int caplen,
|
||||
const u_char*& data, const IP_Hdr* ip_hdr);
|
||||
|
||||
// RFC 4861 Neighbor Discover message options
|
||||
VectorVal* BuildNDOptionsVal(int caplen, const u_char* data);
|
||||
|
||||
RecordVal* icmp_conn_val;
|
||||
int type;
|
||||
int code;
|
||||
int len;
|
||||
|
||||
int request_len, reply_len;
|
||||
|
||||
RuleMatcherState matcher_state;
|
||||
|
@ -56,81 +89,9 @@ private:
|
|||
void UpdateEndpointVal(RecordVal* endp, int is_orig);
|
||||
};
|
||||
|
||||
class ICMP_Echo_Analyzer : public ICMP_Analyzer {
|
||||
public:
|
||||
ICMP_Echo_Analyzer(Connection* conn);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new ICMP_Echo_Analyzer(conn); }
|
||||
|
||||
static bool Available() { return icmp_echo_request || icmp_echo_reply; }
|
||||
|
||||
protected:
|
||||
ICMP_Echo_Analyzer() { }
|
||||
|
||||
virtual void NextICMP(double t, const struct icmp* icmpp,
|
||||
int len, int caplen, const u_char*& data);
|
||||
};
|
||||
|
||||
class ICMP_Redir_Analyzer : public ICMP_Analyzer {
|
||||
public:
|
||||
ICMP_Redir_Analyzer(Connection* conn);
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new ICMP_Redir_Analyzer(conn); }
|
||||
|
||||
static bool Available() { return icmp_redirect; }
|
||||
|
||||
protected:
|
||||
ICMP_Redir_Analyzer() { }
|
||||
|
||||
virtual void NextICMP(double t, const struct icmp* icmpp,
|
||||
int len, int caplen, const u_char*& data);
|
||||
};
|
||||
|
||||
class ICMP_Context_Analyzer : public ICMP_Analyzer {
|
||||
public:
|
||||
ICMP_Context_Analyzer(AnalyzerTag::Tag tag, Connection* conn)
|
||||
: ICMP_Analyzer(tag, conn) { }
|
||||
|
||||
protected:
|
||||
ICMP_Context_Analyzer() { }
|
||||
|
||||
virtual void NextICMP(double t, const struct icmp* icmpp,
|
||||
int len, int caplen, const u_char*& data);
|
||||
};
|
||||
|
||||
class ICMP_TimeExceeded_Analyzer : public ICMP_Context_Analyzer {
|
||||
public:
|
||||
ICMP_TimeExceeded_Analyzer(Connection* conn)
|
||||
: ICMP_Context_Analyzer(AnalyzerTag::ICMP_TimeExceeded, conn) { }
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new ICMP_TimeExceeded_Analyzer(conn); }
|
||||
|
||||
static bool Available() { return icmp_time_exceeded; }
|
||||
|
||||
protected:
|
||||
ICMP_TimeExceeded_Analyzer() { }
|
||||
};
|
||||
|
||||
class ICMP_Unreachable_Analyzer : public ICMP_Context_Analyzer {
|
||||
public:
|
||||
ICMP_Unreachable_Analyzer(Connection* conn)
|
||||
: ICMP_Context_Analyzer(AnalyzerTag::ICMP_Unreachable, conn) { }
|
||||
|
||||
static Analyzer* InstantiateAnalyzer(Connection* conn)
|
||||
{ return new ICMP_Unreachable_Analyzer(conn); }
|
||||
|
||||
static bool Available() { return icmp_unreachable; }
|
||||
|
||||
protected:
|
||||
ICMP_Unreachable_Analyzer() { }
|
||||
};
|
||||
|
||||
|
||||
// Returns the counterpart type to the given type (e.g., the counterpart
|
||||
// to ICMP_ECHOREPLY is ICMP_ECHO).
|
||||
extern int ICMP_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
|
||||
extern int ICMP4_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
|
||||
extern int ICMP6_counterpart(int icmp_type, int icmp_code, bool& is_one_way);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -372,7 +372,7 @@ ID* ID::Unserialize(UnserialInfo* info)
|
|||
|
||||
Ref(id);
|
||||
global_scope()->Insert(id->Name(), id);
|
||||
#ifdef USE_PERFTOOLS
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
heap_checker->IgnoreObject(id);
|
||||
#endif
|
||||
}
|
||||
|
|
633
src/IP.cc
Normal file
633
src/IP.cc
Normal file
|
@ -0,0 +1,633 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "IP.h"
|
||||
#include "Type.h"
|
||||
#include "Val.h"
|
||||
#include "Var.h"
|
||||
|
||||
static RecordType* ip4_hdr_type = 0;
|
||||
static RecordType* ip6_hdr_type = 0;
|
||||
static RecordType* ip6_ext_hdr_type = 0;
|
||||
static RecordType* ip6_option_type = 0;
|
||||
static RecordType* ip6_hopopts_type = 0;
|
||||
static RecordType* ip6_dstopts_type = 0;
|
||||
static RecordType* ip6_routing_type = 0;
|
||||
static RecordType* ip6_fragment_type = 0;
|
||||
static RecordType* ip6_ah_type = 0;
|
||||
static RecordType* ip6_esp_type = 0;
|
||||
static RecordType* ip6_mob_type = 0;
|
||||
static RecordType* ip6_mob_msg_type = 0;
|
||||
static RecordType* ip6_mob_brr_type = 0;
|
||||
static RecordType* ip6_mob_hoti_type = 0;
|
||||
static RecordType* ip6_mob_coti_type = 0;
|
||||
static RecordType* ip6_mob_hot_type = 0;
|
||||
static RecordType* ip6_mob_cot_type = 0;
|
||||
static RecordType* ip6_mob_bu_type = 0;
|
||||
static RecordType* ip6_mob_back_type = 0;
|
||||
static RecordType* ip6_mob_be_type = 0;
|
||||
|
||||
static inline RecordType* hdrType(RecordType*& type, const char* name)
|
||||
{
|
||||
if ( ! type )
|
||||
type = internal_type(name)->AsRecordType();
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static VectorVal* BuildOptionsVal(const u_char* data, int len)
|
||||
{
|
||||
VectorVal* vv = new VectorVal(internal_type("ip6_options")->AsVectorType());
|
||||
|
||||
while ( len > 0 )
|
||||
{
|
||||
const struct ip6_opt* opt = (const struct ip6_opt*) data;
|
||||
RecordVal* rv = new RecordVal(hdrType(ip6_option_type, "ip6_option"));
|
||||
rv->Assign(0, new Val(opt->ip6o_type, TYPE_COUNT));
|
||||
|
||||
if ( opt->ip6o_type == 0 )
|
||||
{
|
||||
// Pad1 option
|
||||
rv->Assign(1, new Val(0, TYPE_COUNT));
|
||||
rv->Assign(2, new StringVal(""));
|
||||
data += sizeof(uint8);
|
||||
len -= sizeof(uint8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PadN or other option
|
||||
uint16 off = 2 * sizeof(uint8);
|
||||
rv->Assign(1, new Val(opt->ip6o_len, TYPE_COUNT));
|
||||
rv->Assign(2, new StringVal(
|
||||
new BroString(data + off, opt->ip6o_len, 1)));
|
||||
data += opt->ip6o_len + off;
|
||||
len -= opt->ip6o_len + off;
|
||||
}
|
||||
|
||||
vv->Assign(vv->Size(), rv, 0);
|
||||
}
|
||||
|
||||
return vv;
|
||||
}
|
||||
|
||||
RecordVal* IPv6_Hdr::BuildRecordVal(VectorVal* chain) const
|
||||
{
|
||||
RecordVal* rv = 0;
|
||||
|
||||
switch ( type ) {
|
||||
case IPPROTO_IPV6:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_hdr_type, "ip6_hdr"));
|
||||
const struct ip6_hdr* ip6 = (const struct ip6_hdr*)data;
|
||||
rv->Assign(0, new Val((ntohl(ip6->ip6_flow) & 0x0ff00000)>>20, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(ntohl(ip6->ip6_flow) & 0x000fffff, TYPE_COUNT));
|
||||
rv->Assign(2, new Val(ntohs(ip6->ip6_plen), TYPE_COUNT));
|
||||
rv->Assign(3, new Val(ip6->ip6_nxt, TYPE_COUNT));
|
||||
rv->Assign(4, new Val(ip6->ip6_hlim, TYPE_COUNT));
|
||||
rv->Assign(5, new AddrVal(IPAddr(ip6->ip6_src)));
|
||||
rv->Assign(6, new AddrVal(IPAddr(ip6->ip6_dst)));
|
||||
if ( ! chain )
|
||||
chain = new VectorVal(
|
||||
internal_type("ip6_ext_hdr_chain")->AsVectorType());
|
||||
rv->Assign(7, chain);
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_HOPOPTS:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_hopopts_type, "ip6_hopopts"));
|
||||
const struct ip6_hbh* hbh = (const struct ip6_hbh*)data;
|
||||
rv->Assign(0, new Val(hbh->ip6h_nxt, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(hbh->ip6h_len, TYPE_COUNT));
|
||||
uint16 off = 2 * sizeof(uint8);
|
||||
rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_DSTOPTS:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_dstopts_type, "ip6_dstopts"));
|
||||
const struct ip6_dest* dst = (const struct ip6_dest*)data;
|
||||
rv->Assign(0, new Val(dst->ip6d_nxt, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(dst->ip6d_len, TYPE_COUNT));
|
||||
uint16 off = 2 * sizeof(uint8);
|
||||
rv->Assign(2, BuildOptionsVal(data + off, Length() - off));
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_ROUTING:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_routing_type, "ip6_routing"));
|
||||
const struct ip6_rthdr* rt = (const struct ip6_rthdr*)data;
|
||||
rv->Assign(0, new Val(rt->ip6r_nxt, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(rt->ip6r_len, TYPE_COUNT));
|
||||
rv->Assign(2, new Val(rt->ip6r_type, TYPE_COUNT));
|
||||
rv->Assign(3, new Val(rt->ip6r_segleft, TYPE_COUNT));
|
||||
uint16 off = 4 * sizeof(uint8);
|
||||
rv->Assign(4, new StringVal(new BroString(data + off, Length() - off, 1)));
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_FRAGMENT:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_fragment_type, "ip6_fragment"));
|
||||
const struct ip6_frag* frag = (const struct ip6_frag*)data;
|
||||
rv->Assign(0, new Val(frag->ip6f_nxt, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(frag->ip6f_reserved, TYPE_COUNT));
|
||||
rv->Assign(2, new Val((ntohs(frag->ip6f_offlg) & 0xfff8)>>3, TYPE_COUNT));
|
||||
rv->Assign(3, new Val((ntohs(frag->ip6f_offlg) & 0x0006)>>1, TYPE_COUNT));
|
||||
rv->Assign(4, new Val(ntohs(frag->ip6f_offlg) & 0x0001, TYPE_BOOL));
|
||||
rv->Assign(5, new Val(ntohl(frag->ip6f_ident), TYPE_COUNT));
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_AH:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_ah_type, "ip6_ah"));
|
||||
rv->Assign(0, new Val(((ip6_ext*)data)->ip6e_nxt, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(((ip6_ext*)data)->ip6e_len, TYPE_COUNT));
|
||||
rv->Assign(2, new Val(ntohs(((uint16*)data)[1]), TYPE_COUNT));
|
||||
rv->Assign(3, new Val(ntohl(((uint32*)data)[1]), TYPE_COUNT));
|
||||
|
||||
if ( Length() >= 12 )
|
||||
{
|
||||
// Sequence Number and ICV fields can only be extracted if
|
||||
// Payload Len was non-zero for this header.
|
||||
rv->Assign(4, new Val(ntohl(((uint32*)data)[2]), TYPE_COUNT));
|
||||
uint16 off = 3 * sizeof(uint32);
|
||||
rv->Assign(5, new StringVal(new BroString(data + off, Length() - off, 1)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IPPROTO_ESP:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_esp_type, "ip6_esp"));
|
||||
const uint32* esp = (const uint32*)data;
|
||||
rv->Assign(0, new Val(ntohl(esp[0]), TYPE_COUNT));
|
||||
rv->Assign(1, new Val(ntohl(esp[1]), TYPE_COUNT));
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
case IPPROTO_MOBILITY:
|
||||
{
|
||||
rv = new RecordVal(hdrType(ip6_mob_type, "ip6_mobility_hdr"));
|
||||
const struct ip6_mobility* mob = (const struct ip6_mobility*) data;
|
||||
rv->Assign(0, new Val(mob->ip6mob_payload, TYPE_COUNT));
|
||||
rv->Assign(1, new Val(mob->ip6mob_len, TYPE_COUNT));
|
||||
rv->Assign(2, new Val(mob->ip6mob_type, TYPE_COUNT));
|
||||
rv->Assign(3, new Val(mob->ip6mob_rsv, TYPE_COUNT));
|
||||
rv->Assign(4, new Val(ntohs(mob->ip6mob_chksum), TYPE_COUNT));
|
||||
|
||||
RecordVal* msg = new RecordVal(hdrType(ip6_mob_msg_type, "ip6_mobility_msg"));
|
||||
msg->Assign(0, new Val(mob->ip6mob_type, TYPE_COUNT));
|
||||
|
||||
uint16 off = sizeof(ip6_mobility);
|
||||
const u_char* msg_data = data + off;
|
||||
|
||||
switch ( mob->ip6mob_type ) {
|
||||
case 0:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_brr"));
|
||||
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
|
||||
off += sizeof(uint16);
|
||||
m->Assign(1, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(1, m);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_hoti"));
|
||||
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
|
||||
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
|
||||
off += sizeof(uint16) + sizeof(uint64);
|
||||
m->Assign(2, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(2, m);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_coti"));
|
||||
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
|
||||
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
|
||||
off += sizeof(uint16) + sizeof(uint64);
|
||||
m->Assign(2, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(3, m);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_hot"));
|
||||
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
|
||||
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
|
||||
m->Assign(2, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16) + sizeof(uint64)))), TYPE_COUNT));
|
||||
off += sizeof(uint16) + 2 * sizeof(uint64);
|
||||
m->Assign(3, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(4, m);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_cot"));
|
||||
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
|
||||
m->Assign(1, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
|
||||
m->Assign(2, new Val(ntohll(*((uint64*)(msg_data + sizeof(uint16) + sizeof(uint64)))), TYPE_COUNT));
|
||||
off += sizeof(uint16) + 2 * sizeof(uint64);
|
||||
m->Assign(3, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(5, m);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_bu"));
|
||||
m->Assign(0, new Val(ntohs(*((uint16*)msg_data)), TYPE_COUNT));
|
||||
m->Assign(1, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x8000, TYPE_BOOL));
|
||||
m->Assign(2, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x4000, TYPE_BOOL));
|
||||
m->Assign(3, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x2000, TYPE_BOOL));
|
||||
m->Assign(4, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))) & 0x1000, TYPE_BOOL));
|
||||
m->Assign(5, new Val(ntohs(*((uint16*)(msg_data + 2*sizeof(uint16)))), TYPE_COUNT));
|
||||
off += 3 * sizeof(uint16);
|
||||
m->Assign(6, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(6, m);
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_back"));
|
||||
m->Assign(0, new Val(*((uint8*)msg_data), TYPE_COUNT));
|
||||
m->Assign(1, new Val(*((uint8*)(msg_data + sizeof(uint8))) & 0x80, TYPE_BOOL));
|
||||
m->Assign(2, new Val(ntohs(*((uint16*)(msg_data + sizeof(uint16)))), TYPE_COUNT));
|
||||
m->Assign(3, new Val(ntohs(*((uint16*)(msg_data + 2*sizeof(uint16)))), TYPE_COUNT));
|
||||
off += 3 * sizeof(uint16);
|
||||
m->Assign(4, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(7, m);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
RecordVal* m = new RecordVal(hdrType(ip6_mob_brr_type, "ip6_mobility_be"));
|
||||
m->Assign(0, new Val(*((uint8*)msg_data), TYPE_COUNT));
|
||||
const in6_addr* hoa = (const in6_addr*)(msg_data + sizeof(uint16));
|
||||
m->Assign(1, new AddrVal(IPAddr(*hoa)));
|
||||
off += sizeof(uint16) + sizeof(in6_addr);
|
||||
m->Assign(2, BuildOptionsVal(data + off, Length() - off));
|
||||
msg->Assign(8, m);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
reporter->Weird(fmt("unknown_mobility_type_%d", mob->ip6mob_type));
|
||||
break;
|
||||
}
|
||||
|
||||
rv->Assign(5, msg);
|
||||
}
|
||||
break;
|
||||
#endif //ENABLE_MOBILE_IPV6
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
RecordVal* IP_Hdr::BuildIPHdrVal() const
|
||||
{
|
||||
RecordVal* rval = 0;
|
||||
|
||||
if ( ip4 )
|
||||
{
|
||||
rval = new RecordVal(hdrType(ip4_hdr_type, "ip4_hdr"));
|
||||
rval->Assign(0, new Val(ip4->ip_hl * 4, TYPE_COUNT));
|
||||
rval->Assign(1, new Val(ip4->ip_tos, TYPE_COUNT));
|
||||
rval->Assign(2, new Val(ntohs(ip4->ip_len), TYPE_COUNT));
|
||||
rval->Assign(3, new Val(ntohs(ip4->ip_id), TYPE_COUNT));
|
||||
rval->Assign(4, new Val(ip4->ip_ttl, TYPE_COUNT));
|
||||
rval->Assign(5, new Val(ip4->ip_p, TYPE_COUNT));
|
||||
rval->Assign(6, new AddrVal(ip4->ip_src.s_addr));
|
||||
rval->Assign(7, new AddrVal(ip4->ip_dst.s_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = ((*ip6_hdrs)[0])->BuildRecordVal(ip6_hdrs->BuildVal());
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
RecordVal* IP_Hdr::BuildPktHdrVal() const
|
||||
{
|
||||
static RecordType* pkt_hdr_type = 0;
|
||||
static RecordType* tcp_hdr_type = 0;
|
||||
static RecordType* udp_hdr_type = 0;
|
||||
static RecordType* icmp_hdr_type = 0;
|
||||
|
||||
if ( ! pkt_hdr_type )
|
||||
{
|
||||
pkt_hdr_type = internal_type("pkt_hdr")->AsRecordType();
|
||||
tcp_hdr_type = internal_type("tcp_hdr")->AsRecordType();
|
||||
udp_hdr_type = internal_type("udp_hdr")->AsRecordType();
|
||||
icmp_hdr_type = internal_type("icmp_hdr")->AsRecordType();
|
||||
}
|
||||
|
||||
RecordVal* pkt_hdr = new RecordVal(pkt_hdr_type);
|
||||
|
||||
if ( ip4 )
|
||||
pkt_hdr->Assign(0, BuildIPHdrVal());
|
||||
else
|
||||
pkt_hdr->Assign(1, BuildIPHdrVal());
|
||||
|
||||
// L4 header.
|
||||
const u_char* data = Payload();
|
||||
|
||||
int proto = NextProto();
|
||||
switch ( proto ) {
|
||||
case IPPROTO_TCP:
|
||||
{
|
||||
const struct tcphdr* tp = (const struct tcphdr*) data;
|
||||
RecordVal* tcp_hdr = new RecordVal(tcp_hdr_type);
|
||||
|
||||
int tcp_hdr_len = tp->th_off * 4;
|
||||
int data_len = PayloadLen() - tcp_hdr_len;
|
||||
|
||||
tcp_hdr->Assign(0, new PortVal(ntohs(tp->th_sport), TRANSPORT_TCP));
|
||||
tcp_hdr->Assign(1, new PortVal(ntohs(tp->th_dport), TRANSPORT_TCP));
|
||||
tcp_hdr->Assign(2, new Val(uint32(ntohl(tp->th_seq)), TYPE_COUNT));
|
||||
tcp_hdr->Assign(3, new Val(uint32(ntohl(tp->th_ack)), TYPE_COUNT));
|
||||
tcp_hdr->Assign(4, new Val(tcp_hdr_len, TYPE_COUNT));
|
||||
tcp_hdr->Assign(5, new Val(data_len, TYPE_COUNT));
|
||||
tcp_hdr->Assign(6, new Val(tp->th_flags, TYPE_COUNT));
|
||||
tcp_hdr->Assign(7, new Val(ntohs(tp->th_win), TYPE_COUNT));
|
||||
|
||||
pkt_hdr->Assign(2, tcp_hdr);
|
||||
break;
|
||||
}
|
||||
|
||||
case IPPROTO_UDP:
|
||||
{
|
||||
const struct udphdr* up = (const struct udphdr*) data;
|
||||
RecordVal* udp_hdr = new RecordVal(udp_hdr_type);
|
||||
|
||||
udp_hdr->Assign(0, new PortVal(ntohs(up->uh_sport), TRANSPORT_UDP));
|
||||
udp_hdr->Assign(1, new PortVal(ntohs(up->uh_dport), TRANSPORT_UDP));
|
||||
udp_hdr->Assign(2, new Val(ntohs(up->uh_ulen), TYPE_COUNT));
|
||||
|
||||
pkt_hdr->Assign(3, udp_hdr);
|
||||
break;
|
||||
}
|
||||
|
||||
case IPPROTO_ICMP:
|
||||
{
|
||||
const struct icmp* icmpp = (const struct icmp *) data;
|
||||
RecordVal* icmp_hdr = new RecordVal(icmp_hdr_type);
|
||||
|
||||
icmp_hdr->Assign(0, new Val(icmpp->icmp_type, TYPE_COUNT));
|
||||
|
||||
pkt_hdr->Assign(4, icmp_hdr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// This is not a protocol we understand.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pkt_hdr;
|
||||
}
|
||||
|
||||
static inline bool isIPv6ExtHeader(uint8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_ROUTING:
|
||||
case IPPROTO_DSTOPTS:
|
||||
case IPPROTO_FRAGMENT:
|
||||
case IPPROTO_AH:
|
||||
case IPPROTO_ESP:
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
case IPPROTO_MOBILITY:
|
||||
#endif
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void IPv6_Hdr_Chain::Init(const struct ip6_hdr* ip6, int total_len,
|
||||
bool set_next, uint16 next)
|
||||
{
|
||||
length = 0;
|
||||
uint8 current_type, next_type;
|
||||
next_type = IPPROTO_IPV6;
|
||||
const u_char* hdrs = (const u_char*) ip6;
|
||||
|
||||
if ( total_len < (int)sizeof(struct ip6_hdr) )
|
||||
reporter->InternalError("IPv6_HdrChain::Init with truncated IP header");
|
||||
|
||||
do
|
||||
{
|
||||
// We can't determine a given header's length if there's less than
|
||||
// two bytes of data available (2nd byte of extension headers is length)
|
||||
if ( total_len < 2 )
|
||||
return;
|
||||
|
||||
current_type = next_type;
|
||||
IPv6_Hdr* p = new IPv6_Hdr(current_type, hdrs);
|
||||
|
||||
next_type = p->NextHdr();
|
||||
uint16 cur_len = p->Length();
|
||||
|
||||
// If this header is truncated, don't add it to chain, don't go further.
|
||||
if ( cur_len > total_len )
|
||||
{
|
||||
delete p;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( set_next && next_type == IPPROTO_FRAGMENT )
|
||||
{
|
||||
p->ChangeNext(next);
|
||||
next_type = next;
|
||||
}
|
||||
|
||||
chain.push_back(p);
|
||||
|
||||
// Check for routing headers and remember final destination address.
|
||||
if ( current_type == IPPROTO_ROUTING )
|
||||
ProcessRoutingHeader((const struct ip6_rthdr*) hdrs, cur_len);
|
||||
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
// Only Mobile IPv6 has a destination option we care about right now.
|
||||
if ( current_type == IPPROTO_DSTOPTS )
|
||||
ProcessDstOpts((const struct ip6_dest*) hdrs, cur_len);
|
||||
#endif
|
||||
|
||||
hdrs += cur_len;
|
||||
length += cur_len;
|
||||
total_len -= cur_len;
|
||||
|
||||
} while ( current_type != IPPROTO_FRAGMENT &&
|
||||
current_type != IPPROTO_ESP &&
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
current_type != IPPROTO_MOBILITY &&
|
||||
#endif
|
||||
isIPv6ExtHeader(next_type) );
|
||||
}
|
||||
|
||||
void IPv6_Hdr_Chain::ProcessRoutingHeader(const struct ip6_rthdr* r, uint16 len)
|
||||
{
|
||||
if ( finalDst )
|
||||
{
|
||||
// RFC 2460 section 4.1 says Routing should occur at most once.
|
||||
reporter->Weird(SrcAddr(), DstAddr(), "multiple_routing_headers");
|
||||
return;
|
||||
}
|
||||
|
||||
// Last 16 bytes of header (for all known types) is the address we want.
|
||||
const in6_addr* addr = (const in6_addr*)(((const u_char*)r) + len - 16);
|
||||
|
||||
switch ( r->ip6r_type ) {
|
||||
case 0: // Defined by RFC 2460, deprecated by RFC 5095
|
||||
{
|
||||
if ( r->ip6r_segleft > 0 && r->ip6r_len >= 2 )
|
||||
{
|
||||
if ( r->ip6r_len % 2 == 0 )
|
||||
finalDst = new IPAddr(*addr);
|
||||
else
|
||||
reporter->Weird(SrcAddr(), DstAddr(), "odd_routing0_len");
|
||||
}
|
||||
|
||||
// Always raise a weird since this type is deprecated.
|
||||
reporter->Weird(SrcAddr(), DstAddr(), "routing0_hdr");
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
case 2: // Defined by Mobile IPv6 RFC 6275.
|
||||
{
|
||||
if ( r->ip6r_segleft > 0 )
|
||||
{
|
||||
if ( r->ip6r_len == 2 )
|
||||
finalDst = new IPAddr(*addr);
|
||||
else
|
||||
reporter->Weird(SrcAddr(), DstAddr(), "bad_routing2_len");
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
reporter->Weird(fmt("unknown_routing_type_%d", r->ip6r_type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
void IPv6_Hdr_Chain::ProcessDstOpts(const struct ip6_dest* d, uint16 len)
|
||||
{
|
||||
const u_char* data = (const u_char*) d;
|
||||
len -= 2 * sizeof(uint8);
|
||||
data += 2* sizeof(uint8);
|
||||
|
||||
while ( len > 0 )
|
||||
{
|
||||
const struct ip6_opt* opt = (const struct ip6_opt*) data;
|
||||
switch ( opt->ip6o_type ) {
|
||||
case 201: // Home Address Option, Mobile IPv6 RFC 6275 section 6.3
|
||||
{
|
||||
if ( opt->ip6o_len == 16 )
|
||||
if ( homeAddr )
|
||||
reporter->Weird(SrcAddr(), DstAddr(), "multiple_home_addr_opts");
|
||||
else
|
||||
homeAddr = new IPAddr(*((const in6_addr*)(data + 2)));
|
||||
else
|
||||
reporter->Weird(SrcAddr(), DstAddr(), "bad_home_addr_len");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( opt->ip6o_type == 0 )
|
||||
{
|
||||
data += sizeof(uint8);
|
||||
len -= sizeof(uint8);
|
||||
}
|
||||
else
|
||||
{
|
||||
data += 2 * sizeof(uint8) + opt->ip6o_len;
|
||||
len -= 2 * sizeof(uint8) + opt->ip6o_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
VectorVal* IPv6_Hdr_Chain::BuildVal() const
|
||||
{
|
||||
if ( ! ip6_ext_hdr_type )
|
||||
{
|
||||
ip6_ext_hdr_type = internal_type("ip6_ext_hdr")->AsRecordType();
|
||||
ip6_hopopts_type = internal_type("ip6_hopopts")->AsRecordType();
|
||||
ip6_dstopts_type = internal_type("ip6_dstopts")->AsRecordType();
|
||||
ip6_routing_type = internal_type("ip6_routing")->AsRecordType();
|
||||
ip6_fragment_type = internal_type("ip6_fragment")->AsRecordType();
|
||||
ip6_ah_type = internal_type("ip6_ah")->AsRecordType();
|
||||
ip6_esp_type = internal_type("ip6_esp")->AsRecordType();
|
||||
ip6_mob_type = internal_type("ip6_mobility_hdr")->AsRecordType();
|
||||
}
|
||||
|
||||
VectorVal* rval = new VectorVal(
|
||||
internal_type("ip6_ext_hdr_chain")->AsVectorType());
|
||||
|
||||
for ( size_t i = 1; i < chain.size(); ++i )
|
||||
{
|
||||
RecordVal* v = chain[i]->BuildRecordVal();
|
||||
RecordVal* ext_hdr = new RecordVal(ip6_ext_hdr_type);
|
||||
uint8 type = chain[i]->Type();
|
||||
ext_hdr->Assign(0, new Val(type, TYPE_COUNT));
|
||||
|
||||
switch (type) {
|
||||
case IPPROTO_HOPOPTS:
|
||||
ext_hdr->Assign(1, v);
|
||||
break;
|
||||
case IPPROTO_DSTOPTS:
|
||||
ext_hdr->Assign(2, v);
|
||||
break;
|
||||
case IPPROTO_ROUTING:
|
||||
ext_hdr->Assign(3, v);
|
||||
break;
|
||||
case IPPROTO_FRAGMENT:
|
||||
ext_hdr->Assign(4, v);
|
||||
break;
|
||||
case IPPROTO_AH:
|
||||
ext_hdr->Assign(5, v);
|
||||
break;
|
||||
case IPPROTO_ESP:
|
||||
ext_hdr->Assign(6, v);
|
||||
break;
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
case IPPROTO_MOBILITY:
|
||||
ext_hdr->Assign(7, v);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
reporter->InternalError("IPv6_Hdr_Chain bad header %d", type);
|
||||
break;
|
||||
}
|
||||
rval->Assign(rval->Size(), ext_hdr, 0);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
574
src/IP.h
574
src/IP.h
|
@ -4,67 +4,370 @@
|
|||
#define ip_h
|
||||
|
||||
#include "config.h"
|
||||
#include "net_util.h"
|
||||
#include "IPAddr.h"
|
||||
#include "Reporter.h"
|
||||
#include "Val.h"
|
||||
#include "Type.h"
|
||||
#include <vector>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
#include <net_util.h>
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
|
||||
#ifndef IPPROTO_MOBILITY
|
||||
#define IPPROTO_MOBILITY 135
|
||||
#endif
|
||||
|
||||
struct ip6_mobility {
|
||||
uint8 ip6mob_payload;
|
||||
uint8 ip6mob_len;
|
||||
uint8 ip6mob_type;
|
||||
uint8 ip6mob_rsv;
|
||||
uint16 ip6mob_chksum;
|
||||
};
|
||||
|
||||
#endif //ENABLE_MOBILE_IPV6
|
||||
|
||||
/**
|
||||
* Base class for IPv6 header/extensions.
|
||||
*/
|
||||
class IPv6_Hdr {
|
||||
public:
|
||||
/**
|
||||
* Construct an IPv6 header or extension header from assigned type number.
|
||||
*/
|
||||
IPv6_Hdr(uint8 t, const u_char* d) : type(t), data(d) {}
|
||||
|
||||
/**
|
||||
* Replace the value of the next protocol field.
|
||||
*/
|
||||
void ChangeNext(uint8 next_type)
|
||||
{
|
||||
switch ( type ) {
|
||||
case IPPROTO_IPV6:
|
||||
((ip6_hdr*)data)->ip6_nxt = next_type;
|
||||
break;
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_DSTOPTS:
|
||||
case IPPROTO_ROUTING:
|
||||
case IPPROTO_FRAGMENT:
|
||||
case IPPROTO_AH:
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
case IPPROTO_MOBILITY:
|
||||
#endif
|
||||
((ip6_ext*)data)->ip6e_nxt = next_type;
|
||||
break;
|
||||
case IPPROTO_ESP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
~IPv6_Hdr() {}
|
||||
|
||||
/**
|
||||
* Returns the assigned IPv6 extension header type number of the header
|
||||
* that immediately follows this one.
|
||||
*/
|
||||
uint8 NextHdr() const
|
||||
{
|
||||
switch ( type ) {
|
||||
case IPPROTO_IPV6:
|
||||
return ((ip6_hdr*)data)->ip6_nxt;
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_DSTOPTS:
|
||||
case IPPROTO_ROUTING:
|
||||
case IPPROTO_FRAGMENT:
|
||||
case IPPROTO_AH:
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
case IPPROTO_MOBILITY:
|
||||
#endif
|
||||
return ((ip6_ext*)data)->ip6e_nxt;
|
||||
case IPPROTO_ESP:
|
||||
default:
|
||||
return IPPROTO_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the header in bytes.
|
||||
*/
|
||||
uint16 Length() const
|
||||
{
|
||||
switch ( type ) {
|
||||
case IPPROTO_IPV6:
|
||||
return 40;
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_DSTOPTS:
|
||||
case IPPROTO_ROUTING:
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
case IPPROTO_MOBILITY:
|
||||
#endif
|
||||
return 8 + 8 * ((ip6_ext*)data)->ip6e_len;
|
||||
case IPPROTO_FRAGMENT:
|
||||
return 8;
|
||||
case IPPROTO_AH:
|
||||
return 8 + 4 * ((ip6_ext*)data)->ip6e_len;
|
||||
case IPPROTO_ESP:
|
||||
return 8; //encrypted payload begins after 8 bytes
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RFC 1700 et seq. IANA assigned number for the header.
|
||||
*/
|
||||
uint8 Type() const { return type; }
|
||||
|
||||
/**
|
||||
* Returns pointer to the start of where header structure resides in memory.
|
||||
*/
|
||||
const u_char* Data() const { return data; }
|
||||
|
||||
/**
|
||||
* Returns the script-layer record representation of the header.
|
||||
*/
|
||||
RecordVal* BuildRecordVal(VectorVal* chain = 0) const;
|
||||
|
||||
protected:
|
||||
uint8 type;
|
||||
const u_char* data;
|
||||
};
|
||||
|
||||
class IPv6_Hdr_Chain {
|
||||
public:
|
||||
/**
|
||||
* Initializes the header chain from an IPv6 header structure.
|
||||
*/
|
||||
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, int len) :
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
homeAddr(0),
|
||||
#endif
|
||||
finalDst(0)
|
||||
{ Init(ip6, len, false); }
|
||||
|
||||
~IPv6_Hdr_Chain()
|
||||
{
|
||||
for ( size_t i = 0; i < chain.size(); ++i ) delete chain[i];
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
delete homeAddr;
|
||||
#endif
|
||||
delete finalDst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of headers in the chain.
|
||||
*/
|
||||
size_t Size() const { return chain.size(); }
|
||||
|
||||
/**
|
||||
* Returns the sum of the length of all headers in the chain in bytes.
|
||||
*/
|
||||
uint16 TotalLength() const { return length; }
|
||||
|
||||
/**
|
||||
* Accesses the header at the given location in the chain.
|
||||
*/
|
||||
const IPv6_Hdr* operator[](const size_t i) const { return chain[i]; }
|
||||
|
||||
/**
|
||||
* Returns whether the header chain indicates a fragmented packet.
|
||||
*/
|
||||
bool IsFragment() const
|
||||
{ return chain[chain.size()-1]->Type() == IPPROTO_FRAGMENT; }
|
||||
|
||||
/**
|
||||
* Returns pointer to fragment header structure if the chain contains one.
|
||||
*/
|
||||
const struct ip6_frag* GetFragHdr() const
|
||||
{ return IsFragment() ?
|
||||
(const struct ip6_frag*)chain[chain.size()-1]->Data(): 0; }
|
||||
|
||||
/**
|
||||
* If the header chain is a fragment, returns the offset in number of bytes
|
||||
* relative to the start of the Fragmentable Part of the original packet.
|
||||
*/
|
||||
uint16 FragOffset() const
|
||||
{ return IsFragment() ?
|
||||
(ntohs(GetFragHdr()->ip6f_offlg) & 0xfff8) : 0; }
|
||||
|
||||
/**
|
||||
* If the header chain is a fragment, returns the identification field.
|
||||
*/
|
||||
uint32 ID() const
|
||||
{ return IsFragment() ? ntohl(GetFragHdr()->ip6f_ident) : 0; }
|
||||
|
||||
/**
|
||||
* If the header chain is a fragment, returns the M (more fragments) flag.
|
||||
*/
|
||||
int MF() const
|
||||
{ return IsFragment() ?
|
||||
(ntohs(GetFragHdr()->ip6f_offlg) & 0x0001) != 0 : 0; }
|
||||
|
||||
/**
|
||||
* If the chain contains a Destination Options header with a Home Address
|
||||
* option as defined by Mobile IPv6 (RFC 6275), then return it, else
|
||||
* return the source address in the main IPv6 header.
|
||||
*/
|
||||
IPAddr SrcAddr() const
|
||||
{
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
if ( homeAddr )
|
||||
return IPAddr(*homeAddr);
|
||||
else
|
||||
#endif
|
||||
return IPAddr(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_src);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the chain contains a Routing header with non-zero segments left,
|
||||
* then return the last address of the first such header, else return
|
||||
* the destination address of the main IPv6 header.
|
||||
*/
|
||||
IPAddr DstAddr() const
|
||||
{
|
||||
if ( finalDst )
|
||||
return IPAddr(*finalDst);
|
||||
else
|
||||
return IPAddr(((const struct ip6_hdr*)(chain[0]->Data()))->ip6_dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a vector of ip6_ext_hdr RecordVals that includes script-layer
|
||||
* representation of all extension headers in the chain.
|
||||
*/
|
||||
VectorVal* BuildVal() const;
|
||||
|
||||
protected:
|
||||
// for access to protected ctor that changes next header values that
|
||||
// point to a fragment
|
||||
friend class FragReassembler;
|
||||
|
||||
/**
|
||||
* Initializes the header chain from an IPv6 header structure, and replaces
|
||||
* the first next protocol pointer field that points to a fragment header.
|
||||
*/
|
||||
IPv6_Hdr_Chain(const struct ip6_hdr* ip6, uint16 next, int len) :
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
homeAddr(0),
|
||||
#endif
|
||||
finalDst(0)
|
||||
{ Init(ip6, len, true, next); }
|
||||
|
||||
/**
|
||||
* Initializes the header chain from an IPv6 header structure of a given
|
||||
* length, possibly setting the first next protocol pointer field that
|
||||
* points to a fragment header.
|
||||
*/
|
||||
void Init(const struct ip6_hdr* ip6, int total_len, bool set_next,
|
||||
uint16 next = 0);
|
||||
|
||||
/**
|
||||
* Process a routing header and allocate/remember the final destination
|
||||
* address if it has segments left and is a valid routing header.
|
||||
*/
|
||||
void ProcessRoutingHeader(const struct ip6_rthdr* r, uint16 len);
|
||||
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
/**
|
||||
* Inspect a Destination Option header's options for things we need to
|
||||
* remember, such as the Home Address option from Mobile IPv6.
|
||||
*/
|
||||
void ProcessDstOpts(const struct ip6_dest* d, uint16 len);
|
||||
#endif
|
||||
|
||||
vector<IPv6_Hdr*> chain;
|
||||
|
||||
/**
|
||||
* The summation of all header lengths in the chain in bytes.
|
||||
*/
|
||||
uint16 length;
|
||||
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
/**
|
||||
* Home Address of the packet's source as defined by Mobile IPv6 (RFC 6275).
|
||||
*/
|
||||
IPAddr* homeAddr;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The final destination address in chain's first Routing header that has
|
||||
* non-zero segments left.
|
||||
*/
|
||||
IPAddr* finalDst;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that wraps either an IPv4 or IPv6 packet and abstracts methods
|
||||
* for inquiring about common features between the two.
|
||||
*/
|
||||
class IP_Hdr {
|
||||
public:
|
||||
IP_Hdr(struct ip* arg_ip4)
|
||||
/**
|
||||
* Attempts to construct the header from some blob of data based on IP
|
||||
* version number. Caller must have already checked that the header
|
||||
* is not truncated.
|
||||
* @param p pointer to memory containing an IPv4 or IPv6 packet.
|
||||
* @param arg_del whether to take ownership of \a p pointer's memory.
|
||||
* @param len the length of data, in bytes, pointed to by \a p.
|
||||
*/
|
||||
IP_Hdr(const u_char* p, bool arg_del, int len)
|
||||
: ip4(0), ip6(0), del(arg_del), ip6_hdrs(0)
|
||||
{
|
||||
ip4 = arg_ip4;
|
||||
ip6 = 0;
|
||||
del = 1;
|
||||
|
||||
#ifdef BROv6
|
||||
src_addr[0] = src_addr[1] = src_addr[2] = 0;
|
||||
dst_addr[0] = dst_addr[1] = dst_addr[2] = 0;
|
||||
|
||||
src_addr[3] = ip4->ip_src.s_addr;
|
||||
dst_addr[3] = ip4->ip_dst.s_addr;
|
||||
#endif
|
||||
if ( ((const struct ip*)p)->ip_v == 4 )
|
||||
ip4 = (const struct ip*)p;
|
||||
else if ( ((const struct ip*)p)->ip_v == 6 )
|
||||
{
|
||||
ip6 = (const struct ip6_hdr*)p;
|
||||
ip6_hdrs = new IPv6_Hdr_Chain(ip6, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( arg_del )
|
||||
delete [] p;
|
||||
reporter->InternalError("bad IP version in IP_Hdr ctor");
|
||||
}
|
||||
}
|
||||
|
||||
IP_Hdr(const struct ip* arg_ip4)
|
||||
/**
|
||||
* Construct the header wrapper from an IPv4 packet. Caller must have
|
||||
* already checked that the header is not truncated.
|
||||
* @param arg_ip4 pointer to memory containing an IPv4 packet.
|
||||
* @param arg_del whether to take ownership of \a arg_ip4 pointer's memory.
|
||||
*/
|
||||
IP_Hdr(const struct ip* arg_ip4, bool arg_del)
|
||||
: ip4(arg_ip4), ip6(0), del(arg_del), ip6_hdrs(0)
|
||||
{
|
||||
ip4 = arg_ip4;
|
||||
ip6 = 0;
|
||||
del = 0;
|
||||
|
||||
#ifdef BROv6
|
||||
src_addr[0] = src_addr[1] = src_addr[2] = 0;
|
||||
dst_addr[0] = dst_addr[1] = dst_addr[2] = 0;
|
||||
|
||||
src_addr[3] = ip4->ip_src.s_addr;
|
||||
dst_addr[3] = ip4->ip_dst.s_addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
IP_Hdr(struct ip6_hdr* arg_ip6)
|
||||
/**
|
||||
* Construct the header wrapper from an IPv6 packet. Caller must have
|
||||
* already checked that the static IPv6 header is not truncated. If
|
||||
* the packet contains extension headers and they are truncated, that can
|
||||
* be checked afterwards by comparing \a len with \a TotalLen. E.g.
|
||||
* NetSessions::DoNextPacket does this to skip truncated packets.
|
||||
* @param arg_ip6 pointer to memory containing an IPv6 packet.
|
||||
* @param arg_del whether to take ownership of \a arg_ip6 pointer's memory.
|
||||
* @param len the packet's length in bytes.
|
||||
* @param c an already-constructed header chain to take ownership of.
|
||||
*/
|
||||
IP_Hdr(const struct ip6_hdr* arg_ip6, bool arg_del, int len,
|
||||
const IPv6_Hdr_Chain* c = 0)
|
||||
: ip4(0), ip6(arg_ip6), del(arg_del),
|
||||
ip6_hdrs(c ? c : new IPv6_Hdr_Chain(ip6, len))
|
||||
{
|
||||
ip4 = 0;
|
||||
ip6 = arg_ip6;
|
||||
del = 1;
|
||||
|
||||
#ifdef BROv6
|
||||
memcpy(src_addr, ip6->ip6_src.s6_addr, 16);
|
||||
memcpy(dst_addr, ip6->ip6_dst.s6_addr, 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
IP_Hdr(const struct ip6_hdr* arg_ip6)
|
||||
{
|
||||
ip4 = 0;
|
||||
ip6 = arg_ip6;
|
||||
del = 0;
|
||||
|
||||
#ifdef BROv6
|
||||
memcpy(src_addr, ip6->ip6_src.s6_addr, 16);
|
||||
memcpy(dst_addr, ip6->ip6_dst.s6_addr, 16);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~IP_Hdr()
|
||||
{
|
||||
if ( ip6 )
|
||||
delete ip6_hdrs;
|
||||
|
||||
if ( del )
|
||||
{
|
||||
if ( ip4 )
|
||||
|
@ -74,68 +377,181 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If an IPv4 packet is wrapped, return a pointer to it, else null.
|
||||
*/
|
||||
const struct ip* IP4_Hdr() const { return ip4; }
|
||||
|
||||
/**
|
||||
* If an IPv6 packet is wrapped, return a pointer to it, else null.
|
||||
*/
|
||||
const struct ip6_hdr* IP6_Hdr() const { return ip6; }
|
||||
|
||||
#ifdef BROv6
|
||||
const uint32* SrcAddr() const { return src_addr; }
|
||||
const uint32* DstAddr() const { return dst_addr; }
|
||||
#else
|
||||
const uint32* SrcAddr() const
|
||||
{ return ip4 ? &(ip4->ip_src.s_addr) : 0; }
|
||||
const uint32* DstAddr() const
|
||||
{ return ip4 ? &(ip4->ip_dst.s_addr) : 0; }
|
||||
#endif
|
||||
/**
|
||||
* Returns the source address held in the IP header.
|
||||
*/
|
||||
IPAddr IPHeaderSrcAddr() const
|
||||
{ return ip4 ? IPAddr(ip4->ip_src) : IPAddr(ip6->ip6_src); }
|
||||
|
||||
uint32 SrcAddr4() const { return ip4->ip_src.s_addr; }
|
||||
uint32 DstAddr4() const { return ip4->ip_dst.s_addr; }
|
||||
/**
|
||||
* Returns the destination address held in the IP header.
|
||||
*/
|
||||
IPAddr IPHeaderDstAddr() const
|
||||
{ return ip4 ? IPAddr(ip4->ip_dst) : IPAddr(ip6->ip6_dst); }
|
||||
|
||||
uint16 ID4() const { return ip4 ? ip4->ip_id : 0; }
|
||||
/**
|
||||
* For IPv4 or IPv6 headers that don't contain a Home Address option
|
||||
* (Mobile IPv6, RFC 6275), return source address held in the IP header.
|
||||
* For IPv6 headers that contain a Home Address option, return that address.
|
||||
*/
|
||||
IPAddr SrcAddr() const
|
||||
{ return ip4 ? IPAddr(ip4->ip_src) : ip6_hdrs->SrcAddr(); }
|
||||
|
||||
/**
|
||||
* For IPv4 or IPv6 headers that don't contain a Routing header with
|
||||
* non-zero segments left, return destination address held in the IP header.
|
||||
* For IPv6 headers with a Routing header that has non-zero segments left,
|
||||
* return the last address in the first such Routing header.
|
||||
*/
|
||||
IPAddr DstAddr() const
|
||||
{ return ip4 ? IPAddr(ip4->ip_dst) : ip6_hdrs->DstAddr(); }
|
||||
|
||||
/**
|
||||
* Returns a pointer to the payload of the IP packet, usually an
|
||||
* upper-layer protocol.
|
||||
*/
|
||||
const u_char* Payload() const
|
||||
{
|
||||
if ( ip4 )
|
||||
return ((const u_char*) ip4) + ip4->ip_hl * 4;
|
||||
else
|
||||
return ((const u_char*) ip6) + 40;
|
||||
return ((const u_char*) ip6) + ip6_hdrs->TotalLength();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MOBILE_IPV6
|
||||
/**
|
||||
* Returns a pointer to the mobility header of the IP packet, if present,
|
||||
* else a null pointer.
|
||||
*/
|
||||
const ip6_mobility* MobilityHeader() const
|
||||
{
|
||||
if ( ip4 )
|
||||
return 0;
|
||||
else if ( (*ip6_hdrs)[ip6_hdrs->Size()-1]->Type() != IPPROTO_MOBILITY )
|
||||
return 0;
|
||||
else
|
||||
return (const ip6_mobility*)(*ip6_hdrs)[ip6_hdrs->Size()-1]->Data();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the length of the IP packet's payload (length of packet minus
|
||||
* header length or, for IPv6, also minus length of all extension headers).
|
||||
*/
|
||||
uint16 PayloadLen() const
|
||||
{
|
||||
if ( ip4 )
|
||||
return ntohs(ip4->ip_len) - ip4->ip_hl * 4;
|
||||
else
|
||||
return ntohs(ip6->ip6_plen);
|
||||
return ntohs(ip6->ip6_plen) + 40 - ip6_hdrs->TotalLength();
|
||||
}
|
||||
|
||||
uint16 TotalLen() const
|
||||
{
|
||||
if ( ip4 )
|
||||
return ntohs(ip4->ip_len);
|
||||
else
|
||||
return ntohs(ip6->ip6_plen) + 40;
|
||||
}
|
||||
/**
|
||||
* Returns the length of the IP packet (length of headers and payload).
|
||||
*/
|
||||
uint32 TotalLen() const
|
||||
{ return ip4 ? ntohs(ip4->ip_len) : ntohs(ip6->ip6_plen) + 40; }
|
||||
|
||||
uint16 HdrLen() const { return ip4 ? ip4->ip_hl * 4 : 40; }
|
||||
/**
|
||||
* Returns length of IP packet header (includes extension headers for IPv6).
|
||||
*/
|
||||
uint16 HdrLen() const
|
||||
{ return ip4 ? ip4->ip_hl * 4 : ip6_hdrs->TotalLength(); }
|
||||
|
||||
/**
|
||||
* For IPv6 header chains, returns the type of the last header in the chain.
|
||||
*/
|
||||
uint8 LastHeader() const
|
||||
{ return ip4 ? IPPROTO_RAW :
|
||||
((*ip6_hdrs)[ip6_hdrs->Size()-1])->Type(); }
|
||||
|
||||
/**
|
||||
* Returns the protocol type of the IP packet's payload, usually an
|
||||
* upper-layer protocol. For IPv6, this returns the last (extension)
|
||||
* header's Next Header value.
|
||||
*/
|
||||
unsigned char NextProto() const
|
||||
{ return ip4 ? ip4->ip_p : ip6->ip6_nxt; }
|
||||
{ return ip4 ? ip4->ip_p :
|
||||
((*ip6_hdrs)[ip6_hdrs->Size()-1])->NextHdr(); }
|
||||
|
||||
/**
|
||||
* Returns the IPv4 Time to Live or IPv6 Hop Limit field.
|
||||
*/
|
||||
unsigned char TTL() const
|
||||
{ return ip4 ? ip4->ip_ttl : ip6->ip6_hlim; }
|
||||
uint16 FragField() const
|
||||
{ return ntohs(ip4 ? ip4->ip_off : 0); }
|
||||
|
||||
/**
|
||||
* Returns whether the IP header indicates this packet is a fragment.
|
||||
*/
|
||||
bool IsFragment() const
|
||||
{ return ip4 ? (ntohs(ip4->ip_off) & 0x3fff) != 0 :
|
||||
ip6_hdrs->IsFragment(); }
|
||||
|
||||
/**
|
||||
* Returns the fragment packet's offset in relation to the original
|
||||
* packet in bytes.
|
||||
*/
|
||||
uint16 FragOffset() const
|
||||
{ return ip4 ? (ntohs(ip4->ip_off) & 0x1fff) * 8 :
|
||||
ip6_hdrs->FragOffset(); }
|
||||
|
||||
/**
|
||||
* Returns the fragment packet's identification field.
|
||||
*/
|
||||
uint32 ID() const
|
||||
{ return ip4 ? ntohs(ip4->ip_id) : ip6_hdrs->ID(); }
|
||||
|
||||
/**
|
||||
* Returns whether a fragment packet's "More Fragments" field is set.
|
||||
*/
|
||||
int MF() const
|
||||
{ return ip4 ? (ntohs(ip4->ip_off) & 0x2000) != 0 : ip6_hdrs->MF(); }
|
||||
|
||||
/**
|
||||
* Returns whether a fragment packet's "Don't Fragment" field is set.
|
||||
* Note that IPv6 has no such field.
|
||||
*/
|
||||
int DF() const
|
||||
{ return ip4 ? ((ntohs(ip4->ip_off) & IP_DF) != 0) : 0; }
|
||||
uint16 IP_ID() const
|
||||
{ return ip4 ? (ntohs(ip4->ip_id)) : 0; }
|
||||
{ return ip4 ? ((ntohs(ip4->ip_off) & 0x4000) != 0) : 0; }
|
||||
|
||||
/**
|
||||
* Returns value of an IPv6 header's flow label field or 0 if it's IPv4.
|
||||
*/
|
||||
uint32 FlowLabel() const
|
||||
{ return ip4 ? 0 : (ntohl(ip6->ip6_flow) & 0x000fffff); }
|
||||
|
||||
/**
|
||||
* Returns number of IP headers in packet (includes IPv6 extension headers).
|
||||
*/
|
||||
size_t NumHeaders() const
|
||||
{ return ip4 ? 1 : ip6_hdrs->Size(); }
|
||||
|
||||
/**
|
||||
* Returns an ip_hdr or ip6_hdr_chain RecordVal.
|
||||
*/
|
||||
RecordVal* BuildIPHdrVal() const;
|
||||
|
||||
/**
|
||||
* Returns a pkt_hdr RecordVal, which includes not only the IP header, but
|
||||
* also upper-layer (tcp/udp/icmp) headers.
|
||||
*/
|
||||
RecordVal* BuildPktHdrVal() const;
|
||||
|
||||
private:
|
||||
const struct ip* ip4;
|
||||
const struct ip6_hdr* ip6;
|
||||
#ifdef BROv6
|
||||
uint32 src_addr[NUM_ADDR_WORDS];
|
||||
uint32 dst_addr[NUM_ADDR_WORDS];
|
||||
#endif
|
||||
int del;
|
||||
bool del;
|
||||
const IPv6_Hdr_Chain* ip6_hdrs;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
286
src/IPAddr.cc
Normal file
286
src/IPAddr.cc
Normal file
|
@ -0,0 +1,286 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "IPAddr.h"
|
||||
#include "Reporter.h"
|
||||
#include "Conn.h"
|
||||
#include "DPM.h"
|
||||
#include "bro_inet_ntop.h"
|
||||
|
||||
const uint8_t IPAddr::v4_mapped_prefix[12] = { 0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0xff, 0xff };
|
||||
|
||||
HashKey* BuildConnIDHashKey(const ConnID& id)
|
||||
{
|
||||
struct {
|
||||
in6_addr ip1;
|
||||
in6_addr ip2;
|
||||
uint16 port1;
|
||||
uint16 port2;
|
||||
} key;
|
||||
|
||||
// Lookup up connection based on canonical ordering, which is
|
||||
// the smaller of <src addr, src port> and <dst addr, dst port>
|
||||
// followed by the other.
|
||||
if ( id.is_one_way ||
|
||||
addr_port_canon_lt(id.src_addr, id.src_port, id.dst_addr, id.dst_port)
|
||||
)
|
||||
{
|
||||
key.ip1 = id.src_addr.in6;
|
||||
key.ip2 = id.dst_addr.in6;
|
||||
key.port1 = id.src_port;
|
||||
key.port2 = id.dst_port;
|
||||
}
|
||||
else
|
||||
{
|
||||
key.ip1 = id.dst_addr.in6;
|
||||
key.ip2 = id.src_addr.in6;
|
||||
key.port1 = id.dst_port;
|
||||
key.port2 = id.src_port;
|
||||
}
|
||||
|
||||
return new HashKey(&key, sizeof(key));
|
||||
}
|
||||
|
||||
HashKey* BuildExpectedConnHashKey(const ExpectedConn& c)
|
||||
{
|
||||
struct {
|
||||
in6_addr orig;
|
||||
in6_addr resp;
|
||||
uint16 resp_p;
|
||||
uint16 proto;
|
||||
} key;
|
||||
|
||||
key.orig = c.orig.in6;
|
||||
key.resp = c.resp.in6;
|
||||
key.resp_p = c.resp_p;
|
||||
key.proto = c.proto;
|
||||
|
||||
return new HashKey(&key, sizeof(key));
|
||||
}
|
||||
|
||||
void IPAddr::Mask(int top_bits_to_keep)
|
||||
{
|
||||
if ( top_bits_to_keep < 0 || top_bits_to_keep > 128 )
|
||||
{
|
||||
reporter->Error("Bad IPAddr::Mask value %d", top_bits_to_keep);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t tmp[4];
|
||||
memcpy(tmp, in6.s6_addr, sizeof(in6.s6_addr));
|
||||
|
||||
int word = 3;
|
||||
int bits_to_chop = 128 - top_bits_to_keep;
|
||||
|
||||
while ( bits_to_chop >= 32 )
|
||||
{
|
||||
tmp[word] = 0;
|
||||
--word;
|
||||
bits_to_chop -= 32;
|
||||
}
|
||||
|
||||
uint32_t w = ntohl(tmp[word]);
|
||||
w >>= bits_to_chop;
|
||||
w <<= bits_to_chop;
|
||||
tmp[word] = htonl(w);
|
||||
|
||||
memcpy(in6.s6_addr, tmp, sizeof(in6.s6_addr));
|
||||
}
|
||||
|
||||
void IPAddr::ReverseMask(int top_bits_to_chop)
|
||||
{
|
||||
if ( top_bits_to_chop < 0 || top_bits_to_chop > 128 )
|
||||
{
|
||||
reporter->Error("Bad IPAddr::ReverseMask value %d", top_bits_to_chop);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t tmp[4];
|
||||
memcpy(tmp, in6.s6_addr, sizeof(in6.s6_addr));
|
||||
|
||||
int word = 0;
|
||||
int bits_to_chop = top_bits_to_chop;
|
||||
|
||||
while ( bits_to_chop >= 32 )
|
||||
{
|
||||
tmp[word] = 0;
|
||||
++word;
|
||||
bits_to_chop -= 32;
|
||||
}
|
||||
|
||||
uint32_t w = ntohl(tmp[word]);
|
||||
w <<= bits_to_chop;
|
||||
w >>= bits_to_chop;
|
||||
tmp[word] = htonl(w);
|
||||
|
||||
memcpy(in6.s6_addr, tmp, sizeof(in6.s6_addr));
|
||||
}
|
||||
|
||||
void IPAddr::Init(const std::string& s)
|
||||
{
|
||||
if ( s.find(':') == std::string::npos ) // IPv4.
|
||||
{
|
||||
memcpy(in6.s6_addr, v4_mapped_prefix, sizeof(v4_mapped_prefix));
|
||||
|
||||
// Parse the address directly instead of using inet_pton since
|
||||
// some platforms have more sensitive implementations than others
|
||||
// that can't e.g. handle leading zeroes.
|
||||
int a[4];
|
||||
int n = sscanf(s.c_str(), "%d.%d.%d.%d", a+0, a+1, a+2, a+3);
|
||||
|
||||
if ( n != 4 || a[0] < 0 || a[1] < 0 || a[2] < 0 || a[3] < 0 ||
|
||||
a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 )
|
||||
{
|
||||
reporter->Error("Bad IP address: %s", s.c_str());
|
||||
memset(in6.s6_addr, 0, sizeof(in6.s6_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t addr = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
|
||||
addr = htonl(addr);
|
||||
memcpy(&in6.s6_addr[12], &addr, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( inet_pton(AF_INET6, s.c_str(), in6.s6_addr) <=0 )
|
||||
{
|
||||
reporter->Error("Bad IP address: %s", s.c_str());
|
||||
memset(in6.s6_addr, 0, sizeof(in6.s6_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string IPAddr::AsString() const
|
||||
{
|
||||
if ( GetFamily() == IPv4 )
|
||||
{
|
||||
char s[INET_ADDRSTRLEN];
|
||||
|
||||
if ( ! bro_inet_ntop(AF_INET, &in6.s6_addr[12], s, INET_ADDRSTRLEN) )
|
||||
return "<bad IPv4 address conversion";
|
||||
else
|
||||
return s;
|
||||
}
|
||||
else
|
||||
{
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
|
||||
if ( ! bro_inet_ntop(AF_INET6, in6.s6_addr, s, INET6_ADDRSTRLEN) )
|
||||
return "<bad IPv6 address conversion";
|
||||
else
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
string IPAddr::AsHexString() const
|
||||
{
|
||||
char buf[33];
|
||||
|
||||
if ( GetFamily() == IPv4 )
|
||||
{
|
||||
uint32_t* p = (uint32_t*) &in6.s6_addr[12];
|
||||
snprintf(buf, sizeof(buf), "%08x", (uint32_t) ntohl(*p));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t* p = (uint32_t*) in6.s6_addr;
|
||||
snprintf(buf, sizeof(buf), "%08x%08x%08x%08x",
|
||||
(uint32_t) ntohl(p[0]), (uint32_t) ntohl(p[1]),
|
||||
(uint32_t) ntohl(p[2]), (uint32_t) ntohl(p[3]));
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
string IPAddr::PtrName() const
|
||||
{
|
||||
if ( GetFamily() == IPv4 )
|
||||
{
|
||||
char buf[256];
|
||||
uint32_t* p = (uint32_t*) &in6.s6_addr[12];
|
||||
uint32_t a = ntohl(*p);
|
||||
uint32_t a3 = (a >> 24) & 0xff;
|
||||
uint32_t a2 = (a >> 16) & 0xff;
|
||||
uint32_t a1 = (a >> 8) & 0xff;
|
||||
uint32_t a0 = a & 0xff;
|
||||
snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa", a0, a1, a2, a3);
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char hex_digit[] = "0123456789abcdef";
|
||||
string ptr_name("ip6.arpa");
|
||||
uint32_t* p = (uint32_t*) in6.s6_addr;
|
||||
|
||||
for ( unsigned int i = 0; i < 4; ++i )
|
||||
{
|
||||
uint32 a = ntohl(p[i]);
|
||||
for ( unsigned int j = 1; j <=8; ++j )
|
||||
{
|
||||
ptr_name.insert(0, 1, '.');
|
||||
ptr_name.insert(0, 1, hex_digit[(a >> (32-j*4)) & 0x0f]);
|
||||
}
|
||||
}
|
||||
|
||||
return ptr_name;
|
||||
}
|
||||
}
|
||||
|
||||
IPPrefix::IPPrefix(const in4_addr& in4, uint8_t length)
|
||||
: prefix(in4), length(96 + length)
|
||||
{
|
||||
if ( length > 32 )
|
||||
reporter->InternalError("Bad in4_addr IPPrefix length : %d", length);
|
||||
|
||||
prefix.Mask(this->length);
|
||||
}
|
||||
|
||||
IPPrefix::IPPrefix(const in6_addr& in6, uint8_t length)
|
||||
: prefix(in6), length(length)
|
||||
{
|
||||
if ( length > 128 )
|
||||
reporter->InternalError("Bad in6_addr IPPrefix length : %d", length);
|
||||
|
||||
prefix.Mask(this->length);
|
||||
}
|
||||
|
||||
IPPrefix::IPPrefix(const IPAddr& addr, uint8_t length)
|
||||
: prefix(addr)
|
||||
{
|
||||
if ( prefix.GetFamily() == IPv4 )
|
||||
{
|
||||
if ( length > 32 )
|
||||
reporter->InternalError("Bad IPAddr(v4) IPPrefix length : %d",
|
||||
length);
|
||||
|
||||
this->length = length + 96;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( length > 128 )
|
||||
reporter->InternalError("Bad IPAddr(v6) IPPrefix length : %d",
|
||||
length);
|
||||
|
||||
this->length = length;
|
||||
}
|
||||
|
||||
prefix.Mask(this->length);
|
||||
}
|
||||
|
||||
string IPPrefix::AsString() const
|
||||
{
|
||||
char l[16];
|
||||
|
||||
if ( prefix.GetFamily() == IPv4 )
|
||||
modp_uitoa10(length - 96, l);
|
||||
else
|
||||
modp_uitoa10(length, l);
|
||||
|
||||
return prefix.AsString() +"/" + l;
|
||||
}
|
||||
|
643
src/IPAddr.h
Normal file
643
src/IPAddr.h
Normal file
|
@ -0,0 +1,643 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef IPADDR_H
|
||||
#define IPADDR_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string>
|
||||
|
||||
#include "BroString.h"
|
||||
#include "Hash.h"
|
||||
#include "util.h"
|
||||
#include "Type.h"
|
||||
#include "threading/SerialTypes.h"
|
||||
|
||||
struct ConnID;
|
||||
class ExpectedConn;
|
||||
|
||||
typedef in_addr in4_addr;
|
||||
|
||||
/**
|
||||
* Class storing both IPv4 and IPv6 addresses.
|
||||
*/
|
||||
class IPAddr
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Address family.
|
||||
*/
|
||||
typedef IPFamily Family;
|
||||
|
||||
/**
|
||||
* Byte order.
|
||||
*/
|
||||
enum ByteOrder { Host, Network };
|
||||
|
||||
/**
|
||||
* Constructs the unspecified IPv6 address (all 128 bits zeroed).
|
||||
*/
|
||||
IPAddr()
|
||||
{
|
||||
memset(in6.s6_addr, 0, sizeof(in6.s6_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an address instance from an IPv4 address.
|
||||
*
|
||||
* @param in6 The IPv6 address.
|
||||
*/
|
||||
explicit IPAddr(const in4_addr& in4)
|
||||
{
|
||||
memcpy(in6.s6_addr, v4_mapped_prefix, sizeof(v4_mapped_prefix));
|
||||
memcpy(&in6.s6_addr[12], &in4.s_addr, sizeof(in4.s_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an address instance from an IPv6 address.
|
||||
*
|
||||
* @param in6 The IPv6 address.
|
||||
*/
|
||||
explicit IPAddr(const in6_addr& arg_in6) : in6(arg_in6) { }
|
||||
|
||||
/**
|
||||
* Constructs an address instance from a string representation.
|
||||
*
|
||||
* @param s String containing an IP address as either a dotted IPv4
|
||||
* address or a hex IPv6 address.
|
||||
*/
|
||||
IPAddr(const std::string& s)
|
||||
{
|
||||
Init(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an address instance from a string representation.
|
||||
*
|
||||
* @param s ASCIIZ string containing an IP address as either a
|
||||
* dotted IPv4 address or a hex IPv6 address.
|
||||
*/
|
||||
IPAddr(const char* s)
|
||||
{
|
||||
Init(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an address instance from a string representation.
|
||||
*
|
||||
* @param s String containing an IP address as either a dotted IPv4
|
||||
* address or a hex IPv6 address.
|
||||
*/
|
||||
IPAddr(const BroString& s)
|
||||
{
|
||||
Init(s.CheckString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an address instance from a raw byte representation.
|
||||
*
|
||||
* @param family The address family.
|
||||
*
|
||||
* @param bytes A pointer to the raw byte representation. This must point
|
||||
* to 4 bytes if \a family is IPv4, and to 16 bytes if \a family is
|
||||
* IPv6.
|
||||
*
|
||||
* @param order Indicates whether the raw representation pointed to
|
||||
* by \a bytes is stored in network or host order.
|
||||
*/
|
||||
IPAddr(Family family, const uint32_t* bytes, ByteOrder order);
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
IPAddr(const IPAddr& other) : in6(other.in6) { };
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~IPAddr() { };
|
||||
|
||||
/**
|
||||
* Returns the address' family.
|
||||
*/
|
||||
Family GetFamily() const
|
||||
{
|
||||
if ( memcmp(in6.s6_addr, v4_mapped_prefix, 12) == 0 )
|
||||
return IPv4;
|
||||
else
|
||||
return IPv6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the address represents a loopback device.
|
||||
*/
|
||||
bool IsLoopback() const;
|
||||
|
||||
/**
|
||||
* Returns true if the address represents a multicast address.
|
||||
*/
|
||||
bool IsMulticast() const
|
||||
{
|
||||
if ( GetFamily() == IPv4 )
|
||||
return in6.s6_addr[12] == 224;
|
||||
else
|
||||
return in6.s6_addr[0] == 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the address represents a broadcast address.
|
||||
*/
|
||||
bool IsBroadcast() const
|
||||
{
|
||||
if ( GetFamily() == IPv4 )
|
||||
return ((in6.s6_addr[12] == 0xff) && (in6.s6_addr[13] == 0xff)
|
||||
&& (in6.s6_addr[14] == 0xff) && (in6.s6_addr[15] == 0xff));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the raw byte representation of the address.
|
||||
*
|
||||
* @param bytes The pointer to which \a bytes points will be set to
|
||||
* the address of the raw representation in network-byte order.
|
||||
* The return value indicates how many 32-bit words are valid starting at
|
||||
* that address. The pointer will be valid as long as the address instance
|
||||
* exists.
|
||||
*
|
||||
* @return The number of 32-bit words the raw representation uses. This
|
||||
* will be 1 for an IPv4 address and 4 for an IPv6 address.
|
||||
*/
|
||||
int GetBytes(const uint32_t** bytes) const
|
||||
{
|
||||
if ( GetFamily() == IPv4 )
|
||||
{
|
||||
*bytes = (uint32_t*) &in6.s6_addr[12];
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bytes = (uint32_t*) in6.s6_addr;
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a copy of the IPv6 raw byte representation of the address.
|
||||
* If the internal address is IPv4, then the copied bytes use the
|
||||
* IPv4 to IPv6 address mapping to return a full 16 bytes.
|
||||
*
|
||||
* @param bytes The pointer to a memory location in which the
|
||||
* raw bytes of the address are to be copied.
|
||||
*
|
||||
* @param order The byte-order in which the returned raw bytes are copied.
|
||||
* The default is network order.
|
||||
*/
|
||||
void CopyIPv6(uint32_t* bytes, ByteOrder order = Network) const
|
||||
{
|
||||
memcpy(bytes, in6.s6_addr, sizeof(in6.s6_addr));
|
||||
|
||||
if ( order == Host )
|
||||
{
|
||||
for ( unsigned int i = 0; i < 4; ++i )
|
||||
bytes[i] = ntohl(bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a copy of the IPv6 raw byte representation of the address.
|
||||
* @see CopyIPv6(uint32_t)
|
||||
*/
|
||||
void CopyIPv6(in6_addr* arg_in6) const
|
||||
{
|
||||
memcpy(arg_in6->s6_addr, in6.s6_addr, sizeof(in6.s6_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a copy of the IPv4 raw byte representation of the address.
|
||||
* The caller should verify the address is of the IPv4 family type
|
||||
* beforehand. @see GetFamily().
|
||||
*
|
||||
* @param in4 The pointer to a memory location in which the raw bytes
|
||||
* of the address are to be copied in network byte-order.
|
||||
*/
|
||||
void CopyIPv4(in4_addr* in4) const
|
||||
{
|
||||
memcpy(&in4->s_addr, &in6.s6_addr[12], sizeof(in4->s_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key that can be used to lookup the IP Address in a hash
|
||||
* table. Passes ownership to caller.
|
||||
*/
|
||||
HashKey* GetHashKey() const
|
||||
{
|
||||
return new HashKey((void*)in6.s6_addr, sizeof(in6.s6_addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Masks out lower bits of the address.
|
||||
*
|
||||
* @param top_bits_to_keep The number of bits \a not to mask out,
|
||||
* counting from the highest order bit. The value is always
|
||||
* interpreted relative to the IPv6 bit width, even if the address
|
||||
* is IPv4. That means if compute ``192.168.1.2/16``, you need to
|
||||
* pass in 112 (i.e., 96 + 16). The value must be in the range from
|
||||
* 0 to 128.
|
||||
*/
|
||||
void Mask(int top_bits_to_keep);
|
||||
|
||||
/**
|
||||
* Masks out top bits of the address.
|
||||
*
|
||||
* @param top_bits_to_chop The number of bits to mask out, counting
|
||||
* from the highest order bit. The value is always interpreted relative
|
||||
* to the IPv6 bit width, even if the address is IPv4. So to mask out
|
||||
* the first 16 bits of an IPv4 address, pass in 112 (i.e., 96 + 16).
|
||||
* The value must be in the range from 0 to 128.
|
||||
*/
|
||||
void ReverseMask(int top_bits_to_chop);
|
||||
|
||||
/**
|
||||
* Assignment operator.
|
||||
*/
|
||||
IPAddr& operator=(const IPAddr& other)
|
||||
{
|
||||
// No self-assignment check here because it's correct without it and
|
||||
// makes the common case faster.
|
||||
in6 = other.in6;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise OR operator returns the IP address resulting from the bitwise
|
||||
* OR operation on the raw bytes of this address with another.
|
||||
*/
|
||||
IPAddr operator|(const IPAddr& other)
|
||||
{
|
||||
in6_addr result;
|
||||
for ( int i = 0; i < 16; ++i )
|
||||
result.s6_addr[i] = this->in6.s6_addr[i] | other.in6.s6_addr[i];
|
||||
|
||||
return IPAddr(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the address. IPv4 addresses
|
||||
* will be returned in dotted representation, IPv6 addresses in
|
||||
* compressed hex.
|
||||
*/
|
||||
string AsString() const;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the address suitable for inclusion
|
||||
* in an URI. For IPv4 addresses, this is the same as AsString(), but
|
||||
* IPv6 addresses are encased in square brackets.
|
||||
*/
|
||||
string AsURIString() const
|
||||
{
|
||||
if ( GetFamily() == IPv4 )
|
||||
return AsString();
|
||||
else
|
||||
return string("[") + AsString() + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a host-order, plain hex string representation of the address.
|
||||
*/
|
||||
string AsHexString() const;
|
||||
|
||||
/**
|
||||
* Returns a string representation of the address. This returns the
|
||||
* same as AsString().
|
||||
*/
|
||||
operator std::string() const { return AsString(); }
|
||||
|
||||
/**
|
||||
* Returns a reverse pointer name associated with the IP address.
|
||||
* For example, 192.168.0.1's reverse pointer is 1.0.168.192.in-addr.arpa.
|
||||
*/
|
||||
string PtrName() const;
|
||||
|
||||
/**
|
||||
* Comparison operator for IP address.
|
||||
*/
|
||||
friend bool operator==(const IPAddr& addr1, const IPAddr& addr2)
|
||||
{
|
||||
return memcmp(&addr1.in6, &addr2.in6, sizeof(in6_addr)) == 0;
|
||||
}
|
||||
|
||||
friend bool operator!=(const IPAddr& addr1, const IPAddr& addr2)
|
||||
{
|
||||
return ! (addr1 == addr2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison operator IP addresses. This defines a well-defined order for
|
||||
* IP addresses. However, the order does not necessarily correspond to
|
||||
* their numerical values.
|
||||
*/
|
||||
friend bool operator<(const IPAddr& addr1, const IPAddr& addr2)
|
||||
{
|
||||
return memcmp(&addr1.in6, &addr2.in6, sizeof(in6_addr)) < 0;
|
||||
}
|
||||
|
||||
friend bool operator<=(const IPAddr& addr1, const IPAddr& addr2)
|
||||
{
|
||||
return addr1 < addr2 || addr1 == addr2;
|
||||
}
|
||||
|
||||
friend bool operator>=(const IPAddr& addr1, const IPAddr& addr2)
|
||||
{
|
||||
return ! ( addr1 < addr2 );
|
||||
}
|
||||
|
||||
friend bool operator>(const IPAddr& addr1, const IPAddr& addr2)
|
||||
{
|
||||
return ! ( addr1 <= addr2 );
|
||||
}
|
||||
|
||||
/** Converts the address into the type used internally by the
|
||||
* inter-thread communication.
|
||||
*/
|
||||
void ConvertToThreadingValue(threading::Value::addr_t* v) const;
|
||||
|
||||
friend HashKey* BuildConnIDHashKey(const ConnID& id);
|
||||
friend HashKey* BuildExpectedConnHashKey(const ExpectedConn& c);
|
||||
|
||||
unsigned int MemoryAllocation() const { return padded_sizeof(*this); }
|
||||
|
||||
private:
|
||||
friend class IPPrefix;
|
||||
|
||||
/**
|
||||
* Initializes an address instance from a string representation.
|
||||
*
|
||||
* @param s String containing an IP address as either a dotted IPv4
|
||||
* address or a hex IPv6 address.
|
||||
*/
|
||||
void Init(const std::string& s);
|
||||
|
||||
in6_addr in6; // IPv6 or v4-to-v6-mapped address
|
||||
|
||||
static const uint8_t v4_mapped_prefix[12]; // top 96 bits of v4-mapped-addr
|
||||
};
|
||||
|
||||
inline IPAddr::IPAddr(Family family, const uint32_t* bytes, ByteOrder order)
|
||||
{
|
||||
if ( family == IPv4 )
|
||||
{
|
||||
memcpy(in6.s6_addr, v4_mapped_prefix, sizeof(v4_mapped_prefix));
|
||||
memcpy(&in6.s6_addr[12], bytes, sizeof(uint32_t));
|
||||
|
||||
if ( order == Host )
|
||||
{
|
||||
uint32_t* p = (uint32_t*) &in6.s6_addr[12];
|
||||
*p = htonl(*p);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
memcpy(in6.s6_addr, bytes, sizeof(in6.s6_addr));
|
||||
|
||||
if ( order == Host )
|
||||
{
|
||||
for ( unsigned int i = 0; i < 4; ++ i)
|
||||
{
|
||||
uint32_t* p = (uint32_t*) &in6.s6_addr[i*4];
|
||||
*p = htonl(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IPAddr::IsLoopback() const
|
||||
{
|
||||
if ( GetFamily() == IPv4 )
|
||||
return in6.s6_addr[12] == 127;
|
||||
|
||||
else
|
||||
return ((in6.s6_addr[0] == 0) && (in6.s6_addr[1] == 0)
|
||||
&& (in6.s6_addr[2] == 0) && (in6.s6_addr[3] == 0)
|
||||
&& (in6.s6_addr[4] == 0) && (in6.s6_addr[5] == 0)
|
||||
&& (in6.s6_addr[6] == 0) && (in6.s6_addr[7] == 0)
|
||||
&& (in6.s6_addr[8] == 0) && (in6.s6_addr[9] == 0)
|
||||
&& (in6.s6_addr[10] == 0) && (in6.s6_addr[11] == 0)
|
||||
&& (in6.s6_addr[12] == 0) && (in6.s6_addr[13] == 0)
|
||||
&& (in6.s6_addr[14] == 0) && (in6.s6_addr[15] == 1));
|
||||
}
|
||||
|
||||
inline void IPAddr::ConvertToThreadingValue(threading::Value::addr_t* v) const
|
||||
{
|
||||
v->family = GetFamily();
|
||||
|
||||
switch ( v->family ) {
|
||||
|
||||
case IPv4:
|
||||
CopyIPv4(&v->in.in4);
|
||||
return;
|
||||
|
||||
case IPv6:
|
||||
CopyIPv6(&v->in.in6);
|
||||
return;
|
||||
|
||||
// Can't be reached.
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash key for a given ConnID. Passes ownership to caller.
|
||||
*/
|
||||
HashKey* BuildConnIDHashKey(const ConnID& id);
|
||||
|
||||
/**
|
||||
* Returns a hash key for a given ExpectedConn instance. Passes ownership to caller.
|
||||
*/
|
||||
HashKey* BuildExpectedConnHashKey(const ExpectedConn& c);
|
||||
|
||||
/**
|
||||
* Class storing both IPv4 and IPv6 prefixes
|
||||
* (i.e., \c 192.168.1.1/16 and \c FD00::/8.
|
||||
*/
|
||||
class IPPrefix
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructs a prefix 0/0.
|
||||
*/
|
||||
IPPrefix() : length(0) {}
|
||||
|
||||
/**
|
||||
* Constructs a prefix instance from an IPv4 address and a prefix
|
||||
* length.
|
||||
*
|
||||
* @param in4 The IPv4 address.
|
||||
*
|
||||
* @param length The prefix length in the range from 0 to 32.
|
||||
*/
|
||||
IPPrefix(const in4_addr& in4, uint8_t length);
|
||||
|
||||
/**
|
||||
* Constructs a prefix instance from an IPv6 address and a prefix
|
||||
* length.
|
||||
*
|
||||
* @param in6 The IPv6 address.
|
||||
*
|
||||
* @param length The prefix length in the range from 0 to 128.
|
||||
*/
|
||||
IPPrefix(const in6_addr& in6, uint8_t length);
|
||||
|
||||
/**
|
||||
* Constructs a prefix instance from an IPAddr object and prefix length.
|
||||
*
|
||||
* @param addr The IP address.
|
||||
*
|
||||
* @param length The prefix length in the range from 0 to 128
|
||||
*/
|
||||
IPPrefix(const IPAddr& addr, uint8_t length);
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
IPPrefix(const IPPrefix& other)
|
||||
: prefix(other.prefix), length(other.length) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~IPPrefix() { }
|
||||
|
||||
/**
|
||||
* Returns the prefix in the form of an IP address. The address will
|
||||
* have all bits not part of the prefixed set to zero.
|
||||
*/
|
||||
const IPAddr& Prefix() const { return prefix; }
|
||||
|
||||
/**
|
||||
* Returns the bit length of the prefix, relative to the 32 bits
|
||||
* of an IPv4 prefix or relative to the 128 bits of an IPv6 prefix.
|
||||
*/
|
||||
uint8_t Length() const
|
||||
{
|
||||
return prefix.GetFamily() == IPv4 ? length - 96 : length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit length of the prefix always relative to a full
|
||||
* 128 bits of an IPv6 prefix (or IPv4 mapped to IPv6).
|
||||
*/
|
||||
uint8_t LengthIPv6() const { return length; }
|
||||
|
||||
/** Returns true if the given address is part of the prefix.
|
||||
*
|
||||
* @param addr The address to test.
|
||||
*/
|
||||
bool Contains(const IPAddr& addr) const
|
||||
{
|
||||
IPAddr p(addr);
|
||||
p.Mask(length);
|
||||
return p == prefix;
|
||||
}
|
||||
/**
|
||||
* Assignment operator.
|
||||
*/
|
||||
IPPrefix& operator=(const IPPrefix& other)
|
||||
{
|
||||
// No self-assignment check here because it's correct without it and
|
||||
// makes the common case faster.
|
||||
prefix = other.prefix;
|
||||
length = other.length;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the prefix. IPv4 addresses
|
||||
* will be returned in dotted representation, IPv6 addresses in
|
||||
* compressed hex.
|
||||
*/
|
||||
string AsString() const;
|
||||
|
||||
operator std::string() const { return AsString(); }
|
||||
|
||||
/**
|
||||
* Returns a key that can be used to lookup the IP Prefix in a hash
|
||||
* table. Passes ownership to caller.
|
||||
*/
|
||||
HashKey* GetHashKey() const
|
||||
{
|
||||
struct {
|
||||
in6_addr ip;
|
||||
uint32 len;
|
||||
} key;
|
||||
|
||||
key.ip = prefix.in6;
|
||||
key.len = Length();
|
||||
|
||||
return new HashKey(&key, sizeof(key));
|
||||
}
|
||||
|
||||
/** Converts the prefix into the type used internally by the
|
||||
* inter-thread communication.
|
||||
*/
|
||||
void ConvertToThreadingValue(threading::Value::subnet_t* v) const
|
||||
{
|
||||
v->length = length;
|
||||
prefix.ConvertToThreadingValue(&v->prefix);
|
||||
}
|
||||
|
||||
unsigned int MemoryAllocation() const { return padded_sizeof(*this); }
|
||||
|
||||
/**
|
||||
* Comparison operator for IP prefix.
|
||||
*/
|
||||
friend bool operator==(const IPPrefix& net1, const IPPrefix& net2)
|
||||
{
|
||||
return net1.Prefix() == net2.Prefix() && net1.Length() == net2.Length();
|
||||
}
|
||||
|
||||
friend bool operator!=(const IPPrefix& net1, const IPPrefix& net2)
|
||||
{
|
||||
return ! (net1 == net2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison operator IP prefixes. This defines a well-defined order for
|
||||
* IP prefix. However, the order does not necessarily corresponding to their
|
||||
* numerical values.
|
||||
*/
|
||||
friend bool operator<(const IPPrefix& net1, const IPPrefix& net2)
|
||||
{
|
||||
if ( net1.Prefix() < net2.Prefix() )
|
||||
return true;
|
||||
|
||||
else if ( net1.Prefix() == net2.Prefix() )
|
||||
return net1.Length() < net2.Length();
|
||||
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
friend bool operator<=(const IPPrefix& net1, const IPPrefix& net2)
|
||||
{
|
||||
return net1 < net2 || net1 == net2;
|
||||
}
|
||||
|
||||
friend bool operator>=(const IPPrefix& net1, const IPPrefix& net2)
|
||||
{
|
||||
return ! (net1 < net2 );
|
||||
}
|
||||
|
||||
friend bool operator>(const IPPrefix& net1, const IPPrefix& net2)
|
||||
{
|
||||
return ! ( net1 <= net2 );
|
||||
}
|
||||
|
||||
private:
|
||||
IPAddr prefix; // We store it as an address with the non-prefix bits masked out via Mask().
|
||||
uint8_t length; // The bit length of the prefix relative to full IPv6 addr.
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1188,15 +1188,10 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig)
|
|||
if ( orig_status == REGISTERED && resp_status == REGISTERED &&
|
||||
orig_zip_status == ACCEPT_ZIP && resp_zip_status == ACCEPT_ZIP )
|
||||
{
|
||||
#ifdef HAVE_LIBZ
|
||||
orig_zip_status = ZIP_LOADED;
|
||||
resp_zip_status = ZIP_LOADED;
|
||||
AddSupportAnalyzer(new ZIP_Analyzer(Conn(), true));
|
||||
AddSupportAnalyzer(new ZIP_Analyzer(Conn(), false));
|
||||
#else
|
||||
reporter->Error("IRC analyzer lacking libz support");
|
||||
Remove();
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
140
src/LogMgr.h
140
src/LogMgr.h
|
@ -1,140 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
//
|
||||
// A class managing log writers and filters.
|
||||
|
||||
#ifndef LOGMGR_H
|
||||
#define LOGMGR_H
|
||||
|
||||
#include "Val.h"
|
||||
#include "EventHandler.h"
|
||||
#include "RemoteSerializer.h"
|
||||
|
||||
class SerializationFormat;
|
||||
|
||||
// Description of a log field.
|
||||
struct LogField {
|
||||
string name;
|
||||
TypeTag type;
|
||||
|
||||
LogField() { }
|
||||
LogField(const LogField& other)
|
||||
: name(other.name), type(other.type) { }
|
||||
|
||||
// (Un-)serialize.
|
||||
bool Read(SerializationFormat* fmt);
|
||||
bool Write(SerializationFormat* fmt) const;
|
||||
};
|
||||
|
||||
// Values as logged by a writer.
|
||||
struct LogVal {
|
||||
TypeTag type;
|
||||
bool present; // False for unset fields.
|
||||
|
||||
// The following union is a subset of BroValUnion, including only the
|
||||
// types we can log directly.
|
||||
struct set_t { bro_int_t size; LogVal** vals; };
|
||||
typedef set_t vec_t;
|
||||
|
||||
union _val {
|
||||
bro_int_t int_val;
|
||||
bro_uint_t uint_val;
|
||||
uint32 addr_val[NUM_ADDR_WORDS];
|
||||
subnet_type subnet_val;
|
||||
double double_val;
|
||||
string* string_val;
|
||||
set_t set_val;
|
||||
vec_t vector_val;
|
||||
} val;
|
||||
|
||||
LogVal(TypeTag arg_type = TYPE_ERROR, bool arg_present = true)
|
||||
: type(arg_type), present(arg_present) {}
|
||||
~LogVal();
|
||||
|
||||
// (Un-)serialize.
|
||||
bool Read(SerializationFormat* fmt);
|
||||
bool Write(SerializationFormat* fmt) const;
|
||||
|
||||
// Returns true if the type can be logged the framework. If
|
||||
// `atomic_only` is true, will not permit composite types.
|
||||
static bool IsCompatibleType(BroType* t, bool atomic_only=false);
|
||||
|
||||
private:
|
||||
LogVal(const LogVal& other) { }
|
||||
};
|
||||
|
||||
class LogWriter;
|
||||
class RemoteSerializer;
|
||||
class RotationTimer;
|
||||
|
||||
class LogMgr {
|
||||
public:
|
||||
LogMgr();
|
||||
~LogMgr();
|
||||
|
||||
// These correspond to the BiFs visible on the scripting layer. The
|
||||
// actual BiFs just forward here.
|
||||
bool CreateStream(EnumVal* id, RecordVal* stream);
|
||||
bool EnableStream(EnumVal* id);
|
||||
bool DisableStream(EnumVal* id);
|
||||
bool AddFilter(EnumVal* id, RecordVal* filter);
|
||||
bool RemoveFilter(EnumVal* id, StringVal* name);
|
||||
bool RemoveFilter(EnumVal* id, string name);
|
||||
bool Write(EnumVal* id, RecordVal* columns);
|
||||
bool SetBuf(EnumVal* id, bool enabled); // Adjusts all writers.
|
||||
bool Flush(EnumVal* id); // Flushes all writers..
|
||||
|
||||
protected:
|
||||
friend class LogWriter;
|
||||
friend class RemoteSerializer;
|
||||
friend class RotationTimer;
|
||||
|
||||
//// Function also used by the RemoteSerializer.
|
||||
|
||||
// Takes ownership of fields.
|
||||
LogWriter* CreateWriter(EnumVal* id, EnumVal* writer, string path,
|
||||
int num_fields, LogField** fields);
|
||||
|
||||
// Takes ownership of values..
|
||||
bool Write(EnumVal* id, EnumVal* writer, string path,
|
||||
int num_fields, LogVal** vals);
|
||||
|
||||
// Announces all instantiated writers to peer.
|
||||
void SendAllWritersTo(RemoteSerializer::PeerID peer);
|
||||
|
||||
//// Functions safe to use by writers.
|
||||
|
||||
// Signals that a file has been rotated.
|
||||
bool FinishedRotation(LogWriter* writer, string new_name, string old_name,
|
||||
double open, double close, bool terminating);
|
||||
|
||||
// Reports an error for the given writer.
|
||||
void Error(LogWriter* writer, const char* msg);
|
||||
|
||||
// Deletes the values as passed into Write().
|
||||
void DeleteVals(int num_fields, LogVal** vals);
|
||||
|
||||
private:
|
||||
struct Filter;
|
||||
struct Stream;
|
||||
struct WriterInfo;
|
||||
|
||||
bool TraverseRecord(Stream* stream, Filter* filter, RecordType* rt,
|
||||
TableVal* include, TableVal* exclude, string path, list<int> indices);
|
||||
|
||||
LogVal** RecordToFilterVals(Stream* stream, Filter* filter,
|
||||
RecordVal* columns);
|
||||
|
||||
LogVal* ValToLogVal(Val* val, BroType* ty = 0);
|
||||
Stream* FindStream(EnumVal* id);
|
||||
void RemoveDisabledWriters(Stream* stream);
|
||||
void InstallRotationTimer(WriterInfo* winfo);
|
||||
void Rotate(WriterInfo* info);
|
||||
Filter* FindFilter(EnumVal* id, StringVal* filter);
|
||||
WriterInfo* FindWriter(LogWriter* writer);
|
||||
|
||||
vector<Stream *> streams; // Indexed by stream enum.
|
||||
};
|
||||
|
||||
extern LogMgr* log_mgr;
|
||||
|
||||
#endif
|
158
src/LogWriter.cc
158
src/LogWriter.cc
|
@ -1,158 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "util.h"
|
||||
#include "LogWriter.h"
|
||||
|
||||
LogWriter::LogWriter()
|
||||
{
|
||||
buf = 0;
|
||||
buf_len = 1024;
|
||||
buffering = true;
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
LogWriter::~LogWriter()
|
||||
{
|
||||
if ( buf )
|
||||
free(buf);
|
||||
|
||||
for(int i = 0; i < num_fields; ++i)
|
||||
delete fields[i];
|
||||
|
||||
delete [] fields;
|
||||
}
|
||||
|
||||
bool LogWriter::Init(string arg_path, int arg_num_fields,
|
||||
const LogField* const * arg_fields)
|
||||
{
|
||||
path = arg_path;
|
||||
num_fields = arg_num_fields;
|
||||
fields = arg_fields;
|
||||
|
||||
if ( ! DoInit(arg_path, arg_num_fields, arg_fields) )
|
||||
{
|
||||
disabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogWriter::Write(int arg_num_fields, LogVal** vals)
|
||||
{
|
||||
// Double-check that the arguments match. If we get this from remote,
|
||||
// something might be mixed up.
|
||||
if ( num_fields != arg_num_fields )
|
||||
{
|
||||
DBG_LOG(DBG_LOGGING, "Number of fields don't match in LogWriter::Write() (%d vs. %d)",
|
||||
arg_num_fields, num_fields);
|
||||
|
||||
DeleteVals(vals);
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < num_fields; ++i )
|
||||
{
|
||||
if ( vals[i]->type != fields[i]->type )
|
||||
{
|
||||
DBG_LOG(DBG_LOGGING, "Field type doesn't match in LogWriter::Write() (%d vs. %d)",
|
||||
vals[i]->type, fields[i]->type);
|
||||
DeleteVals(vals);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = DoWrite(num_fields, fields, vals);
|
||||
|
||||
DeleteVals(vals);
|
||||
|
||||
if ( ! result )
|
||||
disabled = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LogWriter::SetBuf(bool enabled)
|
||||
{
|
||||
if ( enabled == buffering )
|
||||
// No change.
|
||||
return true;
|
||||
|
||||
buffering = enabled;
|
||||
|
||||
if ( ! DoSetBuf(enabled) )
|
||||
{
|
||||
disabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogWriter::Rotate(string rotated_path, double open,
|
||||
double close, bool terminating)
|
||||
{
|
||||
if ( ! DoRotate(rotated_path, open, close, terminating) )
|
||||
{
|
||||
disabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogWriter::Flush()
|
||||
{
|
||||
if ( ! DoFlush() )
|
||||
{
|
||||
disabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogWriter::Finish()
|
||||
{
|
||||
DoFinish();
|
||||
}
|
||||
|
||||
const char* LogWriter::Fmt(const char* format, ...)
|
||||
{
|
||||
if ( ! buf )
|
||||
buf = (char*) malloc(buf_len);
|
||||
|
||||
va_list al;
|
||||
va_start(al, format);
|
||||
int n = safe_vsnprintf(buf, buf_len, format, al);
|
||||
va_end(al);
|
||||
|
||||
if ( (unsigned int) n >= buf_len )
|
||||
{ // Not enough room, grow the buffer.
|
||||
buf_len = n + 32;
|
||||
buf = (char*) realloc(buf, buf_len);
|
||||
|
||||
// Is it portable to restart?
|
||||
va_start(al, format);
|
||||
n = safe_vsnprintf(buf, buf_len, format, al);
|
||||
va_end(al);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void LogWriter::Error(const char *msg)
|
||||
{
|
||||
log_mgr->Error(this, msg);
|
||||
}
|
||||
|
||||
void LogWriter::DeleteVals(LogVal** vals)
|
||||
{
|
||||
log_mgr->DeleteVals(num_fields, vals);
|
||||
}
|
||||
|
||||
bool LogWriter::FinishedRotation(string new_name, string old_name, double open,
|
||||
double close, bool terminating)
|
||||
{
|
||||
return log_mgr->FinishedRotation(this, new_name, old_name, open, close, terminating);
|
||||
}
|
192
src/LogWriter.h
192
src/LogWriter.h
|
@ -1,192 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
//
|
||||
// Interface API for a log writer backend. The LogMgr creates a separate
|
||||
// writer instance of pair of (writer type, output path).
|
||||
//
|
||||
// Note thay classes derived from LogWriter must be fully thread-safe and not
|
||||
// use any non-thread-safe Bro functionality (which includes almost
|
||||
// everything ...). In particular, do not use fmt() but LogWriter::Fmt()!.
|
||||
//
|
||||
// The one exception to this rule is the constructor: it is guaranteed to be
|
||||
// executed inside the main thread and can thus in particular access global
|
||||
// script variables.
|
||||
|
||||
#ifndef LOGWRITER_H
|
||||
#define LOGWRITER_H
|
||||
|
||||
#include "LogMgr.h"
|
||||
#include "BroString.h"
|
||||
|
||||
class LogWriter {
|
||||
public:
|
||||
LogWriter();
|
||||
virtual ~LogWriter();
|
||||
|
||||
//// Interface methods to interact with the writer. Note that these
|
||||
//// methods are not necessarily thread-safe and must be called only
|
||||
//// from the main thread (which will typically mean only from the
|
||||
//// LogMgr). In particular, they must not be called from the
|
||||
//// writer's derived implementation.
|
||||
|
||||
// One-time initialization of the writer to define the logged fields.
|
||||
// Interpretation of "path" is left to the writer, and will be
|
||||
// corresponding the value configured on the script-level.
|
||||
//
|
||||
// Returns false if an error occured, in which case the writer must
|
||||
// not be used further.
|
||||
//
|
||||
// The new instance takes ownership of "fields", and will delete them
|
||||
// when done.
|
||||
bool Init(string path, int num_fields, const LogField* const * fields);
|
||||
|
||||
// Writes one log entry. The method takes ownership of "vals" and
|
||||
// will return immediately after queueing the write request, which is
|
||||
// potentially before output has actually been written out.
|
||||
//
|
||||
// num_fields and the types of the LogVals must match what was passed
|
||||
// to Init().
|
||||
//
|
||||
// Returns false if an error occured, in which case the writer must
|
||||
// not be used any further.
|
||||
bool Write(int num_fields, LogVal** vals);
|
||||
|
||||
// Sets the buffering status for the writer, if the writer supports
|
||||
// that. (If not, it will be ignored).
|
||||
bool SetBuf(bool enabled);
|
||||
|
||||
// Flushes any currently buffered output, if the writer supports
|
||||
// that. (If not, it will be ignored).
|
||||
bool Flush();
|
||||
|
||||
// Triggers rotation, if the writer supports that. (If not, it will
|
||||
// be ignored).
|
||||
bool Rotate(string rotated_path, double open, double close, bool terminating);
|
||||
|
||||
// Finishes writing to this logger regularly. Must not be called if
|
||||
// an error has been indicated earlier. After calling this, no
|
||||
// further writing must be performed.
|
||||
void Finish();
|
||||
|
||||
//// Thread-safe methods that may be called from the writer
|
||||
//// implementation.
|
||||
|
||||
// The following methods return the information as passed to Init().
|
||||
const string Path() const { return path; }
|
||||
int NumFields() const { return num_fields; }
|
||||
const LogField* const * Fields() const { return fields; }
|
||||
|
||||
protected:
|
||||
// Methods for writers to override. If any of these returs false, it
|
||||
// will be assumed that a fatal error has occured that prevents the
|
||||
// writer from further operation. It will then be disabled and
|
||||
// deleted. When return false, the writer should also report the
|
||||
// error via Error(). Note that even if a writer does not support the
|
||||
// functionality for one these methods (like rotation), it must still
|
||||
// return true if that is not to be considered a fatal error.
|
||||
//
|
||||
// Called once for initialization of the writer.
|
||||
virtual bool DoInit(string path, int num_fields,
|
||||
const LogField* const * fields) = 0;
|
||||
|
||||
// Called once per log entry to record.
|
||||
virtual bool DoWrite(int num_fields, const LogField* const * fields,
|
||||
LogVal** vals) = 0;
|
||||
|
||||
// Called when the buffering status for this writer is changed. If
|
||||
// buffering is disabled, the writer should attempt to write out
|
||||
// information as quickly as possible even if doing so may have a
|
||||
// performance impact. If enabled (which is the default), it may
|
||||
// buffer data as helpful and write it out later in a way optimized
|
||||
// for performance. The current buffering state can be queried via
|
||||
// IsBuf().
|
||||
//
|
||||
// A writer may ignore buffering changes if it doesn't fit with its
|
||||
// semantics (but must still return true in that case).
|
||||
virtual bool DoSetBuf(bool enabled) = 0;
|
||||
|
||||
// Called to flush any currently buffered output.
|
||||
//
|
||||
// A writer may ignore flush requests if it doesn't fit with its
|
||||
// semantics (but must still return true in that case).
|
||||
virtual bool DoFlush() = 0;
|
||||
|
||||
// Called when a log output is to be rotated. Most directly this only
|
||||
// applies to writers writing into files, which should then close the
|
||||
// current file and open a new one. However, a writer may also
|
||||
// trigger other apppropiate actions if semantics are similar.
|
||||
//
|
||||
// Once rotation has finished, the implementation should call
|
||||
// RotationDone() to signal the log manager that potential
|
||||
// postprocessors can now run.
|
||||
//
|
||||
// "rotate_path" reflects the path to where the rotated output is to
|
||||
// be moved, with specifics depending on the writer. It should
|
||||
// generally be interpreted in a way consistent with that of "path"
|
||||
// as passed into DoInit(). As an example, for file-based output,
|
||||
// "rotate_path" could be the original filename extended with a
|
||||
// timestamp indicating the time of the rotation.
|
||||
//
|
||||
// "open" and "close" are the network time's when the *current* file
|
||||
// was opened and closed, respectively.
|
||||
//
|
||||
// "terminating" indicated whether the rotation request occurs due
|
||||
// the main Bro prcoess terminating (and not because we've reach a
|
||||
// regularly scheduled time for rotation).
|
||||
//
|
||||
// A writer may ignore rotation requests if it doesn't fit with its
|
||||
// semantics (but must still return true in that case).
|
||||
virtual bool DoRotate(string rotated_path, double open, double close,
|
||||
bool terminating) = 0;
|
||||
|
||||
// Called once on termination. Not called when any of the other
|
||||
// methods has previously signaled an error, i.e., executing this
|
||||
// method signals a regular shutdown of the writer.
|
||||
virtual void DoFinish() = 0;
|
||||
|
||||
//// Methods for writers to use. These are thread-safe.
|
||||
|
||||
// A thread-safe version of fmt().
|
||||
const char* Fmt(const char* format, ...);
|
||||
|
||||
// Returns the current buffering state.
|
||||
bool IsBuf() { return buffering; }
|
||||
|
||||
// Reports an error to the user.
|
||||
void Error(const char *msg);
|
||||
|
||||
// Signals to the log manager that a file has been rotated.
|
||||
//
|
||||
// new_name: The filename of the rotated file. old_name: The filename
|
||||
// of the origina file.
|
||||
//
|
||||
// open/close: The timestamps when the original file was opened and
|
||||
// closed, respectively.
|
||||
//
|
||||
// terminating: True if rotation request occured due to the main Bro
|
||||
// process shutting down.
|
||||
bool FinishedRotation(string new_name, string old_name, double open,
|
||||
double close, bool terminating);
|
||||
|
||||
private:
|
||||
friend class LogMgr;
|
||||
|
||||
// When an error occurs, we call this method to set a flag marking
|
||||
// the writer as disabled. The LogMgr will check the flag later and
|
||||
// remove the writer.
|
||||
bool Disabled() { return disabled; }
|
||||
|
||||
// Deletes the values as passed into Write().
|
||||
void DeleteVals(LogVal** vals);
|
||||
|
||||
string path;
|
||||
int num_fields;
|
||||
const LogField* const * fields;
|
||||
bool buffering;
|
||||
bool disabled;
|
||||
|
||||
// For implementing Fmt().
|
||||
char* buf;
|
||||
unsigned int buf_len;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,318 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <string>
|
||||
#include <errno.h>
|
||||
|
||||
#include "LogWriterAscii.h"
|
||||
#include "NetVar.h"
|
||||
|
||||
/**
|
||||
* Takes a string, escapes each character into its equivalent hex code (\x##), and
|
||||
* returns a string containing all escaped values.
|
||||
*
|
||||
* @param str string to escape
|
||||
* @return A std::string containing a list of escaped hex values of the form \x##
|
||||
*/
|
||||
static string get_escaped_string(const std::string& str)
|
||||
{
|
||||
char tbuf[16];
|
||||
string esc = "";
|
||||
|
||||
for ( size_t i = 0; i < str.length(); ++i )
|
||||
{
|
||||
snprintf(tbuf, sizeof(tbuf), "\\x%02x", str[i]);
|
||||
esc += tbuf;
|
||||
}
|
||||
|
||||
return esc;
|
||||
}
|
||||
|
||||
LogWriterAscii::LogWriterAscii()
|
||||
{
|
||||
file = 0;
|
||||
|
||||
output_to_stdout = BifConst::LogAscii::output_to_stdout;
|
||||
include_header = BifConst::LogAscii::include_header;
|
||||
|
||||
separator_len = BifConst::LogAscii::separator->Len();
|
||||
separator = new char[separator_len];
|
||||
memcpy(separator, BifConst::LogAscii::separator->Bytes(),
|
||||
separator_len);
|
||||
|
||||
set_separator_len = BifConst::LogAscii::set_separator->Len();
|
||||
set_separator = new char[set_separator_len];
|
||||
memcpy(set_separator, BifConst::LogAscii::set_separator->Bytes(),
|
||||
set_separator_len);
|
||||
|
||||
empty_field_len = BifConst::LogAscii::empty_field->Len();
|
||||
empty_field = new char[empty_field_len];
|
||||
memcpy(empty_field, BifConst::LogAscii::empty_field->Bytes(),
|
||||
empty_field_len);
|
||||
|
||||
unset_field_len = BifConst::LogAscii::unset_field->Len();
|
||||
unset_field = new char[unset_field_len];
|
||||
memcpy(unset_field, BifConst::LogAscii::unset_field->Bytes(),
|
||||
unset_field_len);
|
||||
|
||||
header_prefix_len = BifConst::LogAscii::header_prefix->Len();
|
||||
header_prefix = new char[header_prefix_len];
|
||||
memcpy(header_prefix, BifConst::LogAscii::header_prefix->Bytes(),
|
||||
header_prefix_len);
|
||||
|
||||
desc.SetEscape(separator, separator_len);
|
||||
}
|
||||
|
||||
LogWriterAscii::~LogWriterAscii()
|
||||
{
|
||||
if ( file )
|
||||
fclose(file);
|
||||
|
||||
delete [] separator;
|
||||
delete [] set_separator;
|
||||
delete [] empty_field;
|
||||
delete [] unset_field;
|
||||
delete [] header_prefix;
|
||||
}
|
||||
|
||||
bool LogWriterAscii::WriteHeaderField(const string& key, const string& val)
|
||||
{
|
||||
string str = string(header_prefix, header_prefix_len) +
|
||||
key + string(separator, separator_len) + val + "\n";
|
||||
|
||||
return (fwrite(str.c_str(), str.length(), 1, file) == 1);
|
||||
}
|
||||
|
||||
bool LogWriterAscii::DoInit(string path, int num_fields,
|
||||
const LogField* const * fields)
|
||||
{
|
||||
if ( output_to_stdout )
|
||||
path = "/dev/stdout";
|
||||
|
||||
fname = IsSpecial(path) ? path : path + ".log";
|
||||
|
||||
if ( ! (file = fopen(fname.c_str(), "w")) )
|
||||
{
|
||||
Error(Fmt("cannot open %s: %s", fname.c_str(),
|
||||
strerror(errno)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( include_header )
|
||||
{
|
||||
string str = string(header_prefix, header_prefix_len)
|
||||
+ "separator " // Always use space as separator here.
|
||||
+ get_escaped_string(string(separator, separator_len))
|
||||
+ "\n";
|
||||
|
||||
if( fwrite(str.c_str(), str.length(), 1, file) != 1 )
|
||||
goto write_error;
|
||||
|
||||
if ( ! WriteHeaderField("path", path) )
|
||||
goto write_error;
|
||||
|
||||
string names;
|
||||
string types;
|
||||
|
||||
for ( int i = 0; i < num_fields; ++i )
|
||||
{
|
||||
if ( i > 0 )
|
||||
{
|
||||
names += string(separator, separator_len);
|
||||
types += string(separator, separator_len);
|
||||
}
|
||||
|
||||
const LogField* field = fields[i];
|
||||
names += field->name;
|
||||
types += type_name(field->type);
|
||||
}
|
||||
|
||||
if ( ! (WriteHeaderField("fields", names)
|
||||
&& WriteHeaderField("types", types)) )
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
write_error:
|
||||
Error(Fmt("error writing to %s: %s", fname.c_str(), strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LogWriterAscii::DoFlush()
|
||||
{
|
||||
fflush(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogWriterAscii::DoFinish()
|
||||
{
|
||||
}
|
||||
|
||||
bool LogWriterAscii::DoWriteOne(ODesc* desc, LogVal* val, const LogField* field)
|
||||
{
|
||||
if ( ! val->present )
|
||||
{
|
||||
desc->AddN(unset_field, unset_field_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch ( val->type ) {
|
||||
|
||||
case TYPE_BOOL:
|
||||
desc->Add(val->val.int_val ? "T" : "F");
|
||||
break;
|
||||
|
||||
case TYPE_INT:
|
||||
desc->Add(val->val.int_val);
|
||||
break;
|
||||
|
||||
case TYPE_COUNT:
|
||||
case TYPE_COUNTER:
|
||||
case TYPE_PORT:
|
||||
desc->Add(val->val.uint_val);
|
||||
break;
|
||||
|
||||
case TYPE_SUBNET:
|
||||
desc->Add(dotted_addr(val->val.subnet_val.net));
|
||||
desc->Add("/");
|
||||
desc->Add(val->val.subnet_val.width);
|
||||
break;
|
||||
|
||||
case TYPE_ADDR:
|
||||
desc->Add(dotted_addr(val->val.addr_val));
|
||||
break;
|
||||
|
||||
case TYPE_TIME:
|
||||
case TYPE_INTERVAL:
|
||||
char buf[256];
|
||||
modp_dtoa(val->val.double_val, buf, 6);
|
||||
desc->Add(buf);
|
||||
break;
|
||||
|
||||
case TYPE_DOUBLE:
|
||||
desc->Add(val->val.double_val);
|
||||
break;
|
||||
|
||||
case TYPE_ENUM:
|
||||
case TYPE_STRING:
|
||||
case TYPE_FILE:
|
||||
case TYPE_FUNC:
|
||||
{
|
||||
int size = val->val.string_val->size();
|
||||
if ( size )
|
||||
desc->AddN(val->val.string_val->data(), val->val.string_val->size());
|
||||
else
|
||||
desc->AddN(empty_field, empty_field_len);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_TABLE:
|
||||
{
|
||||
if ( ! val->val.set_val.size )
|
||||
{
|
||||
desc->AddN(empty_field, empty_field_len);
|
||||
break;
|
||||
}
|
||||
|
||||
for ( int j = 0; j < val->val.set_val.size; j++ )
|
||||
{
|
||||
if ( j > 0 )
|
||||
desc->AddN(set_separator, set_separator_len);
|
||||
|
||||
if ( ! DoWriteOne(desc, val->val.set_val.vals[j], field) )
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
if ( ! val->val.vector_val.size )
|
||||
{
|
||||
desc->AddN(empty_field, empty_field_len);
|
||||
break;
|
||||
}
|
||||
|
||||
for ( int j = 0; j < val->val.vector_val.size; j++ )
|
||||
{
|
||||
if ( j > 0 )
|
||||
desc->AddN(set_separator, set_separator_len);
|
||||
|
||||
if ( ! DoWriteOne(desc, val->val.vector_val.vals[j], field) )
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Error(Fmt("unsupported field format %d for %s", val->type,
|
||||
field->name.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields,
|
||||
LogVal** vals)
|
||||
{
|
||||
if ( ! file )
|
||||
DoInit(Path(), NumFields(), Fields());
|
||||
|
||||
desc.Clear();
|
||||
|
||||
for ( int i = 0; i < num_fields; i++ )
|
||||
{
|
||||
if ( i > 0 )
|
||||
desc.AddRaw(separator, separator_len);
|
||||
|
||||
if ( ! DoWriteOne(&desc, vals[i], fields[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
desc.AddRaw("\n", 1);
|
||||
|
||||
if ( fwrite(desc.Bytes(), desc.Len(), 1, file) != 1 )
|
||||
{
|
||||
Error(Fmt("error writing to %s: %s", fname.c_str(), strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( IsBuf() )
|
||||
fflush(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogWriterAscii::DoRotate(string rotated_path, double open,
|
||||
double close, bool terminating)
|
||||
{
|
||||
// Don't rotate special files or if there's not one currently open.
|
||||
if ( ! file || IsSpecial(Path()) )
|
||||
return true;
|
||||
|
||||
fclose(file);
|
||||
file = 0;
|
||||
|
||||
string nname = rotated_path + ".log";
|
||||
rename(fname.c_str(), nname.c_str());
|
||||
|
||||
if ( ! FinishedRotation(nname, fname, open, close, terminating) )
|
||||
{
|
||||
Error(Fmt("error rotating %s to %s", fname.c_str(), nname.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogWriterAscii::DoSetBuf(bool enabled)
|
||||
{
|
||||
// Nothing to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
//
|
||||
// Log writer for delimiter-separated ASCII logs.
|
||||
|
||||
#ifndef LOGWRITERASCII_H
|
||||
#define LOGWRITERASCII_H
|
||||
|
||||
#include "LogWriter.h"
|
||||
|
||||
class LogWriterAscii : public LogWriter {
|
||||
public:
|
||||
LogWriterAscii();
|
||||
~LogWriterAscii();
|
||||
|
||||
static LogWriter* Instantiate() { return new LogWriterAscii; }
|
||||
|
||||
protected:
|
||||
virtual bool DoInit(string path, int num_fields,
|
||||
const LogField* const * fields);
|
||||
virtual bool DoWrite(int num_fields, const LogField* const * fields,
|
||||
LogVal** vals);
|
||||
virtual bool DoSetBuf(bool enabled);
|
||||
virtual bool DoRotate(string rotated_path, double open, double close,
|
||||
bool terminating);
|
||||
virtual bool DoFlush();
|
||||
virtual void DoFinish();
|
||||
|
||||
private:
|
||||
bool IsSpecial(string path) { return path.find("/dev/") == 0; }
|
||||
bool DoWriteOne(ODesc* desc, LogVal* val, const LogField* field);
|
||||
bool WriteHeaderField(const string& key, const string& value);
|
||||
|
||||
FILE* file;
|
||||
string fname;
|
||||
ODesc desc;
|
||||
|
||||
// Options set from the script-level.
|
||||
bool output_to_stdout;
|
||||
bool include_header;
|
||||
|
||||
char* separator;
|
||||
int separator_len;
|
||||
|
||||
char* set_separator;
|
||||
int set_separator_len;
|
||||
|
||||
char* empty_field;
|
||||
int empty_field_len;
|
||||
|
||||
char* unset_field;
|
||||
int unset_field_len;
|
||||
|
||||
char* header_prefix;
|
||||
int header_prefix_len;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#include "LogWriterNone.h"
|
||||
|
||||
bool LogWriterNone::DoRotate(string rotated_path, double open,
|
||||
double close, bool terminating)
|
||||
{
|
||||
if ( ! FinishedRotation(string("/dev/null"), Path(), open, close, terminating))
|
||||
{
|
||||
Error(Fmt("error rotating %s", Path().c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
//
|
||||
// Dummy log writer that just discards everything (but still pretends to rotate).
|
||||
|
||||
#ifndef LOGWRITERNONE_H
|
||||
#define LOGWRITERNONE_H
|
||||
|
||||
#include "LogWriter.h"
|
||||
|
||||
class LogWriterNone : public LogWriter {
|
||||
public:
|
||||
LogWriterNone() {}
|
||||
~LogWriterNone() {};
|
||||
|
||||
static LogWriter* Instantiate() { return new LogWriterNone; }
|
||||
|
||||
protected:
|
||||
virtual bool DoInit(string path, int num_fields,
|
||||
const LogField* const * fields) { return true; }
|
||||
|
||||
virtual bool DoWrite(int num_fields, const LogField* const * fields,
|
||||
LogVal** vals) { return true; }
|
||||
virtual bool DoSetBuf(bool enabled) { return true; }
|
||||
virtual bool DoRotate(string rotated_path, double open, double close,
|
||||
bool terminating);
|
||||
virtual bool DoFlush() { return true; }
|
||||
virtual void DoFinish() {}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -38,7 +38,7 @@ Login_Analyzer::Login_Analyzer(AnalyzerTag::Tag tag, Connection* conn)
|
|||
|
||||
if ( ! re_skip_authentication )
|
||||
{
|
||||
#ifdef USE_PERFTOOLS
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
HeapLeakChecker::Disabler disabler;
|
||||
#endif
|
||||
re_skip_authentication = init_RE(skip_authentication);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "MIME.h"
|
||||
#include "Event.h"
|
||||
#include "Reporter.h"
|
||||
#include "digest.h"
|
||||
|
||||
// Here are a few things to do:
|
||||
//
|
||||
|
@ -1008,7 +1009,7 @@ void MIME_Mail::Done()
|
|||
if ( compute_content_hash && mime_content_hash )
|
||||
{
|
||||
u_char* digest = new u_char[16];
|
||||
md5_finish(&md5_hash, digest);
|
||||
md5_final(&md5_hash, digest);
|
||||
|
||||
val_list* vl = new val_list;
|
||||
vl->append(analyzer->BuildConnVal());
|
||||
|
@ -1096,7 +1097,7 @@ void MIME_Mail::SubmitData(int len, const char* buf)
|
|||
if ( compute_content_hash )
|
||||
{
|
||||
content_hash_length += len;
|
||||
md5_append(&md5_hash, (const u_char*) buf, len);
|
||||
md5_update(&md5_hash, (const u_char*) buf, len);
|
||||
}
|
||||
|
||||
if ( mime_entity_data || mime_all_data )
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
#define mime_h
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/md5.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
using namespace std;
|
||||
|
||||
#include "md5.h"
|
||||
#include "Base64.h"
|
||||
#include "BroString.h"
|
||||
#include "Analyzer.h"
|
||||
|
@ -248,7 +247,7 @@ protected:
|
|||
int buffer_offset;
|
||||
int compute_content_hash;
|
||||
int content_hash_length;
|
||||
md5_state_t md5_hash;
|
||||
MD5_CTX md5_hash;
|
||||
vector<const BroString*> entity_content;
|
||||
vector<const BroString*> all_content;
|
||||
|
||||
|
|
|
@ -225,5 +225,7 @@ NCP_Analyzer::NCP_Analyzer(Connection* conn)
|
|||
NCP_Analyzer::~NCP_Analyzer()
|
||||
{
|
||||
delete session;
|
||||
delete o_ncp;
|
||||
delete r_ncp;
|
||||
}
|
||||
|
||||
|
|
15
src/Net.cc
15
src/Net.cc
|
@ -42,7 +42,6 @@ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
|
|||
PList(PktSrc) pkt_srcs;
|
||||
|
||||
// FIXME: We should really merge PktDumper and PacketDumper.
|
||||
// It's on my to-do [Robin].
|
||||
PktDumper* pkt_dumper = 0;
|
||||
|
||||
int reading_live = 0;
|
||||
|
@ -70,6 +69,7 @@ PktSrc* current_pktsrc = 0;
|
|||
IOSource* current_iosrc;
|
||||
|
||||
std::list<ScannedFile> files_scanned;
|
||||
std::vector<string> sig_files;
|
||||
|
||||
RETSIGTYPE watchdog(int /* signo */)
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ RETSIGTYPE watchdog(int /* signo */)
|
|||
return RETSIGVAL;
|
||||
}
|
||||
|
||||
void net_init(name_list& interfaces, name_list& readfiles,
|
||||
void net_init(name_list& interfaces, name_list& readfiles,
|
||||
name_list& netflows, name_list& flowfiles,
|
||||
const char* writefile, const char* filter,
|
||||
const char* secondary_filter, int do_watchdog)
|
||||
|
@ -248,12 +248,14 @@ void net_init(name_list& interfaces, name_list& readfiles,
|
|||
FlowSocketSrc* fs = new FlowSocketSrc(netflows[i]);
|
||||
|
||||
if ( ! fs->IsOpen() )
|
||||
{
|
||||
reporter->Error("%s: problem with netflow socket %s - %s\n",
|
||||
prog, netflows[i], fs->ErrorMsg());
|
||||
else
|
||||
{
|
||||
io_sources.Register(fs);
|
||||
delete fs;
|
||||
}
|
||||
|
||||
else
|
||||
io_sources.Register(fs);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -454,6 +456,7 @@ void net_run()
|
|||
// date on timers and events.
|
||||
network_time = ct;
|
||||
expire_timers();
|
||||
usleep(1); // Just yield.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,6 +486,8 @@ void net_run()
|
|||
// since Bro timers are not high-precision anyway.)
|
||||
if ( ! using_communication )
|
||||
usleep(100000);
|
||||
else
|
||||
usleep(1000);
|
||||
|
||||
// Flawfinder says about usleep:
|
||||
//
|
||||
|
|
|
@ -111,5 +111,6 @@ struct ScannedFile {
|
|||
};
|
||||
|
||||
extern std::list<ScannedFile> files_scanned;
|
||||
extern std::vector<string> sig_files;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,7 +16,9 @@ RecordType* pcap_packet;
|
|||
RecordType* signature_state;
|
||||
EnumType* transport_proto;
|
||||
TableType* string_set;
|
||||
TableType* string_array;
|
||||
TableType* count_set;
|
||||
VectorType* string_vec;
|
||||
|
||||
int watchdog_interval;
|
||||
|
||||
|
@ -29,7 +31,6 @@ int tcp_SYN_ack_ok;
|
|||
int tcp_match_undelivered;
|
||||
|
||||
int encap_hdr_size;
|
||||
int udp_tunnel_port;
|
||||
|
||||
double frag_timeout;
|
||||
|
||||
|
@ -45,17 +46,10 @@ int tcp_max_initial_window;
|
|||
int tcp_max_above_hole_without_any_acks;
|
||||
int tcp_excessive_data_without_further_acks;
|
||||
|
||||
int ssl_compare_cipherspecs;
|
||||
int ssl_analyze_certificates;
|
||||
int ssl_store_certificates;
|
||||
int ssl_verify_certificates;
|
||||
int ssl_store_key_material;
|
||||
int ssl_max_cipherspec_size;
|
||||
StringVal* ssl_store_cert_path;
|
||||
StringVal* x509_trusted_cert_path;
|
||||
TableType* cipher_suites_list;
|
||||
RecordType* x509_type;
|
||||
|
||||
RecordType* socks_address;
|
||||
|
||||
double non_analyzed_lifetime;
|
||||
double tcp_inactivity_timeout;
|
||||
double udp_inactivity_timeout;
|
||||
|
@ -174,6 +168,7 @@ TableVal* preserve_orig_addr;
|
|||
TableVal* preserve_resp_addr;
|
||||
TableVal* preserve_other_addr;
|
||||
|
||||
int max_files_in_cache;
|
||||
double log_rotate_interval;
|
||||
double log_max_size;
|
||||
RecordType* rotate_info;
|
||||
|
@ -190,8 +185,6 @@ StringVal* ssl_ca_certificate;
|
|||
StringVal* ssl_private_key;
|
||||
StringVal* ssl_passphrase;
|
||||
|
||||
StringVal* x509_crl_file;
|
||||
|
||||
Val* profiling_file;
|
||||
double profiling_interval;
|
||||
int expensive_profiling_multiple;
|
||||
|
@ -211,11 +204,6 @@ int sig_max_group_size;
|
|||
|
||||
int enable_syslog;
|
||||
|
||||
int use_connection_compressor;
|
||||
int cc_handle_resets;
|
||||
int cc_handle_only_syns;
|
||||
int cc_instantiate_on_data;
|
||||
|
||||
TableType* irc_join_list;
|
||||
RecordType* irc_join_info;
|
||||
TableVal* irc_servers;
|
||||
|
@ -255,6 +243,7 @@ StringVal* cmd_line_bpf_filter;
|
|||
#include "types.bif.netvar_def"
|
||||
#include "event.bif.netvar_def"
|
||||
#include "logging.bif.netvar_def"
|
||||
#include "input.bif.netvar_def"
|
||||
#include "reporter.bif.netvar_def"
|
||||
|
||||
void init_event_handlers()
|
||||
|
@ -271,6 +260,7 @@ void init_general_global_var()
|
|||
state_dir = internal_val("state_dir")->AsStringVal();
|
||||
state_write_delay = opt_internal_double("state_write_delay");
|
||||
|
||||
max_files_in_cache = opt_internal_int("max_files_in_cache");
|
||||
log_rotate_interval = opt_internal_double("log_rotate_interval");
|
||||
log_max_size = opt_internal_double("log_max_size");
|
||||
rotate_info = internal_type("rotate_info")->AsRecordType();
|
||||
|
@ -315,6 +305,7 @@ void init_net_var()
|
|||
#include "const.bif.netvar_init"
|
||||
#include "types.bif.netvar_init"
|
||||
#include "logging.bif.netvar_init"
|
||||
#include "input.bif.netvar_init"
|
||||
#include "reporter.bif.netvar_init"
|
||||
|
||||
conn_id = internal_type("conn_id")->AsRecordType();
|
||||
|
@ -328,6 +319,8 @@ void init_net_var()
|
|||
pcap_packet = internal_type("pcap_packet")->AsRecordType();
|
||||
transport_proto = internal_type("transport_proto")->AsEnumType();
|
||||
string_set = internal_type("string_set")->AsTableType();
|
||||
string_array = internal_type("string_array")->AsTableType();
|
||||
string_vec = internal_type("string_vec")->AsVectorType();
|
||||
|
||||
ignore_checksums = opt_internal_int("ignore_checksums");
|
||||
partial_connection_ok = opt_internal_int("partial_connection_ok");
|
||||
|
@ -336,8 +329,6 @@ void init_net_var()
|
|||
|
||||
encap_hdr_size = opt_internal_int("encap_hdr_size");
|
||||
|
||||
udp_tunnel_port = opt_internal_int("udp_tunnel_port") & ~UDP_PORT_MASK;
|
||||
|
||||
frag_timeout = opt_internal_double("frag_timeout");
|
||||
|
||||
tcp_SYN_timeout = opt_internal_double("tcp_SYN_timeout");
|
||||
|
@ -354,17 +345,9 @@ void init_net_var()
|
|||
tcp_excessive_data_without_further_acks =
|
||||
opt_internal_int("tcp_excessive_data_without_further_acks");
|
||||
|
||||
ssl_compare_cipherspecs = opt_internal_int("ssl_compare_cipherspecs");
|
||||
ssl_analyze_certificates = opt_internal_int("ssl_analyze_certificates");
|
||||
ssl_store_certificates = opt_internal_int("ssl_store_certificates");
|
||||
ssl_verify_certificates = opt_internal_int("ssl_verify_certificates");
|
||||
ssl_store_key_material = opt_internal_int("ssl_store_key_material");
|
||||
ssl_max_cipherspec_size = opt_internal_int("ssl_max_cipherspec_size");
|
||||
|
||||
x509_trusted_cert_path = opt_internal_string("X509_trusted_cert_path");
|
||||
ssl_store_cert_path = opt_internal_string("ssl_store_cert_path");
|
||||
x509_type = internal_type("X509")->AsRecordType();
|
||||
x509_crl_file = opt_internal_string("X509_crl_file");
|
||||
|
||||
socks_address = internal_type("SOCKS::Address")->AsRecordType();
|
||||
|
||||
non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime");
|
||||
tcp_inactivity_timeout = opt_internal_double("tcp_inactivity_timeout");
|
||||
|
@ -521,12 +504,6 @@ void init_net_var()
|
|||
|
||||
gap_report_freq = opt_internal_double("gap_report_freq");
|
||||
|
||||
use_connection_compressor =
|
||||
opt_internal_int("use_connection_compressor");
|
||||
cc_handle_resets = opt_internal_int("cc_handle_resets");
|
||||
cc_handle_only_syns = opt_internal_int("cc_handle_only_syns");
|
||||
cc_instantiate_on_data = opt_internal_int("cc_instantiate_on_data");
|
||||
|
||||
irc_join_info = internal_type("irc_join_info")->AsRecordType();
|
||||
irc_join_list = internal_type("irc_join_list")->AsTableType();
|
||||
irc_servers = internal_val("irc_servers")->AsTableVal();
|
||||
|
|
22
src/NetVar.h
22
src/NetVar.h
|
@ -19,7 +19,9 @@ extern RecordType* SYN_packet;
|
|||
extern RecordType* pcap_packet;
|
||||
extern EnumType* transport_proto;
|
||||
extern TableType* string_set;
|
||||
extern TableType* string_array;
|
||||
extern TableType* count_set;
|
||||
extern VectorType* string_vec;
|
||||
|
||||
extern int watchdog_interval;
|
||||
|
||||
|
@ -32,7 +34,6 @@ extern int tcp_SYN_ack_ok;
|
|||
extern int tcp_match_undelivered;
|
||||
|
||||
extern int encap_hdr_size;
|
||||
extern int udp_tunnel_port;
|
||||
|
||||
extern double frag_timeout;
|
||||
|
||||
|
@ -48,17 +49,9 @@ extern int tcp_max_initial_window;
|
|||
extern int tcp_max_above_hole_without_any_acks;
|
||||
extern int tcp_excessive_data_without_further_acks;
|
||||
|
||||
// see policy/ssl.bro for details
|
||||
extern int ssl_compare_cipherspecs;
|
||||
extern int ssl_analyze_certificates;
|
||||
extern int ssl_store_certificates;
|
||||
extern int ssl_verify_certificates;
|
||||
extern int ssl_store_key_material;
|
||||
extern int ssl_max_cipherspec_size;
|
||||
extern StringVal* ssl_store_cert_path;
|
||||
extern StringVal* x509_trusted_cert_path;
|
||||
extern RecordType* x509_type;
|
||||
extern StringVal* x509_crl_file;
|
||||
|
||||
extern RecordType* socks_address;
|
||||
|
||||
extern double non_analyzed_lifetime;
|
||||
extern double tcp_inactivity_timeout;
|
||||
|
@ -178,6 +171,7 @@ extern double connection_status_update_interval;
|
|||
extern StringVal* state_dir;
|
||||
extern double state_write_delay;
|
||||
|
||||
extern int max_files_in_cache;
|
||||
extern double log_rotate_interval;
|
||||
extern double log_max_size;
|
||||
extern RecordType* rotate_info;
|
||||
|
@ -214,11 +208,6 @@ extern int sig_max_group_size;
|
|||
|
||||
extern int enable_syslog;
|
||||
|
||||
extern int use_connection_compressor;
|
||||
extern int cc_handle_resets;
|
||||
extern int cc_handle_only_syns;
|
||||
extern int cc_instantiate_on_data;
|
||||
|
||||
extern TableType* irc_join_list;
|
||||
extern RecordType* irc_join_info;
|
||||
extern TableVal* irc_servers;
|
||||
|
@ -264,6 +253,7 @@ extern void init_net_var();
|
|||
#include "types.bif.netvar_h"
|
||||
#include "event.bif.netvar_h"
|
||||
#include "logging.bif.netvar_h"
|
||||
#include "input.bif.netvar_h"
|
||||
#include "reporter.bif.netvar_h"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -110,7 +110,7 @@ int NetbiosSSN_Interpreter::ParseDatagram(const u_char* data, int len,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
|
||||
int is_query)
|
||||
{
|
||||
|
@ -131,6 +131,9 @@ int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
delete srcname;
|
||||
delete dstname;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,15 +63,16 @@ OSFingerprint::OSFingerprint(FingerprintMode arg_mode)
|
|||
}
|
||||
}
|
||||
|
||||
bool OSFingerprint::CacheMatch(uint32 addr, int id)
|
||||
bool OSFingerprint::CacheMatch(const IPAddr& addr, int id)
|
||||
{
|
||||
HashKey key = HashKey(&addr, 1);
|
||||
HashKey* key = addr.GetHashKey();
|
||||
int* pid = new int;
|
||||
*pid=id;
|
||||
int* prev = os_matches.Insert(&key, pid);
|
||||
int* prev = os_matches.Insert(key, pid);
|
||||
bool ret = (prev ? *prev != id : 1);
|
||||
if (prev)
|
||||
delete prev;
|
||||
delete key;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "util.h"
|
||||
#include "Dict.h"
|
||||
#include "Reporter.h"
|
||||
#include "IPAddr.h"
|
||||
|
||||
// Size limit for size wildcards.
|
||||
#define PACKET_BIG 100
|
||||
|
@ -88,7 +89,7 @@ public:
|
|||
int FindMatch(struct os_type* retval, uint16 tot, uint8 DF_flag,
|
||||
uint8 TTL, uint16 WSS, uint8 ocnt, uint8* op, uint16 MSS,
|
||||
uint8 win_scale, uint32 tstamp, uint32 quirks, uint8 ECN) const;
|
||||
bool CacheMatch(uint32 addr, int id);
|
||||
bool CacheMatch(const IPAddr& addr, int id);
|
||||
|
||||
int Get_OS_From_SYN(struct os_type* retval,
|
||||
uint16 tot, uint8 DF_flag, uint8 TTL, uint16 WSS,
|
||||
|
|
10
src/PIA.cc
10
src/PIA.cc
|
@ -196,20 +196,20 @@ void PIA_TCP::FirstPacket(bool is_orig, const IP_Hdr* ip)
|
|||
ip4->ip_p = IPPROTO_TCP;
|
||||
|
||||
// Cast to const so that it doesn't delete it.
|
||||
ip4_hdr = new IP_Hdr((const struct ip*) ip4);
|
||||
ip4_hdr = new IP_Hdr(ip4, false);
|
||||
}
|
||||
|
||||
if ( is_orig )
|
||||
{
|
||||
copy_addr(Conn()->OrigAddr(), &ip4->ip_src.s_addr);
|
||||
copy_addr(Conn()->RespAddr(), &ip4->ip_dst.s_addr);
|
||||
Conn()->OrigAddr().CopyIPv4(&ip4->ip_src);
|
||||
Conn()->RespAddr().CopyIPv4(&ip4->ip_dst);
|
||||
tcp4->th_sport = htons(Conn()->OrigPort());
|
||||
tcp4->th_dport = htons(Conn()->RespPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_addr(Conn()->RespAddr(), &ip4->ip_src.s_addr);
|
||||
copy_addr(Conn()->OrigAddr(), &ip4->ip_dst.s_addr);
|
||||
Conn()->RespAddr().CopyIPv4(&ip4->ip_src);
|
||||
Conn()->OrigAddr().CopyIPv4(&ip4->ip_dst);
|
||||
tcp4->th_sport = htons(Conn()->RespPort());
|
||||
tcp4->th_dport = htons(Conn()->OrigPort());
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ void POP3_Analyzer::ProcessRequest(int length, const char* line)
|
|||
if ( e >= end )
|
||||
{
|
||||
Weird("pop3_malformed_auth_plain");
|
||||
delete decoded;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -167,6 +168,7 @@ void POP3_Analyzer::ProcessRequest(int length, const char* line)
|
|||
if ( s >= end )
|
||||
{
|
||||
Weird("pop3_malformed_auth_plain");
|
||||
delete decoded;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include "PacketFilter.h"
|
||||
|
||||
void PacketFilter::AddSrc(addr_type src, uint32 tcp_flags, double probability)
|
||||
void PacketFilter::AddSrc(const IPAddr& src, uint32 tcp_flags, double probability)
|
||||
{
|
||||
Filter* f = new Filter;
|
||||
f->tcp_flags = tcp_flags;
|
||||
f->probability = uint32(probability * RAND_MAX);
|
||||
src_filter.Insert(src, NUM_ADDR_WORDS * 32, f);
|
||||
src_filter.Insert(src, 128, f);
|
||||
}
|
||||
|
||||
void PacketFilter::AddSrc(Val* src, uint32 tcp_flags, double probability)
|
||||
|
@ -16,12 +16,12 @@ void PacketFilter::AddSrc(Val* src, uint32 tcp_flags, double probability)
|
|||
src_filter.Insert(src, f);
|
||||
}
|
||||
|
||||
void PacketFilter::AddDst(addr_type dst, uint32 tcp_flags, double probability)
|
||||
void PacketFilter::AddDst(const IPAddr& dst, uint32 tcp_flags, double probability)
|
||||
{
|
||||
Filter* f = new Filter;
|
||||
f->tcp_flags = tcp_flags;
|
||||
f->probability = uint32(probability * RAND_MAX);
|
||||
dst_filter.Insert(dst, NUM_ADDR_WORDS * 32, f);
|
||||
dst_filter.Insert(dst, 128, f);
|
||||
}
|
||||
|
||||
void PacketFilter::AddDst(Val* dst, uint32 tcp_flags, double probability)
|
||||
|
@ -32,9 +32,9 @@ void PacketFilter::AddDst(Val* dst, uint32 tcp_flags, double probability)
|
|||
dst_filter.Insert(dst, f);
|
||||
}
|
||||
|
||||
bool PacketFilter::RemoveSrc(addr_type src)
|
||||
bool PacketFilter::RemoveSrc(const IPAddr& src)
|
||||
{
|
||||
return src_filter.Remove(src, NUM_ADDR_WORDS * 32) != 0;
|
||||
return src_filter.Remove(src, 128) != 0;
|
||||
}
|
||||
|
||||
bool PacketFilter::RemoveSrc(Val* src)
|
||||
|
@ -42,9 +42,9 @@ bool PacketFilter::RemoveSrc(Val* src)
|
|||
return src_filter.Remove(src) != NULL;
|
||||
}
|
||||
|
||||
bool PacketFilter::RemoveDst(addr_type dst)
|
||||
bool PacketFilter::RemoveDst(const IPAddr& dst)
|
||||
{
|
||||
return dst_filter.Remove(dst, NUM_ADDR_WORDS * 32) != NULL;
|
||||
return dst_filter.Remove(dst, 128) != NULL;
|
||||
}
|
||||
|
||||
bool PacketFilter::RemoveDst(Val* dst)
|
||||
|
@ -54,21 +54,11 @@ bool PacketFilter::RemoveDst(Val* dst)
|
|||
|
||||
bool PacketFilter::Match(const IP_Hdr* ip, int len, int caplen)
|
||||
{
|
||||
#ifdef BROv6
|
||||
Filter* f = (Filter*) src_filter.Lookup(ip->SrcAddr(),
|
||||
NUM_ADDR_WORDS * 32);
|
||||
#else
|
||||
Filter* f = (Filter*) src_filter.Lookup(*ip->SrcAddr(),
|
||||
NUM_ADDR_WORDS * 32);
|
||||
#endif
|
||||
Filter* f = (Filter*) src_filter.Lookup(ip->SrcAddr(), 128);
|
||||
if ( f )
|
||||
return MatchFilter(*f, *ip, len, caplen);
|
||||
|
||||
#ifdef BROv6
|
||||
f = (Filter*) dst_filter.Lookup(ip->DstAddr(), NUM_ADDR_WORDS * 32);
|
||||
#else
|
||||
f = (Filter*) dst_filter.Lookup(*ip->DstAddr(), NUM_ADDR_WORDS * 32);
|
||||
#endif
|
||||
f = (Filter*) dst_filter.Lookup(ip->DstAddr(), 128);
|
||||
if ( f )
|
||||
return MatchFilter(*f, *ip, len, caplen);
|
||||
|
||||
|
@ -81,9 +71,7 @@ bool PacketFilter::MatchFilter(const Filter& f, const IP_Hdr& ip,
|
|||
if ( ip.NextProto() == IPPROTO_TCP && f.tcp_flags )
|
||||
{
|
||||
// Caution! The packet sanity checks have not been performed yet
|
||||
const struct ip* ip4 = ip.IP4_Hdr();
|
||||
|
||||
int ip_hdr_len = ip4->ip_hl * 4;
|
||||
int ip_hdr_len = ip.HdrLen();
|
||||
len -= ip_hdr_len; // remove IP header
|
||||
caplen -= ip_hdr_len;
|
||||
|
||||
|
@ -92,8 +80,7 @@ bool PacketFilter::MatchFilter(const Filter& f, const IP_Hdr& ip,
|
|||
// Packet too short, will be dropped anyway.
|
||||
return false;
|
||||
|
||||
const struct tcphdr* tp =
|
||||
(const struct tcphdr*) ((u_char*) ip4 + ip_hdr_len);
|
||||
const struct tcphdr* tp = (const struct tcphdr*) ip.Payload();
|
||||
|
||||
if ( tp->th_flags & f.tcp_flags )
|
||||
// At least one of the flags is set, so don't drop
|
||||
|
|
|
@ -14,16 +14,16 @@ public:
|
|||
// Drops all packets from a particular source (which may be given
|
||||
// as an AddrVal or a SubnetVal) which hasn't any of TCP flags set
|
||||
// (TH_*) with the given probability (from 0..MAX_PROB).
|
||||
void AddSrc(addr_type src, uint32 tcp_flags, double probability);
|
||||
void AddSrc(const IPAddr& src, uint32 tcp_flags, double probability);
|
||||
void AddSrc(Val* src, uint32 tcp_flags, double probability);
|
||||
void AddDst(addr_type src, uint32 tcp_flags, double probability);
|
||||
void AddDst(const IPAddr& src, uint32 tcp_flags, double probability);
|
||||
void AddDst(Val* src, uint32 tcp_flags, double probability);
|
||||
|
||||
// Removes the filter entry for the given src/dst
|
||||
// Returns false if filter doesn not exist.
|
||||
bool RemoveSrc(addr_type src);
|
||||
bool RemoveSrc(const IPAddr& src);
|
||||
bool RemoveSrc(Val* dst);
|
||||
bool RemoveDst(addr_type dst);
|
||||
bool RemoveDst(const IPAddr& dst);
|
||||
bool RemoveDst(Val* dst);
|
||||
|
||||
// Returns true if packet matches a drop filter
|
||||
|
|
|
@ -27,13 +27,16 @@ PacketSortElement::PacketSortElement(PktSrc* arg_src,
|
|||
{
|
||||
const struct ip* ip = (const struct ip*) (pkt + hdr_size);
|
||||
if ( ip->ip_v == 4 )
|
||||
ip_hdr = new IP_Hdr(ip);
|
||||
ip_hdr = new IP_Hdr(ip, false);
|
||||
else if ( ip->ip_v == 6 && (caplen >= sizeof(struct ip6_hdr) + hdr_size) )
|
||||
ip_hdr = new IP_Hdr((const struct ip6_hdr*) ip, false, caplen - hdr_size);
|
||||
else
|
||||
ip_hdr = new IP_Hdr((const struct ip6_hdr*) ip);
|
||||
// Weird will be generated later in NetSessions::NextPacket.
|
||||
return;
|
||||
|
||||
if ( ip_hdr->NextProto() == IPPROTO_TCP &&
|
||||
// Note: can't sort fragmented packets
|
||||
(ip_hdr->FragField() & 0x3fff) == 0 )
|
||||
( ! ip_hdr->IsFragment() ) )
|
||||
{
|
||||
tcp_offset = hdr_size + ip_hdr->HdrLen();
|
||||
if ( caplen >= tcp_offset + sizeof(struct tcphdr) )
|
||||
|
@ -65,7 +68,7 @@ PacketSortElement::PacketSortElement(PktSrc* arg_src,
|
|||
|
||||
payload_length = ip_hdr->PayloadLen() - tp->th_off * 4;
|
||||
|
||||
key = id.BuildConnKey();
|
||||
key = BuildConnIDHashKey(id);
|
||||
|
||||
is_tcp = 1;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ bool PersistenceSerializer::CheckForFile(UnserialInfo* info, const char* file,
|
|||
|
||||
bool PersistenceSerializer::ReadAll(bool is_init, bool delete_files)
|
||||
{
|
||||
#ifdef USE_PERFTOOLS
|
||||
#ifdef USE_PERFTOOLS_DEBUG
|
||||
HeapLeakChecker::Disabler disabler;
|
||||
#endif
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue