From acc644b7c8c57284e45b4b61c3d571a2e0493642 Mon Sep 17 00:00:00 2001 From: zhang_taibin Date: Wed, 21 May 2025 13:59:48 +0800 Subject: [PATCH] Add support for EtherType double VLAN (QinQ). --- .../java/io/pkts/framer/EthernetFramer.java | 9 +++- .../io/pkts/packet/impl/MACPacketImpl.java | 22 ++++---- pkts-core/src/test/java/io/pkts/VLANTest.java | 50 ++++++++++++++++++ .../resources/io/pkts/event_waf_152197.pcap | Bin 0 -> 787 bytes 4 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 pkts-core/src/test/java/io/pkts/VLANTest.java create mode 100644 pkts-core/src/test/resources/io/pkts/event_waf_152197.pcap diff --git a/pkts-core/src/main/java/io/pkts/framer/EthernetFramer.java b/pkts-core/src/main/java/io/pkts/framer/EthernetFramer.java index 9455243b..fc92919a 100644 --- a/pkts-core/src/main/java/io/pkts/framer/EthernetFramer.java +++ b/pkts-core/src/main/java/io/pkts/framer/EthernetFramer.java @@ -52,8 +52,13 @@ public MACPacket frame(final PCapPacket parent, final Buffer buffer) throws IOEx try { EtherType etherType = getEtherType(buffer.getByte(12), buffer.getByte(13)); if (etherType == EtherType.Dot1Q) { - getEtherType(buffer.getByte(16), buffer.getByte(17)); - headers = buffer.readBytes(18); + EtherType innerEtherType = getEtherType(buffer.getByte(16), buffer.getByte(17)); + // support QinQ + if (innerEtherType == EtherType.Dot1Q) { + headers = buffer.readBytes(22); + } else { + headers = buffer.readBytes(18); + } } else { headers = buffer.readBytes(14); } diff --git a/pkts-core/src/main/java/io/pkts/packet/impl/MACPacketImpl.java b/pkts-core/src/main/java/io/pkts/packet/impl/MACPacketImpl.java index 9123df02..69a9b591 100644 --- a/pkts-core/src/main/java/io/pkts/packet/impl/MACPacketImpl.java +++ b/pkts-core/src/main/java/io/pkts/packet/impl/MACPacketImpl.java @@ -9,10 +9,7 @@ import io.pkts.framer.EthernetFramer; import io.pkts.framer.IPv4Framer; import io.pkts.framer.IPv6Framer; -import io.pkts.packet.IPPacket; -import io.pkts.packet.MACPacket; -import io.pkts.packet.PCapPacket; -import io.pkts.packet.PacketParseException; +import io.pkts.packet.*; import io.pkts.protocol.Protocol; import java.io.IOException; @@ -199,16 +196,17 @@ public Protocol getNextProtocol() throws IOException { } catch (UnknownEtherType e) { throw new PacketParseException(12, String.format("Unknown Ethernet type 0x%02x%02x", e.getB1(), e.getB2())); } - if (etherType == EthernetFramer.EtherType.Dot1Q) { - try { - etherType = EthernetFramer.getEtherType(headers.getByte(16), headers.getByte(17)); - } catch (UnknownEtherType e) { - throw new PacketParseException(16, String.format("Unknown Ethernet type 0x%02x%02x", e.getB1(), e.getB2())); - } catch (IndexOutOfBoundsException e) { - throw new PacketParseException(14, "Not enough bytes in this header"); + for (int i = 0; i < 2; i++) { + if (etherType == EthernetFramer.EtherType.Dot1Q) { + try { + etherType = EthernetFramer.getEtherType(headers.getByte(16 + i * 4), headers.getByte(17 + i * 4)); + } catch (UnknownEtherType e) { + throw new PacketParseException(16 + i * 4, String.format("Unknown Ethernet type 0x%02x%02x", e.getB1(), e.getB2())); + } catch (IndexOutOfBoundsException e) { + throw new PacketParseException(14, "Not enough bytes in this header"); + } } } - switch (etherType) { case IPv4: return Protocol.IPv4; diff --git a/pkts-core/src/test/java/io/pkts/VLANTest.java b/pkts-core/src/test/java/io/pkts/VLANTest.java new file mode 100644 index 00000000..29d5ae4b --- /dev/null +++ b/pkts-core/src/test/java/io/pkts/VLANTest.java @@ -0,0 +1,50 @@ +package io.pkts; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import io.pkts.packet.Packet; +import io.pkts.packet.TCPPacket; +import io.pkts.packet.sip.SipPacket; +import io.pkts.protocol.Protocol; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class VLANTest extends PktsTestBase { + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @Override + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + // test QinQ packet + @Test + public void testLoop() throws Exception { + final InputStream stream = PktsTestBase.class.getResourceAsStream("event_waf_152197.pcap"); + final Pcap pcap = Pcap.openStream(stream); + pcap.loop(packet -> { + while (true) { + packet = packet.getNextPacket(); + if (packet == null) { + break; + } + } + return true; + }); + pcap.close(); + } + +} diff --git a/pkts-core/src/test/resources/io/pkts/event_waf_152197.pcap b/pkts-core/src/test/resources/io/pkts/event_waf_152197.pcap new file mode 100644 index 0000000000000000000000000000000000000000..22e8c39908edb950d39d0f313e179e87c42a8074 GIT binary patch literal 787 zcmZvZ&x_MQ6vwBlEHx0_lPn%|j&`+~ravs3#=2G4U3Dwf&5AcklV=k)$%M(YwO-sk z3EmVz@T49TL=gH92)eK!=*1q?vx0c`zRvUqRxmJ0-ur%e^WNtT-uIu)p#5m_?Cl|x z62VsbLn~ZAh>9YR=h1=BbKkDs@Pii*Gu!CU^KFEbG+IWfqx+gmC_B4&e%#c%^R1Q6esIXRTf=%p7iWB2oPn)*xze z&%k=2JWNL5aGyp7-UNuVcHno!Rcq7{+mTtxEE(@&8rpw1FKL