Removed static IP_HEADER_OFFSET cmake option

Previous versions of VERMONT required a proper compile time option
that tells VERMONT about the size of the layer 2 headers.
This means that VERMONT needed to be recompiled if it was
compiled with the default option and needed to be run on ethernet
traffic with VLAN tags.
The current commit enables dynamic detection of the pcap link type
(Ethernet, BSD loopback, ...) and adopts the IP header offset
accordingly.
Furthermore, the code checks for ethernet VLAN tags for each
packet. This allows to analyze traffic that mixes VLAN-tagged
and untagged traffic.
master
Lothar Braun 2013-01-30 17:13:59 +01:00
parent c2f170a89a
commit cd19757bb4
7 changed files with 52 additions and 100 deletions

View File

@ -231,12 +231,6 @@ ELSE (DEBUG)
ENDIF (DEBUG)
### IP_HEADER_OFFSET
SET(IP_HEADER_OFFSET 14 CACHE STRING "Start position of the IP header in an ethernet frame in Bytes. This value needs to be adjusted according to the network monitored. The default value is 14 for ethernet devices. Other common values are 4 (BSD loop back device) and 18 (Ethernet VLAN)")
ADD_DEFINITIONS(-DIP_HEADER_OFFSET=${IP_HEADER_OFFSET})
### PCAP_MAX_CAPTURE_LENGTH
SET(PCAP_MAX_CAPTURE_LENGTH 128 CACHE STRING "Maximum PCAP packet capture length (this amount of bytes is always allocated for each packet, the smaller the better!)")

View File

@ -116,7 +116,8 @@ void FpaPacketGenerator::onDataRecord(IpfixDataRecord* record)
tv.tv_sec = c.srcTimeEnd/1000;
tv.tv_usec = (c.srcTimeEnd%1000)*1000;
Packet* p = packetManager.getNewInstance();
p->init(tcpDataSegments, tcpSegmentLengths, tv, 0, totlen);
// tcpheader contains a standard 14 bytes ethernet header (see FpaPacketGenerator.h)
p->init(tcpDataSegments, tcpSegmentLengths, tv, 0, totlen, 14);
send(p);
}
totlen = sizeof(tcpHeader)+c.dstPayloadLen;
@ -133,7 +134,8 @@ void FpaPacketGenerator::onDataRecord(IpfixDataRecord* record)
tv.tv_sec = c.dstTimeEnd/1000;
tv.tv_usec = (c.dstTimeEnd%1000)*1000;
Packet* p = packetManager.getNewInstance();
p->init(tcpDataSegments, tcpSegmentLengths, tv, 0, totlen);
// tcpheader contains a standard 14 bytes ethernet header (see FpaPacketGenerator.h)
p->init(tcpDataSegments, tcpSegmentLengths, tv, 0, totlen, 14);
send(p);
}
} else if (c.protocol==17) {
@ -152,7 +154,8 @@ void FpaPacketGenerator::onDataRecord(IpfixDataRecord* record)
tv.tv_sec = c.srcTimeEnd/1000;
tv.tv_usec = (c.srcTimeEnd%1000)*1000;
Packet* p = packetManager.getNewInstance();
p->init(udpDataSegments, udpSegmentLengths, tv, 0, totlen);
// udpheader contains a standard 14 bytes ethernet header (see FpaPacketGenerator.h)
p->init(udpDataSegments, udpSegmentLengths, tv, 0, totlen, 14);
send(p);
}
totlen = sizeof(udpHeader)+c.dstPayloadLen;
@ -170,7 +173,8 @@ void FpaPacketGenerator::onDataRecord(IpfixDataRecord* record)
tv.tv_sec = c.dstTimeEnd/1000;
tv.tv_usec = (c.dstTimeEnd%1000)*1000;
Packet* p = packetManager.getNewInstance();
p->init(udpDataSegments, udpSegmentLengths, tv, 0, totlen);
// udpheader contains a standard 14 bytes ethernet header (see FpaPacketGenerator.h)
p->init(udpDataSegments, udpSegmentLengths, tv, 0, totlen, 14);
send(p);
}

View File

