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.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)

View File

@ -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);
}
}

View File

@ -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--;

View File

@ -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);
/// <summary>
/// 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));
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()

View File

@ -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)": {

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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)
{
}

View File

@ -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();
}
}
}

View File

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

View File

@ -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)

View File

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

View File

@ -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++;
}
}
}

View File

@ -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