Added support for LLC/SNAP inside MPE packets.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 41s

This commit is contained in:
feyris-tan 2026-05-17 21:25:12 +02:00
parent a940ef3a45
commit a925a3a416
15 changed files with 178 additions and 36 deletions

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using log4net;
using skyscraper5.Ietf.Rfc768; using skyscraper5.Ietf.Rfc768;
using skyscraper5.Mpeg2; using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.IO;
@ -13,7 +14,9 @@ namespace skyscraper5.Dvb.DataBroadcasting
{ {
class MultiprotocolEncapsulationDecoder : IPsiProcessor 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) public MultiprotocolEncapsulationDecoder(IMultiprotocolEncapsulationEventHandler eventHandler)
{ {
@ -59,7 +62,7 @@ namespace skyscraper5.Dvb.DataBroadcasting
byte[] payload = ms.ReadBytes(length); byte[] payload = ms.ReadBytes(length);
if (llcSnap) if (llcSnap)
{ {
HandleLlcSnap(sourcePid,payload); HandleLlcSnap(sourcePid, macAddress, payload);
} }
else 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) private void HandleIpDatagram(int sourcePid, byte[] payload)

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using skyscraper5.Ietf.Rfc971; using skyscraper5.Ietf.Rfc971;
@ -11,5 +12,9 @@ namespace skyscraper5.Dvb.DataBroadcasting
{ {
void OnIpv4PacketArrival(InternetHeader internetHeader, byte[] ipv4Packet); void OnIpv4PacketArrival(InternetHeader internetHeader, byte[] ipv4Packet);
void OnIpDatagram(int sourcePid, byte[] payload); void OnIpDatagram(int sourcePid, byte[] payload);
void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents);
} }
} }

View File

@ -38,6 +38,11 @@ namespace skyscraper8.Ietf.Rfc4236_ULE
Score++; Score++;
} }
public void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents)
{
Score++;
}
public void OnUleError(int pid, int errorNo) public void OnUleError(int pid, int errorNo)
{ {
Score--; Score--;

View File

@ -9,7 +9,7 @@ namespace skyscraper8.Ietf.Rfc4236_ULE
{ {
internal interface UleEventHandler 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);
/// <summary> /// <summary>
/// The UlePacketProcessor is supposed to call this whenever an Error occurs during deframing. /// The UlePacketProcessor is supposed to call this whenever an Error occurs during deframing.

View File

@ -202,7 +202,7 @@ namespace skyscraper8.Ietf.Rfc4236_ULE
PhysicalAddress source = new PhysicalAddress(ms.ReadBytes(6)); PhysicalAddress source = new PhysicalAddress(ms.ReadBytes(6));
ushort etherType = ms.ReadUInt16BE(); ushort etherType = ms.ReadUInt16BE();
byte[] contents = ms.ReadBytes(ms.GetAvailableBytes()); byte[] contents = ms.ReadBytes(ms.GetAvailableBytes());
_eventHandler.OnEthernetFrame(_pid, destination, source, etherType, contents); _eventHandler.OnLlcFrame((ushort)_pid, source, destination, etherType, contents);
} }
public void PacketLoss() public void PacketLoss()

View File

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"skyscraper8": { "skyscraper8": {
"commandName": "Project", "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 "remoteDebugEnabled": false
}, },
"Container (Dockerfile)": { "Container (Dockerfile)": {

View File

@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Net.NetworkInformation;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
@ -423,5 +424,13 @@ namespace skyscraper5.Skyscraper.IO
Array.Reverse(buffer); Array.Reverse(buffer);
return BitConverter.ToSingle(buffer, 0); 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);
}
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -8,6 +9,7 @@ namespace skyscraper8.Skyscraper.Net
{ {
internal interface IpTrafficHandler : IDisposable 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);
} }
} }

View File

@ -4,6 +4,7 @@ using skyscraper8.Skyscraper.Scraper.Storage;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; 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)
{ {
} }

View File

