//////////////////////////////////////////////////// // handle a new packet on the stream void EQPacketStream::handlePacket(EQUDPIPPacketFormat& packet) { emit numPacket(++m_packetCount, (int)m_streamid); // Only accept packets if we've been initialized unless they are // initialization packets! if (packet.getNetOpCode() != OP_SessionRequest && packet.getNetOpCode() != OP_SessionResponse && ! m_sessionKey) { #if (defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)) || defined(PACKET_SESSION_DIAG) seqDebug("discarding packet %s:%d ==>%s:%d netopcode=%04x size=%d. Session not initialized. Need to zone to start picking up packets. Session tracking %s.", (const char*)packet.getIPv4SourceA(), packet.getSourcePort(), (const char*)packet.getIPv4DestA(), packet.getDestPort(), packet.getNetOpCode(), packet.payloadLength(), (m_session_tracking_enabled == 2 ? "locked on" : (m_session_tracking_enabled == 1 ? "enabled" : "disabled"))); #endif return; } emit rawPacket(packet.payload(), packet.payloadLength(), m_dir, packet.getNetOpCode()); processPacket(packet, false); // false = isn't subpacket // if the cache isn't empty, then process it. if (!m_cache.empty()) processCache(); }
void* PfRingDevice::captureThreadMain(void *ptr) { PfRingDevice* device = (PfRingDevice*)ptr; int coreId = device->getCurrentCoreId().Id; pfring* ring = NULL; LOG_DEBUG("Starting capture thread %d", coreId); ring = device->m_CoreConfiguration[coreId].Channel; if (ring == NULL) { LOG_ERROR("Couldn't find ring for core %d. Exiting capture thread", coreId); return (void*)NULL; } while (!device->m_StopThread) { // if buffer is NULL PF_RING avoids copy of the data uint8_t* buffer = NULL; uint32_t bufferLen = 0; // in multi-threaded mode flag PF_RING_REENTRANT is set, and this flag doesn't work with zero copy // so I need to allocate a buffer and set buffer to point to it if (device->m_ReentrantMode) { uint8_t tempBuffer[MAX_PACKET_SIZE]; buffer = tempBuffer; bufferLen = MAX_PACKET_SIZE; } struct pfring_pkthdr pktHdr; int recvRes = pfring_recv(ring, &buffer, bufferLen, &pktHdr, 0); if (recvRes > 0) { // if caplen < len it means we don't have the whole packet. Treat this case as packet drop // TODO: add this packet to dropped packet stats // if (pktHdr.caplen != pktHdr.len) // { // LOG_ERROR("Packet dropped due to len != caplen"); // continue; // } RawPacket rawPacket(buffer, pktHdr.caplen, pktHdr.ts, false); device->m_OnPacketsArriveCallback(&rawPacket, 1, coreId, device, device->m_OnPacketsArriveUserCookie); } else if (recvRes < 0) { LOG_ERROR("pfring_recv returned an error: [Err=%d]", recvRes); } } LOG_DEBUG("Exiting capture thread %d", coreId); return (void*)NULL; }
void PcapLiveDevice::onPacketArrives(uint8_t *user, const struct pcap_pkthdr *pkthdr, const uint8_t *packet) { PcapLiveDevice* pThis = (PcapLiveDevice*)user; if (pThis == NULL) { LOG_ERROR("Unable to extract PcapLiveDevice instance"); return; } RawPacket rawPacket(packet, pkthdr->caplen, pkthdr->ts, false); if (pThis->m_cbOnPacketArrives != NULL) pThis->m_cbOnPacketArrives(&rawPacket, pThis, pThis->m_cbOnPacketArrivesUserCookie); }
//////////////////////////////////////////////////// // handle a new packet on the stream void EQPacketStream::handlePacket(EQUDPIPPacketFormat& packet) { emit numPacket(++m_packetCount, (int)m_streamid); // Only accept packets if we've been initialized unless they are // initialization packets! if (packet.getNetOpCode() != OP_SessionRequest && packet.getNetOpCode() != OP_SessionResponse && ! m_sessionKey) { #if (defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)) || (defined(PACKET_SESSION_DIAG) && PACKET_SESSION_DIAG > 1) seqDebug("discarding packet %s:%d ==>%s:%d netopcode=%04x size=%d. Session not initialized. Need to zone to start picking up packets. Session tracking %s.", (const char*)packet.getIPv4SourceA(), packet.getSourcePort(), (const char*)packet.getIPv4DestA(), packet.getDestPort(), packet.getNetOpCode(), packet.payloadLength(), (m_session_tracking_enabled == 2 ? "locked on" : (m_session_tracking_enabled == 1 ? "enabled" : "disabled"))); #endif return; } // Decode the packet first if (! packet.decode(m_maxLength)) { seqWarn("Packet decode failed for stream %s (%d), op %04x, flags %02x packet dropped.", EQStreamStr[m_streamid], m_streamid, packet.getNetOpCode(), packet.getFlags()); return; } #ifdef PACKET_DECODE_DIAG else if (packet.hasFlags()) { seqDebug("Successful decode for stream %s (%d), op %04x, flags %02x.", EQStreamStr[m_streamid], m_streamid, packet.getNetOpCode(), packet.getFlags()); } #endif // Raw packet emit rawPacket(packet.rawPayload(), packet.rawPayloadLength(), m_dir, packet.getNetOpCode()); processPacket(packet, false); // false = isn't subpacket // if the cache isn't empty, then process it. if (!m_cache.empty()) processCache(); }
//////////////////////////////////////////////////// // process the packets payload, decoding if necessary void EQPacketStream::processPayload(uint8_t* data, size_t len) { uint16_t opCode = *(uint16_t*)data; data += 2; len -= 2; if (opCode & FLAG_DECODE) decodePacket(data, len, opCode); else { emit rawPacket(data, len, m_dir, opCode); dispatchPacket(data, len, opCode, m_opcodeDB.find(opCode)); } }
//////////////////////////////////////////////////// // handle a new packet on the stream void EQPacketStream::handlePacket(EQUDPIPPacketFormat& packet) { emit numPacket(++m_packetCount, (int)m_streamid); // Packet is ours now. Logging needs to know this later on. packet.setSessionKey(getSessionKey()); // Only accept packets if we've been initialized unless they are // initialization packets! if (packet.getNetOpCode() != OP_SessionRequest && packet.getNetOpCode() != OP_SessionResponse && ! m_sessionKey) { #if (defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)) || (defined(PACKET_SESSION_DIAG) && PACKET_SESSION_DIAG > 1) seqDebug("discarding packet %s:%d ==>%s:%d netopcode=%04x size=%d. Session not initialized. Need to zone to start picking up packets. Session tracking %s.", (const char*)packet.getIPv4SourceA(), packet.getSourcePort(), (const char*)packet.getIPv4DestA(), packet.getDestPort(), packet.getNetOpCode(), packet.payloadLength(), (m_session_tracking_enabled == 2 ? "locked on" : (m_session_tracking_enabled == 1 ? "enabled" : "disabled"))); #endif return; } // Only accept packets that correspond to our latched client port, if // it is set. This helps filter out multiple sessions on the same physical // host when two eq clients zone at the same time. The first one will win. if (m_sessionClientPort != 0 && ((dir() == DIR_Server && m_sessionClientPort != packet.getDestPort()) || (dir() == DIR_Client && m_sessionClientPort != packet.getSourcePort()))) { #if (defined(PACKET_PROCESS_DIAG) && (PACKET_PROCESS_DIAG > 1)) || (defined(PACKET_SESSION_DIAG) && PACKET_SESSION_DIAG > 1) seqDebug("discarding packet %s:%d ==>%s:%d netopcode=%04x size=%d. Multiple sessions on the same box? Ignoring all but one of them. Latched client port %d. Session tracking %s.", (const char*)packet.getIPv4SourceA(), packet.getSourcePort(), (const char*)packet.getIPv4DestA(), packet.getDestPort(), packet.getNetOpCode(), packet.payloadLength(), m_sessionClientPort, (m_session_tracking_enabled == 2 ? "locked on" : (m_session_tracking_enabled == 1 ? "enabled" : "disabled"))); #endif return; } // Only accept packets that pass the EQ protocol-level CRC check. This helps // weed out non-EQ packets that we might see. #ifdef APPLY_CRC_CHECK if (packet.hasCRC()) { uint16_t calcedCRC = calculateCRC(packet); if (calcedCRC != packet.crc()) { seqWarn("INVALID PACKET: Bad CRC [%s:%d -> %s:%d] netOp %04x seq %04x len %d crc (%04x != %04x)", (const char*)packet.getIPv4SourceA(), packet.getSourcePort(), (const char*)packet.getIPv4DestA(), packet.getDestPort(), packet.getNetOpCode(), packet.arqSeq(), packet.getUDPPayloadLength(), packet.crc(), calcedCRC); return; } } #endif /* APPLY_CRC_CHECK */ // Decode the packet first if (! packet.decode(m_maxLength)) { seqWarn("Packet decode failed for stream %s (%d), op %04x, flags %02x packet dropped.", EQStreamStr[m_streamid], m_streamid, packet.getNetOpCode(), packet.getFlags()); return; } #ifdef PACKET_DECODE_DIAG else if (packet.hasFlags()) { seqDebug("Successful decode for stream %s (%d), op %04x, flags %02x.", EQStreamStr[m_streamid], m_streamid, packet.getNetOpCode(), packet.getFlags()); } #endif // Raw packet emit rawPacket(packet.rawPayload(), packet.rawPayloadLength(), m_dir, packet.getNetOpCode()); processPacket(packet, false); // false = isn't subpacket // if the cache isn't empty, then process it. if (!m_cache.empty()) processCache(); }
//////////////////////////////////////////////////// // decode, decrypt, and unroll packet void EQPacketStream::decodePacket(uint8_t *data, size_t len, uint16_t opCode) { emit rawPacket(data, len, m_dir, opCode); if (opCode & FLAG_CRYPTO || opCode & FLAG_COMP) { data = decodeOpCode (data, &len, opCode); if (data == NULL) return; emit rawPacket(data, len, m_dir, opCode); } const EQPacketOPCode* opcodeEntry = 0; // this works, but could really use a cleanup - mvern while (len > 2) { if (opCode & FLAG_COMBINED) { bool repeatop = false; uint8_t *dptr = data; size_t left = len; int32_t count = 1; if (opCode & FLAG_IMPLICIT) { opCode = opCode & ~FLAG_IMPLICIT; repeatop = true; } #ifdef PACKET_DECODE_DIAG seqDebug("unrolling on %s: 0x%04x", EQStreamStr[m_streamid], opCode); #endif opCode = opCode & ~FLAG_COMBINED; while (count > 0) { uint16_t size = 0; opcodeEntry = m_opcodeDB.find(opCode); if (opcodeEntry) { size = opcodeEntry->implicitLen(); #ifdef PACKET_DECODE_DIAG // ZBTEMP seqDebug("opcode %04x implicitlen %d", opCode, size); #endif } #ifdef PACKET_DECODE_DIAG else seqDebug("No opcodeEntry for %04x", opCode); #endif if (size == 0) { // Not an implicit length opcode if (dptr[0] == 0xff) { // > 255 length left--; dptr++; size = ntohs(*((uint16_t *)dptr)); left -= 2; dptr += 2; } else { // single octet length size = dptr[0]; left--; dptr++; } } #ifdef PACKET_DECODE_DIAG seqDebug ("size on %s: %d", EQStreamStr[m_streamid], size); #endif if (size > left) { seqWarn("error on %s: size > left (size=%d, left=%d, opcode=0x%04x)", EQStreamStr[m_streamid], size, left, opCode); return; } #ifdef PACKET_DECODE_DIAG seqDebug("sending from %s: 0x%04x, %d", EQStreamStr[m_streamid], opCode, size); #endif dispatchPacket(dptr, size, opCode, opcodeEntry); // next dptr += size; left -= size; count--; if (repeatop) { count = dptr[0]; dptr++; left--; repeatop = false; #ifdef PACKET_DECODE_DIAG seqDebug ("repeating %d times on %s", count, EQStreamStr[m_streamid]); #endif } } if (left > 2) { opCode = *((unsigned short *)dptr); dptr += 2; left -= 2; #ifdef PACKET_DECODE_DIAG seqDebug("doing leftover from %s: 0x%04x, %d", EQStreamStr[m_streamid], opCode, left); #endif if (opCode & FLAG_COMBINED) { data = dptr; len = left; continue; } else { #ifdef PACKET_DECODE_DIAG seqDebug("sending from %s: 0x%04x, %d", EQStreamStr[m_streamid], opCode, size); #endif dispatchPacket(dptr, left, opCode, m_opcodeDB.find(opCode)); } } return; } else break; } #ifdef PACKET_DECODE_DIAG seqDebug ("sending from %s: 0x%04x, %d", EQStreamStr[m_streamid], opCode, size); #endif dispatchPacket(data, len, opCode, m_opcodeDB.find(opCode)); }