пятница, 14 ноября 2008 г.

Cisco Raw Data Record format

PRELUDE:

Recently the company I work at bought SCE which reports data throught Netflow v9. Though, in the other docs the SCE is said not to support Netflow v9. So we decided to catch RDRs and convert it to Netflow v5.
I was disappointed that the Raw Data Records: Formats and Field Contents document didn't contain full format description of RDR. It misses the main point: it doesn't tell you how the fields are layed out after you meet certain TAG.
Hopefully, we found a man who have already done RDR to Netflow v5 converter and asked him to help us out with RDR format. He sent us his RDR to Netflow v5 converter which I was observing. When I found out the RDR layout I was once again disappointed, because the first time I tried to catch and read RDRs, I used plain C structures.
For example, Transaction usage RDR contains almost all we need for a Netflow v5 packet. So I used
struct TUR {
char *subscriberID;
unsigned short packageID;
int serviceID;
- - - -
};

When thinking how they could send strings I assumed they simply send zero terminated strings like C does. That was false.

TOPIC:

GCC typedefs I use:
//! Typedef for signed 8-bit integer
typedef signed char s8;
//! Typedef for signed 16-bit integer
typedef signed short s16;
//! Typedef for signed 32-bit integer
typedef signed int s32;
//! Typedef for unsigned 8-bit integer
typedef unsigned char u8;
//! Typedef for unsigned 16-bit integer
typedef unsigned short u16;
//! Typedef for unsigned 32-bit integer
typedef unsigned int u32;


Every RDR field has the following format:
struct RDRField {
u8 type; // Field type
u32 size; // Field size
void *data;
};


Every RDR packet has the following format (RDRHeader format is unknown to me):
struct RDRPacket {
RDRHeader header; // sizeof(RDRHeader) == 20?
u32 tag; // Transaction usage, Subscriber, etc.
u8 fieldsNb; // Number of fields following (25 for TUR, 12 for SUR, etc.)
RDRField *fields;
};


For example, STRING field format is this:
struct STRING {
u8 type; // 0x29
u32 length;
char *str;
};

PACKAGE_ID:
struct PACKAGE_ID {
u8 type;
u32 size;
u16 value;
};

SERVICE_ID:
struct SERVICE_ID {
u8 type;
u32 size;
s32 value;
};

And so on.
Type and size are useful probably only for STRING fields to determine their lengths. Other fields don't need them really.
Note that most signed and unsigned 32-bit integers are in big endian (for example, a field's u32 size).