Problem about BinPAC , wish to get your help

Hi , I am very glad to write this email . I am a user of bro and recently I start to use BinPAC which is a subcomponent of bro . After learning the syntax of BinPAC , I wrote some simple BinPAC programs and tested them . I got a problem during the test and it really confused me . So I am writing to you and hope to get your help . I will describe my problem below .

My BinPAC version is 0.47 .

In the test I have two machines , A and B . One process on machine A sends messages to another process on machine B once per second . the message is in this format :

la(uint32) + lb (uint32) + s(a random string whose length is not fixed)

In the message , “la” and “lb” are both the length of the string “s” . For example , la = 26 , lb = 26 , s = “abcdefghijklmnopqrstuvwxyz” . Another example , la = 10 , lb = 10 , s = “helloworld” . So I wrote a BinPAC program (see file_1.pac in attachment) and it worked as expected . But when I made a small change to the BinPAC program (see file_2.pac in attachment), a bug existed .

In the first case , I defined a type “header” which contains “la : unint32” and “lb : uint32” and I defined another type “body” which only contains “s : bytestring” . And I defined a high-level type which contains “header” and “body” . Then I print out “la” and the length of “s” . It showed that the program worked properly , the output is like this :

238 238
309 309
311 311
339 339
344 344
252 252
290 290
312 312
298 298
300 300
281 281

That is what I want . The first number in each line is “la” and the second number is the length of “s” .

But when I didn’t define the “header” type but wrote “la : uint32 ; lb : uint32” in the high-level type directly instead , it failed to work , I mean , nothing was printed out .

In “file_2.pac” , I wrote like this :

type trans_pdu(is_orig: bool) = record {
la: uint32 &byteorder=bigendian;
lb: uint32 &byteorder=bigendian;
body: trans_body(x) &requires(x);
} &let{
x = la;
} &length = x + 8;

I read the file generated by binpac (“file_2.cc”) , and I added 2 lines into “file_2.cc” to debug it to see what would happen (the additional codes just print out buffering state , the address of “t_begin_of_data” , the address of “t_end_of_data” and “throw”) . The following is part of the code of “file_2.cc” . Only the two “printf” sentences are added by me .

bool trans_pdu::ParseBuffer(flow_buffer_t t_flow_buffer, Contexttrans * t_context)
{
bool t_val_parsing_complete;
t_val_parsing_complete = false;
const_byteptr t_begin_of_data = t_flow_buffer->begin();
const_byteptr t_end_of_data = t_flow_buffer->end();
printf(“buffering state: %d t_begin_of_data: %d t_end_of_data: %d \n” , buffering_state_ , (void*)t_begin_of_data , (void*)t_end_of_data);
switch ( buffering_state_ )
{
case 0:
if ( buffering_state_ == 0 )
{
t_flow_buffer->NewFrame(4, false);
buffering_state_ = 1;
}
buffering_state_ = 1;
break;
case 1:
{
buffering_state_ = 2;
// Checking out-of-bound for “trans_pdu:lb”
if ( (t_begin_of_data + 4) + (4) > t_end_of_data || (t_begin_of_data + 4) + (4) < (t_begin_of_data + 4) )
{
printf("throw*\n");*
// Handle out-of-bound condition
throw binpac::ExceptionOutOfBound(“trans_pdu:lb”,
(4) + (4),
(t_end_of_data) - (t_begin_of_data));
}
// Parse “la”
la_ = FixByteOrder(bigendian, *((uint32 const *) (t_begin_of_data)));
// Evaluate ‘let’ and ‘withinput’ fields
x_ = la();
t_flow_buffer->GrowFrame(x() + 8);
}
break;
case 2:
BINPAC_ASSERT(t_flow_buffer->ready());
if ( t_flow_buffer->ready() )
{

// Parse “lb”
lb_ = FixByteOrder(bigendian, *((uint32 const *) ((t_begin_of_data + 4))));
// Evaluate ‘let’ and ‘withinput’ fields

// Parse “body”
body_ = new trans_body(x());
int t_body__size;
t_body__size = body_->Parse((t_begin_of_data + 8), t_end_of_data);
// Evaluate ‘let’ and ‘withinput’ fields

t_val_parsing_complete = true;
if ( t_val_parsing_complete )
{
// Evaluate ‘let’ and ‘withinput’ fields
proc_ = t_context->flow()->proc_sample_message(this);
}
BINPAC_ASSERT(t_val_parsing_complete);
buffering_state_ = 0;
}
break;
default:
BINPAC_ASSERT(buffering_state_ <= 2);
break;
}
return t_val_parsing_complete;

}

void trans_flow::NewData(const_byteptr t_begin_of_data, const_byteptr t_end_of_data)

{

while ( ! t_dataunit_parsing_complete && flow_buffer_->ready() )
{
const_byteptr t_begin_of_data = flow_buffer()->begin();
const_byteptr t_end_of_data = flow_buffer()->end();
t_dataunit_parsing_complete = dataunit_->ParseBuffer(flow_buffer(), context_);
if ( t_dataunit_parsing_complete )
{
// Evaluate ‘let’ and ‘withinput’ fields
}
}

}

and the following is the output :

buffering state: 0 t_begin_of_data: 44665856 t_end_of_data: 44665856
buffering state: 1 t_begin_of_data: 44665856 t_end_of_data: 44665860
throw
buffering state: 0 t_begin_of_data: 44669328 t_end_of_data: 44669328
buffering state: 1 t_begin_of_data: 44669328 t_end_of_data: 44669332
throw
buffering state: 0 t_begin_of_data: 44687568 t_end_of_data: 44687568
buffering state: 1 t_begin_of_data: 44687568 t_end_of_data: 44687572
throw
buffering state: 0 t_begin_of_data: 44688176 t_end_of_data: 44688176
buffering state: 1 t_begin_of_data: 44688176 t_end_of_data: 44688180
throw

I guess that in " case 0 " , the sentence " t_flow_buffer->NewFrame(4, false) " is used to create a 4-byte frame to parse “la” , since “la” occupies the first 4 bytes of the message and BinPAC need it evaluate the length of the message ? After this operation , "t_begin_of_data " points to the begin of the message and “t_end_of_data” points to the end of “la” . But then " case 1 " will take place . “lb” will be checked whether out-of-bound . “t_begin_of_data + 4” is the begin of “lb” , " 4 " is the length of “lb” , but “t_end_of_data” still points to the end of la . So “(t_begin_of_data + 4) + (4) > t_end_of_data” was met , and the program didn’t go ahead . However , that is only the direct reason but not the source reason . I guess the source reason is that I didn’t write the BinPAC code in the correct way somewhere or maybe there is a small bug in BinPAC .

I really really hope to use BinPAC to deal with some protocol analysis . I tried to read the source code of BinPAC but failed to understand . I don’t know what to do and I really want to get your help !

Wish to get your reply !

Good luck !

Yunchao Chen

2018.2.27

file_2.pac (1.06 KB)

file_1.pac (1.12 KB)