From a925a3a416e7006df2a69f863e950a466f6a2341 Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Sun, 17 May 2026 21:25:12 +0200 Subject: [PATCH] Added support for LLC/SNAP inside MPE packets. --- .../MultiprotocolEncapsulationDecoder.cs | 18 ++- .../MultiprotocolEncapsulationEventHandler.cs | 5 + skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs | 5 + .../Ietf/Rfc4236_ULE/UleEventHandler.cs | 2 +- .../Ietf/Rfc4236_ULE/UlePacketProcessor.cs | 2 +- skyscraper8/Properties/launchSettings.json | 2 +- skyscraper8/Skyscraper/IO/StreamExtensions.cs | 9 ++ .../Skyscraper/Net/IpTrafficHandler.cs | 4 +- .../Skyscraper/Net/NullIpTrafficHandler.cs | 8 +- .../Net/Pcap/PcapIpTrafficHandler.cs | 109 ++++++++++++++---- .../Skyscraper/Net/Pcap/TcpdumpNetworkType.cs | 1 + .../Skyscraper/Scraper/SkyscraperContext.cs | 37 +++++- .../Skyscraper/Scraper/SkyscraperUiFeature.cs | 3 +- .../Contestants/MpeContestant.cs | 7 ++ skyscraper8/bin/Debug/skyscraper5.ini | 2 +- 15 files changed, 178 insertions(+), 36 deletions(-) diff --git a/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationDecoder.cs b/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationDecoder.cs index c42e2b0..fffc4e7 100644 --- a/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationDecoder.cs +++ b/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationDecoder.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; +using log4net; using skyscraper5.Ietf.Rfc768; using skyscraper5.Mpeg2; using skyscraper5.Skyscraper.IO; @@ -13,7 +14,9 @@ namespace skyscraper5.Dvb.DataBroadcasting { class MultiprotocolEncapsulationDecoder : IPsiProcessor { - public IMultiprotocolEncapsulationEventHandler EventHandler { get; } + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + public IMultiprotocolEncapsulationEventHandler EventHandler { get; } public MultiprotocolEncapsulationDecoder(IMultiprotocolEncapsulationEventHandler eventHandler) { @@ -59,7 +62,7 @@ namespace skyscraper5.Dvb.DataBroadcasting byte[] payload = ms.ReadBytes(length); if (llcSnap) { - HandleLlcSnap(sourcePid,payload); + HandleLlcSnap(sourcePid, macAddress, payload); } else { @@ -68,8 +71,17 @@ namespace skyscraper5.Dvb.DataBroadcasting } - private void HandleLlcSnap(int sourcePid, byte[] payload) + private bool announcedLlcTraffic; + private void HandleLlcSnap(int sourcePid, byte[] macAddress, byte[] payload) { + if (!announcedLlcTraffic) + { + logger.InfoFormat("Detected LLC/SNAP traffic on PID {0:x4}", sourcePid); + announcedLlcTraffic = true; + } + + PhysicalAddress physicalAddress = new PhysicalAddress(macAddress); + EventHandler.OnLlcFrame((ushort)sourcePid, PhysicalAddress.None, physicalAddress, (ushort)payload.Length, payload); } private void HandleIpDatagram(int sourcePid, byte[] payload) diff --git a/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationEventHandler.cs b/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationEventHandler.cs index 09fb4cb..12c9a17 100644 --- a/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationEventHandler.cs +++ b/skyscraper8/Dvb/DataBroadcasting/MultiprotocolEncapsulationEventHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; using skyscraper5.Ietf.Rfc971; @@ -11,5 +12,9 @@ namespace skyscraper5.Dvb.DataBroadcasting { void OnIpv4PacketArrival(InternetHeader internetHeader, byte[] ipv4Packet); void OnIpDatagram(int sourcePid, byte[] payload); + + void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents); + + } } diff --git a/skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs b/skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs index e99e361..f1d998a 100644 --- a/skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs +++ b/skyscraper8/Ietf/Rfc4236_ULE/UleContestant.cs @@ -38,6 +38,11 @@ namespace skyscraper8.Ietf.Rfc4236_ULE Score++; } + public void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents) + { + Score++; + } + public void OnUleError(int pid, int errorNo) { Score--; diff --git a/skyscraper8/Ietf/Rfc4236_ULE/UleEventHandler.cs b/skyscraper8/Ietf/Rfc4236_ULE/UleEventHandler.cs index e746118..874545a 100644 --- a/skyscraper8/Ietf/Rfc4236_ULE/UleEventHandler.cs +++ b/skyscraper8/Ietf/Rfc4236_ULE/UleEventHandler.cs @@ -9,7 +9,7 @@ namespace skyscraper8.Ietf.Rfc4236_ULE { internal interface UleEventHandler { - void OnEthernetFrame(int pid, PhysicalAddress destination, PhysicalAddress source, ushort etherType, byte[] contents); + void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents); /// /// The UlePacketProcessor is supposed to call this whenever an Error occurs during deframing. diff --git a/skyscraper8/Ietf/Rfc4236_ULE/UlePacketProcessor.cs b/skyscraper8/Ietf/Rfc4236_ULE/UlePacketProcessor.cs index b621584..478efe8 100644 --- a/skyscraper8/Ietf/Rfc4236_ULE/UlePacketProcessor.cs +++ b/skyscraper8/Ietf/Rfc4236_ULE/UlePacketProcessor.cs @@ -202,7 +202,7 @@ namespace skyscraper8.Ietf.Rfc4236_ULE PhysicalAddress source = new PhysicalAddress(ms.ReadBytes(6)); ushort etherType = ms.ReadUInt16BE(); byte[] contents = ms.ReadBytes(ms.GetAvailableBytes()); - _eventHandler.OnEthernetFrame(_pid, destination, source, etherType, contents); + _eventHandler.OnLlcFrame((ushort)_pid, source, destination, etherType, contents); } public void PacketLoss() diff --git a/skyscraper8/Properties/launchSettings.json b/skyscraper8/Properties/launchSettings.json index b2d6d50..b9f7ec3 100644 --- a/skyscraper8/Properties/launchSettings.json +++ b/skyscraper8/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "skyscraper8": { "commandName": "Project", - "commandLineArgs": "salvage strat3 \"C:\\devel\\skyscraper8-testsuite\\105.5E_4169.263_H_5237_(2026-04-24 12.36.13)_dump.ts\"", + "commandLineArgs": "\"C:\\Users\\Sascha Schiemann\\Downloads\\65w_fix.ts\"", "remoteDebugEnabled": false }, "Container (Dockerfile)": { diff --git a/skyscraper8/Skyscraper/IO/StreamExtensions.cs b/skyscraper8/Skyscraper/IO/StreamExtensions.cs index 8a917d8..efc2743 100644 --- a/skyscraper8/Skyscraper/IO/StreamExtensions.cs +++ b/skyscraper8/Skyscraper/IO/StreamExtensions.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; using System.IO.Compression; +using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Text; @@ -423,5 +424,13 @@ namespace skyscraper5.Skyscraper.IO Array.Reverse(buffer); return BitConverter.ToSingle(buffer, 0); } + + public static PhysicalAddress ReadMacAddress(this Stream stream) + { + byte[] buffer = new byte[6]; + if (stream.Read(buffer, 0, 6) != 6) + throw new EndOfStreamException("failed to read mac address"); + return new PhysicalAddress(buffer); + } } } diff --git a/skyscraper8/Skyscraper/Net/IpTrafficHandler.cs b/skyscraper8/Skyscraper/Net/IpTrafficHandler.cs index 6346c9f..eb58c21 100644 --- a/skyscraper8/Skyscraper/Net/IpTrafficHandler.cs +++ b/skyscraper8/Skyscraper/Net/IpTrafficHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; @@ -8,6 +9,7 @@ namespace skyscraper8.Skyscraper.Net { internal interface IpTrafficHandler : IDisposable { - void HandlePacket(int pid, byte[] payload); + void HandleIpPacket(int pid, byte[] payload); + void HandleLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents); } } diff --git a/skyscraper8/Skyscraper/Net/NullIpTrafficHandler.cs b/skyscraper8/Skyscraper/Net/NullIpTrafficHandler.cs index 6b84024..45cb27a 100644 --- a/skyscraper8/Skyscraper/Net/NullIpTrafficHandler.cs +++ b/skyscraper8/Skyscraper/Net/NullIpTrafficHandler.cs @@ -4,6 +4,7 @@ using skyscraper8.Skyscraper.Scraper.Storage; using System; using System.Collections.Generic; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; @@ -19,7 +20,12 @@ namespace skyscraper8.Skyscraper.Net } - public void HandlePacket(int pid, byte[] payload) + public void HandleIpPacket(int pid, byte[] payload) + { + + } + + public void HandleLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents) { } diff --git a/skyscraper8/Skyscraper/Net/Pcap/PcapIpTrafficHandler.cs b/skyscraper8/Skyscraper/Net/Pcap/PcapIpTrafficHandler.cs index 8edc4b9..6b06458 100644 --- a/skyscraper8/Skyscraper/Net/Pcap/PcapIpTrafficHandler.cs +++ b/skyscraper8/Skyscraper/Net/Pcap/PcapIpTrafficHandler.cs @@ -6,6 +6,7 @@ using skyscraper8.Skyscraper.Scraper.Storage; using System; using System.Collections.Generic; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; @@ -17,26 +18,19 @@ namespace skyscraper8.Skyscraper.Net.Pcap internal class PcapIpTrafficHandler : IpTrafficHandler { private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); - private PcapWriter[] pcapWriters; + private PcapWriter[] pcapWritersIp; + private PcapWriter[] pcapWritersLlc; private DirectoryInfo outputDirectory; - public void HandlePacket(int pid, byte[] payload) + public void HandleIpPacket(int pid, byte[] payload) { - if (pcapWriters == null) + if (pcapWritersIp == null) { - pcapWriters = new PcapWriter[0x1fff]; - - PluginManager pluginManager = PluginManager.GetInstance(); - string outDirPath = pluginManager.Ini.ReadValue("pcapwriter", "outdir", null); - if (!string.IsNullOrEmpty(outDirPath)) - { - outputDirectory = new DirectoryInfo(outDirPath); - if (!outputDirectory.Exists) - outputDirectory.EnsureExists(); - } + pcapWritersIp = new PcapWriter[0x1fff]; + EnsureOutputdirExists(); } - if (pcapWriters[pid] == null) + if (pcapWritersIp[pid] == null) { string fname = String.Format("{0:X4},{1}.pcap", pid, DateTime.Now.Ticks); if (outputDirectory != null) @@ -45,19 +39,94 @@ namespace skyscraper8.Skyscraper.Net.Pcap } logger.InfoFormat("Opening file for writing: {0}", fname); FileStream fs = File.OpenWrite(fname); - pcapWriters[pid] = new PcapWriter(fs, TcpdumpNetworkType.RawIp); + pcapWritersIp[pid] = new PcapWriter(fs, TcpdumpNetworkType.RawIp); + } + pcapWritersIp[pid].WritePacket(payload); + } + + public void HandleLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, + byte[] contents) + { + byte[] dstAddr = destination.GetAddressBytes(); + byte[] srcAddr = source.GetAddressBytes(); + if (dstAddr.Length != 6) + { + throw new ArgumentException("Invalid destination address length."); + } + + if (source.Equals(PhysicalAddress.None)) + { + srcAddr = new byte[6] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + } + else if (srcAddr.Length != 6) + { + throw new ArgumentException("Invalid source address length."); + } + + if (pcapWritersLlc == null) + { + pcapWritersLlc = new PcapWriter[0x1fff]; + EnsureOutputdirExists(); + } + + if (pcapWritersLlc[pid] == null) + { + string fname = String.Format("{0:X4},llc,{1}.pcap", pid, DateTime.Now.Ticks); + if (outputDirectory != null) + { + fname = Path.Combine(outputDirectory.FullName, fname); + } + + logger.InfoFormat("Opening file for writing: {0}", fname); + FileStream fs = File.OpenWrite(fname); + pcapWritersLlc[pid] = new PcapWriter(fs, TcpdumpNetworkType.UserDefined); + } + + /* + byte[] ethernetFrame = new byte[contents.Length + 14]; + Array.Copy(dstAddr, 0, ethernetFrame, 0, dstAddr.Length); + Array.Copy(srcAddr, 0, ethernetFrame, 6, srcAddr.Length); + + byte[] etherTypeBytes = BitConverter.GetBytes(etherType); + if (BitConverter.IsLittleEndian) + { + ethernetFrame[12] = etherTypeBytes[1]; + ethernetFrame[13] = etherTypeBytes[0]; + } + else + { + ethernetFrame[12] = etherTypeBytes[0]; + ethernetFrame[13] = etherTypeBytes[1]; + } + + + + Array.Copy(contents, 0, ethernetFrame, 14, contents.Length); + pcapWritersLlc[pid].WritePacket(ethernetFrame);*/ + pcapWritersLlc[pid].WritePacket(contents); + + } + + private void EnsureOutputdirExists() + { + PluginManager pluginManager = PluginManager.GetInstance(); + string outDirPath = pluginManager.Ini.ReadValue("pcapwriter", "outdir", null); + if (!string.IsNullOrEmpty(outDirPath)) + { + outputDirectory = new DirectoryInfo(outDirPath); + if (!outputDirectory.Exists) + outputDirectory.EnsureExists(); } - pcapWriters[pid].WritePacket(payload); } public void Dispose() { - if (pcapWriters != null) + if (pcapWritersIp != null) { - for (int i = 0; i < pcapWriters.Length; i++) + for (int i = 0; i < pcapWritersIp.Length; i++) { - if (pcapWriters[i] != null) - pcapWriters[i].Dispose(); + if (pcapWritersIp[i] != null) + pcapWritersIp[i].Dispose(); } } } diff --git a/skyscraper8/Skyscraper/Net/Pcap/TcpdumpNetworkType.cs b/skyscraper8/Skyscraper/Net/Pcap/TcpdumpNetworkType.cs index 4913c1c..42c2cce 100644 --- a/skyscraper8/Skyscraper/Net/Pcap/TcpdumpNetworkType.cs +++ b/skyscraper8/Skyscraper/Net/Pcap/TcpdumpNetworkType.cs @@ -13,5 +13,6 @@ namespace skyscraper5.Skyscraper.Net.Pcap PPPoE = 51, RawIp = 101, WLAN = 105, + UserDefined = 147 } } diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index fe13eb7..d3f3301 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -1754,7 +1754,7 @@ namespace skyscraper5.Skyscraper.Scraper return; } - ipTrafficHandler?.HandlePacket(pid, payload); + ipTrafficHandler?.HandleIpPacket(pid, payload); int ipVersion = (payload[0] & 0xf0) >> 4; if (ipVersion == 4) @@ -3010,7 +3010,7 @@ namespace skyscraper5.Skyscraper.Scraper return; if (etherType <= 1500) { - OnLlcFrame(etherType, contents); + OnLlcFrame((ushort)pid, source, destination, etherType, contents); return; } switch (etherType) @@ -3094,9 +3094,23 @@ namespace skyscraper5.Skyscraper.Scraper { throw new NotImplementedException(); } - - public void OnLlcFrame(ushort etherType, byte[] contents) + + public void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents) { + UiJunction?.EnableUiFeature(SkyscraperUiFeature.LlcSnapTrafficAnalysis); + if (ipTrafficHandler == null) + { + StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); + ipTrafficHandler = storageConnectionManager.GetDefaultIpTrafficHandler(); + } + if (contents.Length == 0) + { + return; + } + + ipTrafficHandler.HandleLlcFrame(pid, source, destination, etherType, contents); + + MemoryStream llcStream = new MemoryStream(contents, true); byte dsap = llcStream.ReadUInt8(); byte ssap = llcStream.ReadUInt8(); @@ -3138,9 +3152,20 @@ namespace skyscraper5.Skyscraper.Scraper //This is from Cisco's Discovery Protocol (CDP). Probably not interesting. return; } + else if (oui[0] == 0x00 && oui[1] == 0x80 && oui[2] == 0xc2 && snapProtocolId == 0x0007) + { + ushort zero = llcStream.ReadUInt16BE(); + //Tunneled Ethernet frame + PhysicalAddress ethernetDst = llcStream.ReadMacAddress(); + PhysicalAddress ethernetSrc = llcStream.ReadMacAddress(); + ushort ethernetType = llcStream.ReadUInt16BE(); + byte[] ethernetPayload = llcStream.ReadBytes(llcStream.GetAvailableBytes()); + OnEthernetFrame(pid, ethernetDst, ethernetSrc, ethernetType, ethernetPayload); + return; + } else { - throw new NotImplementedException(String.Format("SNAP Frame, OUI = {0:X2}-{1:X2}-{2:X2}, Protocol ID = 0x{3:X4}", oui[0], oui[1], oui[2], snapProtocolId)); + //throw new NotImplementedException(String.Format("SNAP Frame, OUI = {0:X2}-{1:X2}-{2:X2}, Protocol ID = 0x{3:X4}", oui[0], oui[1], oui[2], snapProtocolId)); } } else @@ -3173,7 +3198,7 @@ namespace skyscraper5.Skyscraper.Scraper //Likely an LLC management packet (TEST or XID) return; } - throw new NotImplementedException("LLC/SNAP"); + //throw new NotImplementedException("LLC/SNAP"); } public void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange) diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperUiFeature.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperUiFeature.cs index 4644621..5a23784 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperUiFeature.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperUiFeature.cs @@ -14,6 +14,7 @@ namespace skyscraper8.Skyscraper.Scraper IpTrafficAnalysis, GseAnalysis, DvbNipAnalyis, - RcsAnalysis + RcsAnalysis, + LlcSnapTrafficAnalysis } } diff --git a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/MpeContestant.cs b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/MpeContestant.cs index f2f9330..14670a4 100644 --- a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/MpeContestant.cs +++ b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/MpeContestant.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; using skyscraper5.Dvb.DataBroadcasting; @@ -85,5 +86,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants throw new NotSupportedException("IPv6"); } } + + public void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents) + { + Score++; + } + } } diff --git a/skyscraper8/bin/Debug/skyscraper5.ini b/skyscraper8/bin/Debug/skyscraper5.ini index f8efa58..e1e8416 100644 --- a/skyscraper8/bin/Debug/skyscraper5.ini +++ b/skyscraper8/bin/Debug/skyscraper5.ini @@ -18,6 +18,6 @@ Endpoint=172.20.20.3:9000 [dataStorage3] Username=ft Port=5432 -Password=welcometotheworld +Password=12345678 Host=172.20.20.17 Database=skyscraper5 \ No newline at end of file