Merge remote-tracking branch 'origin/master' into topic/seth/pppoe

This commit is contained in:
Seth Hall 2012-10-24 00:50:43 -04:00
commit 012acb22e9
1326 changed files with 60201 additions and 14196 deletions

View file

@ -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);

View file

@ -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
View 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
View 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

View file

@ -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()

View file

@ -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)

View file

@ -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
};

View file

@ -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 )
{

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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 */

View file

@ -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)

View file

@ -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); }

View file

@ -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)

View file

@ -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); }

View file

@ -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
}

View file

@ -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;

View file

@ -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
View 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
View 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_ */

View file

@ -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)

View file

@ -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 */

View file

@ -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

View file

@ -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:

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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" : "?"));

View file

@ -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);

View file

@ -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,

View file

@ -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); }

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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)

View file

@ -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
};

View file

@ -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)

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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 )

View file

@ -7,7 +7,6 @@
#include "List.h"
#include "BroList.h"
#include "net_util.h"
class Func;
class FuncType;

View file

@ -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;
}

View file

@ -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);

View file

@ -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();
}

View file

@ -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

View file

@ -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)));

View file

@ -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; }

View file

@ -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

View file

@ -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

View file

@ -58,7 +58,7 @@ void FlowSrc::Process()
void FlowSrc::Close()
{
close(selectable_fd);
safe_close(selectable_fd);
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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"

View file

@ -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();

View file

@ -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);

View file

@ -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)

View file

@ -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); }

View file

@ -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;

View file

@ -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();

View file

@ -7,7 +7,7 @@
#include "BroString.h"
#define UHASH_KEY_SIZE 32
#define UHASH_KEY_SIZE 36
typedef uint64 hash_t;

View file

@ -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;
}
}

View file

@ -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

View file

@ -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
View 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
View file

@ -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
View 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
View 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

View file

@ -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;

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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 )

View file

@ -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;

View file

@ -225,5 +225,7 @@ NCP_Analyzer::NCP_Analyzer(Connection* conn)
NCP_Analyzer::~NCP_Analyzer()
{
delete session;
delete o_ncp;
delete r_ncp;
}

View file

@ -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:
//

View file

@ -111,5 +111,6 @@ struct ScannedFile {
};
extern std::list<ScannedFile> files_scanned;
extern std::vector<string> sig_files;
#endif

View file

@ -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();

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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,

View file

@ -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());
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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