// See the file "COPYING" in the main distribution directory for copyright.

#include "zeek/packet_analysis/protocol/nflog/NFLog.h"

using namespace zeek::packet_analysis::NFLog;

NFLogAnalyzer::NFLogAnalyzer() : zeek::packet_analysis::Analyzer("NFLog") { }

bool NFLogAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* packet)
	{
	if ( 4 >= len )
		{
		Weird("truncated_nflog_header", packet);
		return false;
		}

	// See https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
	uint32_t protocol = data[0];
	uint8_t version = data[1];

	if ( version != 0 )
		{
		Weird("unknown_nflog_version", packet);
		return false;
		}

	// Skip to TLVs.
	data += 4;
	len -= 4;

	uint16_t tlv_len;
	uint16_t tlv_type;

	while ( true )
		{
		if ( 4 >= len )
			{
			Weird("nflog_no_pcap_payload", packet);
			return false;
			}

		// TLV Type and Length values are specified in host byte order
		// (libpcap should have done any needed byteswapping already).

		tlv_len = *(reinterpret_cast<const uint16_t*>(data));
		tlv_type = *(reinterpret_cast<const uint16_t*>(data + 2));

		auto constexpr nflog_type_payload = 9;

		if ( tlv_type == nflog_type_payload )
			{
			// The raw packet payload follows this TLV.
			data += 4;
			len -= 4;
			break;
			}
		else
			{
			// The Length value includes the 4 octets for the Type and
			// Length values, but TLVs are also implicitly padded to
			// 32-bit alignments (that padding may not be included in
			// the Length value).

			if ( tlv_len < 4 )
				{
				Weird("nflog_bad_tlv_len", packet);
				return false;
				}
			else
				{
				auto rem = tlv_len % 4;

				if ( rem != 0 )
					tlv_len += 4 - rem;
				}

			data += tlv_len;
			len -= tlv_len;
			}
		}

	return ForwardPacket(len, data, packet, protocol);
	}