@ -153,9 +153,7 @@ void *Observer::observerThread(void *arg)
struct pcap_pkthdr packetHeader;
bool have_send = false;
obs->registerCurrentThread();
bool file_eof = false;
bool file_eof = false;
msg(MSG_INFO, "Observer started with following parameters:");
msg(MSG_INFO, " - readFromFile=%d", obs->readFromFile);
@ -164,6 +162,7 @@ void *Observer::observerThread(void *arg)
msg(MSG_INFO, " - filterString='%s'", (obs->filter_exp ? obs->filter_exp : "none"));
msg(MSG_INFO, " - maxPackets=%u", obs->maxPackets);
msg(MSG_INFO, " - capturelen=%d", obs->capturelen);
msg(MSG_INFO, " - dataLinkType=%d", obs->dataLinkType);
if (obs->readFromFile) {
msg(MSG_INFO, " - autoExit=%d", obs->autoExit);
msg(MSG_INFO, " - stretchTime=%f", obs->stretchTime);
@ -216,7 +215,7 @@ void *Observer::observerThread(void *arg)
// initialize packet structure (init copies packet data)
p = packetManager.getNewInstance();
p->init((char*)pcapData, packetHeader.caplen, packetHeader.ts, obs->observationDomainID, packetHeader.len);
p->init((char*)pcapData, packetHeader.caplen, packetHeader.ts, obs->observationDomainID, packetHeader.len, obs->dataLinkType);
DPRINTF("received packet at %u.%04u, len=%d",
(unsigned)p->timestamp.tv_sec,
@ -312,7 +311,7 @@ void *Observer::observerThread(void *arg)
// in contrast to live capturing, the data length is not limited
// to any snap length when reading from a pcap file
(packetHeader.caplen < obs->capturelen) ? packetHeader.caplen : obs->capturelen,
packetHeader.ts, obs->observationDomainID, packetHeader.len);
packetHeader.ts, obs->observationDomainID, packetHeader.len, obs->dataLinkType);
DPRINTF("received packet at %u.%03u, len=%d",
@ -393,31 +392,6 @@ bool Observer::prepare(const std::string& filter)
goto out2;
}
// IP_HEADER_OFFSET is set by the configure script
switch (getDataLinkType()) {
case DLT_EN10MB:
if (IP_HEADER_OFFSET != 14 && IP_HEADER_OFFSET != 18) {
msg(MSG_FATAL, "IP_HEADER_OFFSET on an ethernet device has to be 14 or 18 Bytes. Please adjust that value via configure --with-ipheader-offset");
goto out2;
}
break;
case DLT_LOOP:
case DLT_NULL:
if (IP_HEADER_OFFSET != 4) {
msg(MSG_FATAL, "IP_HEADER_OFFSET on BSD loop back device has to be 4 Bytes. Please adjust that value via configure --with-ipheader-offset");
goto out2;
}
break;
case DLT_LINUX_SLL:
if (IP_HEADER_OFFSET != 16) {
msg(MSG_FATAL, "IP_HEADER_OFFSET on linux cooked devices has to be 16 Bytes. Please adjust that value via configure --with-ipheader-offset");
goto out2;
}
default:
msg(MSG_ERROR, "You are using an unkown IP_HEADER_OFFSET and data link combination. This can make problems. Please check if you use the correct IP_HEADER_OFFSET for your data link, if you see strange IPFIX/PSAMP packets.");
}
/* we need the netmask for the pcap_compile */
if(pcap_lookupnet(captureInterface, &network, &netmask, errorBuffer) == -1) {
msg(MSG_ERROR, "unable to determine netmask/network: %s", errorBuffer);
@ -439,6 +413,7 @@ bool Observer::prepare(const std::string& filter)
netmask=0;
}
dataLinkType = pcap_datalink(captureDevice);
if (filter_exp) {
msg(MSG_DEBUG, "compiling pcap filter code from: %s", filter_exp);
@ -533,11 +508,6 @@ int Observer::getCaptureLen()
return capturelen;
}
int Observer::getDataLinkType()
{
return pcap_datalink(captureDevice);
}
void Observer::replaceOfflineTimestamps()
{
replaceTimestampsFromFile = true;

View File

@ -58,7 +58,6 @@ public:
bool prepare(const std::string& filter);
static void doLogging(void *arg);
virtual std::string getStatisticsXML(double interval);
int getDataLinkType();
protected:
@ -132,6 +131,8 @@ protected:
uint32_t statTotalRecvPackets;
static void *observerThread(void *);
int dataLinkType; // contains the datalink type of the capturing device
};
#endif

View File