@ -6,6 +6,7 @@ using skyscraper8.Skyscraper.Scraper.Storage;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -17,26 +18,19 @@ namespace skyscraper8.Skyscraper.Net.Pcap
internal class PcapIpTrafficHandler : IpTrafficHandler internal class PcapIpTrafficHandler : IpTrafficHandler
{ {
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); 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; 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]; pcapWritersIp = new PcapWriter[0x1fff];
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();
}
} }
if (pcapWriters[pid] == null) if (pcapWritersIp[pid] == null)
{ {
string fname = String.Format("{0:X4},{1}.pcap", pid, DateTime.Now.Ticks); string fname = String.Format("{0:X4},{1}.pcap", pid, DateTime.Now.Ticks);
if (outputDirectory != null) if (outputDirectory != null)
@ -45,19 +39,94 @@ namespace skyscraper8.Skyscraper.Net.Pcap
} }
logger.InfoFormat("Opening file for writing: {0}", fname); logger.InfoFormat("Opening file for writing: {0}", fname);
FileStream fs = File.OpenWrite(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() 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) if (pcapWritersIp[i] != null)
pcapWriters[i].Dispose(); pcapWritersIp[i].Dispose();
} }
} }
} }

View File

@ -13,5 +13,6 @@ namespace skyscraper5.Skyscraper.Net.Pcap
PPPoE = 51, PPPoE = 51,
RawIp = 101, RawIp = 101,
WLAN = 105, WLAN = 105,
UserDefined = 147
} }
} }

View File

@ -1754,7 +1754,7 @@ namespace skyscraper5.Skyscraper.Scraper
return; return;
} }
ipTrafficHandler?.HandlePacket(pid, payload); ipTrafficHandler?.HandleIpPacket(pid, payload);
int ipVersion = (payload[0] & 0xf0) >> 4; int ipVersion = (payload[0] & 0xf0) >> 4;
if (ipVersion == 4) if (ipVersion == 4)
@ -3010,7 +3010,7 @@ namespace skyscraper5.Skyscraper.Scraper
return; return;
if (etherType <= 1500) if (etherType <= 1500)
{ {
OnLlcFrame(etherType, contents); OnLlcFrame((ushort)pid, source, destination, etherType, contents);
return; return;
} }
switch (etherType) switch (etherType)
@ -3095,8 +3095,22 @@ namespace skyscraper5.Skyscraper.Scraper
throw new NotImplementedException(); 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); MemoryStream llcStream = new MemoryStream(contents, true);
byte dsap = llcStream.ReadUInt8(); byte dsap = llcStream.ReadUInt8();
byte ssap = 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. //This is from Cisco's Discovery Protocol (CDP). Probably not interesting.
return; 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 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 else
@ -3173,7 +3198,7 @@ namespace skyscraper5.Skyscraper.Scraper
//Likely an LLC management packet (TEST or XID) //Likely an LLC management packet (TEST or XID)
return; return;
} }
throw new NotImplementedException("LLC/SNAP"); //throw new NotImplementedException("LLC/SNAP");
} }
public void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange) public void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange)

View File

@ -14,6 +14,7 @@ namespace skyscraper8.Skyscraper.Scraper
IpTrafficAnalysis, IpTrafficAnalysis,
GseAnalysis, GseAnalysis,
DvbNipAnalyis, DvbNipAnalyis,
RcsAnalysis RcsAnalysis,
LlcSnapTrafficAnalysis
} }
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using skyscraper5.Dvb.DataBroadcasting; using skyscraper5.Dvb.DataBroadcasting;
@ -85,5 +86,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
throw new NotSupportedException("IPv6"); throw new NotSupportedException("IPv6");
} }
} }
public void OnLlcFrame(ushort pid, PhysicalAddress source, PhysicalAddress destination, ushort etherType, byte[] contents)
{
Score++;
}
} }
} }

View File

@ -18,6 +18,6 @@ Endpoint=172.20.20.3:9000
[dataStorage3] [dataStorage3]
Username=ft Username=ft
Port=5432 Port=5432
Password=welcometotheworld Password=12345678
Host=172.20.20.17 Host=172.20.20.17
Database=skyscraper5 Database=skyscraper5