@ -24,6 +24,7 @@
#include <cstring>
#include <stdint.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include <sys/time.h>
#include "common/msg.h"
@ -32,6 +33,8 @@
#include "common/ManagedInstance.h"
#include "common/ipfixlolib/encoding.h"
#include <pcap.h>
#include "core/Emitable.h"
// the various header types (actually, HEAD_PAYLOAD is not neccessarily a header but it works like one for
@ -78,13 +81,6 @@
class Packet : public ManagedInstance<Packet>, public Emitable
{
public:
/*
the raw offset at which the IP header starts in the packet
for Ethernet, this is 14 bytes (MAC header size).
This constant is set via the configure script. It defaults to 14
*/
static const int IPHeaderOffset=IP_HEADER_OFFSET;
// Transport header classifications (used in Packet::ipProtocolType)
// Note: ALL is reserved and enables bitoperations using the enums
enum IPProtocolType { NONE=0x00, TCP=0x01, UDP=0x02, ICMP=0x04, IGMP=0x08, ALL=0xFF };
@ -137,55 +133,19 @@ public:
Packet(InstanceManager<Packet>* im)
: ManagedInstance<Packet>(im),
zeroBytes(0),
netHeader(data + IPHeaderOffset), // netHeader must not be changed afterwards
netHeaderOffset(IPHeaderOffset)
zeroBytes(0)
{
}
Packet()
: ManagedInstance<Packet>(0),
netHeader(data + IPHeaderOffset),
netHeaderOffset(IPHeaderOffset)
: ManagedInstance<Packet>(0)
{
}
/*
void copyPacket(Packet* other)
{
observationDomainID = other->observationDomainID;
memcpy(&data, &other->data, PCAP_MAX_CAPTURE_LENGTH);
netHeader = other->netHeader;
transportHeader = other->transportHeader;
payload = other->payload;
zeroBytes = other->zeroBytes;
netHeaderOffset = other->netHeaderOffset;
transportHeaderOffset = other->transportHeaderOffset;
payloadOffset = other->payloadOffset;
classification = other->classification;
ipProtocolType = other->ipProtocolType;
data_length = other->data_length;
pcapPacketLength = other->pcapPacketLength;
timestamp = other->timestamp;
time_sec_nbo = other->time_sec_nbo;
time_usec_nbo = other->time_usec_nbo;
time_msec_nbo = other->time_msec_nbo;
memcpy(&varlength, &other->varlength, sizeof(varlength));
varlength_index = other->varlength_index;
}
*/
/**
* @param origplen original packet length
*/
inline void init(char* packetData, int len, struct timeval time, uint32_t obsdomainid, uint32_t origplen)
inline void init(char* packetData, int len, struct timeval time, uint32_t obsdomainid, uint32_t origplen, int dataLinkType)
{
transportHeader = NULL;
payload = NULL;
@ -217,10 +177,10 @@ public:
totalPacketsReceived++;
classify();
classify(dataLinkType);
};
inline void init(char** datasegments, uint32_t* segmentlens, struct timeval time, uint32_t obsdomainid, uint32_t origplen)
inline void init(char** datasegments, uint32_t* segmentlens, struct timeval time, uint32_t obsdomainid, uint32_t origplen, int dataLinkType)
{
transportHeader = NULL;
payload = NULL;
@ -233,8 +193,6 @@ public:
observationDomainID = obsdomainid;
pcapPacketLength = origplen;
data_length = 0;
for (uint32_t i=0; datasegments[i]!=0; i++) {
if (data_length+segmentlens[i] > PCAP_MAX_CAPTURE_LENGTH) {
@ -256,7 +214,7 @@ public:
totalPacketsReceived++;
classify();
classify(dataLinkType);
};
// Delete the packet and free all data associated with it.
@ -265,10 +223,35 @@ public:
}
// classify the packet headers
void classify()
void classify(int dataLinkType)
{
unsigned char protocol = 0;
// get netheader
switch (dataLinkType) {
case DLT_EN10MB: {
// 14 oder 18
// check if we have a vlan on the data link layer.
uint16_t et = ntohs(((struct ether_header*)data)->ether_type);
netHeaderOffset = 14 + ((et == ETHERTYPE_VLAN)?4:0);
break;
}
case DLT_LOOP:
case DLT_NULL: {
netHeaderOffset = 4;
break;
}
case DLT_LINUX_SLL:{
netHeaderOffset = 16;
break;
}
default:
msg(MSG_ERROR, "Received packet on not supported link layer \"%u\". Assuming that no layer 2 header exists. This will probably fail!", dataLinkType);
netHeaderOffset = 0;
}
netHeader = data + netHeaderOffset;
// first check for IPv4 header which needs to be at least 20 bytes long
if ( (netHeader + 20 <= data + data_length) && ((*netHeader >> 4) == 4) )
{

View File

@ -146,7 +146,7 @@ void AggregationPerfTest::sendPacketsTo(Destination<Packet*>* dest, uint32_t num
for (size_t i = 0; i < numpackets; i++) {
Packet* packet = packetManager.getNewInstance();
packet->init((char*)packetdata, packetdatalen, curtime, 0, packetdatalen);
packet->init((char*)packetdata, packetdatalen, curtime, 0, packetdatalen, 14);
dest->receive(packet);
}
}

View File

@ -43,7 +43,7 @@ void ReconfTest::sendPacketsTo(Destination<Packet*>* dest, size_t numpackets)
for (size_t i = 0; i < numpackets; i++) {
Packet* packet = packetManager.getNewInstance();
packet->init((char*)packetdata, packetdatalen, curtime, 0, packetdatalen);
packet->init((char*)packetdata, packetdatalen, curtime, 0, packetdatalen, 14);
dest->receive(packet);
}
}