From c324a923deb647b8b34e6114f455a04b366c064a Mon Sep 17 00:00:00 2001 From: feyris-tan Date: Tue, 14 Oct 2025 15:59:45 +0200 Subject: [PATCH] Added a port of BbfUdpDecap. --- skyscraper8.sln.DotSettings.user | 1 + skyscraper8/GSE/BbfUdpDecap.cs | 261 ++++++++++++++++++ skyscraper8/GSE/Pts2Bbf.cs | 22 +- skyscraper8/Program.cs | 15 +- skyscraper8/Skyscraper/IO/StreamExtensions.cs | 11 + skyscraper8/skyscraper8.csproj | 2 + 6 files changed, 306 insertions(+), 6 deletions(-) create mode 100644 skyscraper8/GSE/BbfUdpDecap.cs diff --git a/skyscraper8.sln.DotSettings.user b/skyscraper8.sln.DotSettings.user index 24e0a36..33fbc3f 100644 --- a/skyscraper8.sln.DotSettings.user +++ b/skyscraper8.sln.DotSettings.user @@ -1,3 +1,4 @@  ForceIncluded + ForceIncluded <data><HostParameters type="LocalHostParameters" /><Argument type="StandaloneArgument"><Arguments IsNull="False"></Arguments><FileName IsNull="False"></FileName><WorkingDirectory IsNull="False"></WorkingDirectory><Scope><ProcessFilters /></Scope></Argument><Info type="TimelineInfo" /><CoreOptions type="CoreOptions"><CoreTempPath IsNull="False"></CoreTempPath><RemoteEndPoint IsNull="False"></RemoteEndPoint><AdditionalEnvironmentVariables /></CoreOptions><HostOptions type="HostOptions"><HostTempPath IsNull="False"></HostTempPath></HostOptions></data> \ No newline at end of file diff --git a/skyscraper8/GSE/BbfUdpDecap.cs b/skyscraper8/GSE/BbfUdpDecap.cs new file mode 100644 index 0000000..dd04066 --- /dev/null +++ b/skyscraper8/GSE/BbfUdpDecap.cs @@ -0,0 +1,261 @@ +using System.Net; +using System.Runtime.InteropServices; +using skyscraper5.Skyscraper.IO; + +namespace skyscraper8.GSE; + +public class BbfUdpDecap : IBbframeDeencapsulator +{ + public IUdpDecapOutput Sink { get; set; } + public long NumPushed { get; private set; } + + public void SetTargetIp(IPAddress ip) + { + HasTargetIp = ip.GetAddressBytes(); + } + + public void SetTargetPort(int tmp) + { + HasTargetPort = new byte[4]; + HasTargetPort[0] = (byte)(tmp >> 8); + HasTargetPort[1] = (byte)(tmp & 0xff); + } + + private byte? HasMis; + private byte[] HasSourceIp; + private byte[] HasTargetIp; + private byte[] HasSourcePort; + private byte[] HasTargetPort; + + private byte[] inData; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct bbheader + { + public byte MaType1; + public byte MaType2; + public byte Upl1; + public byte Upl2; + public byte Dfl1; + public byte Dfl2; + public byte Sync; + public byte SyncD1; + public byte SyncD2; + public byte Crc8; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + unsafe struct Layer3 + { + public byte l3sync; + public bbheader header; + public fixed byte Data[7254-10]; + } + public unsafe void PushPacket(byte[] bbframe) + { + NumPushed++; + + if (inData == null) + { + inData = new byte[8100]; + } + + if (fragmentor == null) + { + fragmentor = new byte[256][]; + fragmentorLength = new int[256]; + fragmentorPos = new int[256]; + } + MemoryStream inbuf = new MemoryStream(bbframe); + Layer3 myLayer; + while (true) + { + if (inbuf.Peek() == 0xb8) + break; + inbuf.ReadByte(); + } + + while (true) + { + int fail = inbuf.Read(inData, 0, 11); + if (fail != 11) + break; + myLayer = MemoryMarshal.Read(inData); + if (myLayer.l3sync != 0xb8) + { + while (true) + { + if (inbuf.Peek() == 0xb8) + break; + fail = inbuf.Read(inData, 0, 1); + if (fail != 1) + break; + } + } + + int bblength = myLayer.header.Dfl1 << 8 | myLayer.header.Dfl2; + bblength >>= 3; + fail = inbuf.Read(inData, 11, bblength); + if (fail != bblength) + break; + myLayer = MemoryMarshal.Read(inData); + if (HasMis.HasValue && (myLayer.header.MaType2 != HasMis.Value)) + continue; + + int pos = 0; + while (pos < bblength - 4) + { + int gseLength = ((myLayer.Data[pos] & 0x0f) << 8) | (myLayer.Data[pos + 1]); + if ((myLayer.Data[pos] & 0xf0) == 0) break; + if (gseLength + 2 > bblength - pos) break; + if (!ProcessBbFrame(&myLayer.Data[pos], gseLength)) + break; + pos += gseLength += 2; + } + } + } + + private byte[][] fragmentor; + private int[] fragmentorLength; + private int[] fragmentorPos; + + private unsafe void Copy(byte* src, byte[] dst, int srcOffset, int dstOffset, int len) + { + for (int i = 0; i < len; i++) + { + dst[dstOffset + i] = src[srcOffset + i]; + } + } + private unsafe bool ProcessBbFrame(byte* payload, int gseLength) + { + uint offset = 0; + uint fragId = 0; + + if ((payload[0] & 0xc0) == 0x80) + { + fragId = payload[2]; + int length=(payload[3]<<8) | payload[4]; + if(fragmentor[fragId]!=null) + fragmentor[fragId] = null; + fragmentor[fragId] = new byte[length + 2]; + fragmentorLength[fragId] = length + 2; + fragmentor[fragId][0] = payload[0]; + fragmentor[fragId][1] = payload[1]; + fragmentor[fragId][0] |= 0xc0; + Copy(payload, fragmentor[fragId], 5, 2, gseLength - 3); + fragmentorPos[fragId] = gseLength - 1; + } + else if ((payload[0] & 0xc0) == 0x00) + { + throw new NotImplementedException("inbetween packet"); + } + else if ((payload[0] & 0xc0) == 0x40) + { + fragId = payload[2]; + if (fragmentor[fragId] == null) + return true; + + Copy(payload, fragmentor[fragId], 3, fragmentorPos[fragId], gseLength - 5); + fragmentorPos[fragId] += gseLength - 1; + fixed (byte* p = fragmentor[fragId]) + { + ProcessBbFrame(p, fragmentorLength[fragId]); + } + fragmentor[fragId] = null; + + } + else if ((payload[0] & 0xc0) == 0xc0) + { + if (payload[offset + 2] == 0x00 && payload[offset + 3] == 0x04) + { + throw new NotImplementedException("ethertype 0x0400"); + } + else if (payload[offset + 2] == 0x00 && payload[offset + 3] == 0x00) + { + throw new NotImplementedException("ethertype 0x0000"); + } + else if (payload[offset + 2] == 0x08 && payload[offset + 3] == 0x00) + { + if((payload[0]&0x30)==0x01) { + offset += 3; //3-byte label + } + else if((payload[0] & 0x30) == 0x00) { + offset += 6; //MAC address + } + + offset += 0x10; //IPv4 header + if (IsSelected(&payload[offset])) + { + offset += 0x10; + } + else + { + return true; + } + + long sinkSize = gseLength + 2 -offset; + byte[] sinkMe = new byte[sinkSize]; + Copy(payload,sinkMe,(int)offset,0, sinkMe.Length); + Sink.Write(sinkMe); + return true; + } + + //throw new NotImplementedException("complete packet"); + } + else if ((payload[0] & 0x0f0) == 0x00) + { + throw new NotImplementedException("padding packet"); + } + return true; + } + + private unsafe bool IsSelected(byte* buf) + { + byte zero = buf[0]; + byte one = buf[1]; + byte two = buf[2]; + byte three = buf[3]; + byte four = buf[4]; + byte five = buf[5]; + byte six = buf[6]; + byte seven = buf[7]; + + if(HasSourceIp != null && (!(zero==HasSourceIp[0] && one==HasSourceIp[1] && two==HasSourceIp[2] && three==HasSourceIp[3]))) + return false; + if(HasTargetIp != null && (!(four==HasTargetIp[0] && five==HasTargetIp[1] && six==HasTargetIp[2] && seven==HasTargetIp[3]))) + return false; + if(HasSourcePort != null &&(!(buf[0x8]==HasSourcePort[0] && buf[0x9]==HasSourcePort[1]))) + return false; + if(HasTargetPort != null &&(!(buf[0xa]==HasTargetPort[0] && buf[0xb]==HasTargetPort[1]))) + return false; + return true; + } + + public interface IUdpDecapOutput + { + public void Write(byte[] buffer); + } + + internal class UdpDecapFileOutput : IUdpDecapOutput + { + public UdpDecapFileOutput(FileInfo file) + { + file.Directory.EnsureExists(); + ourStream = file.OpenWrite(); + } + + private FileStream ourStream; + + public void Write(byte[] udpPacket) + { + ourStream.Write(udpPacket, 0, udpPacket.Length); + } + + public void Dispose() + { + ourStream.Flush(); + ourStream.Close(); + ourStream.Dispose(); + } + } +} \ No newline at end of file diff --git a/skyscraper8/GSE/Pts2Bbf.cs b/skyscraper8/GSE/Pts2Bbf.cs index 60dd0a3..3996159 100644 --- a/skyscraper8/GSE/Pts2Bbf.cs +++ b/skyscraper8/GSE/Pts2Bbf.cs @@ -1,3 +1,4 @@ +using System.Net; using log4net; using skyscraper5.Mpeg2; using skyscraper5.Skyscraper.Scraper; @@ -10,7 +11,7 @@ public class Pts2Bbf { private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); - public static void Run(FileInfo file) + public static void Run(FileInfo file, bool useUdpDecap = false) { if (!file.Exists) { @@ -18,8 +19,23 @@ public class Pts2Bbf return; } - string changeExtension = Path.ChangeExtension(file.FullName, ".sbbf"); - BbframeDumper dumper = new BbframeDumper(new FileInfo(changeExtension)); + IBbframeDeencapsulator dumper; + if (useUdpDecap) + { + string changeExtension = Path.ChangeExtension(file.FullName, ".sdecap"); + BbfUdpDecap.UdpDecapFileOutput udpDecapSink = new BbfUdpDecap.UdpDecapFileOutput(new FileInfo(changeExtension)); + + BbfUdpDecap bbfUdpDecap = new BbfUdpDecap(); + bbfUdpDecap.SetTargetPort(1234); + bbfUdpDecap.SetTargetIp(IPAddress.Parse("239.199.2.1")); + bbfUdpDecap.Sink = udpDecapSink; + dumper = bbfUdpDecap; + } + else + { + string changeExtension = Path.ChangeExtension(file.FullName, ".sbbf"); + dumper = new BbframeDumper(new FileInfo(changeExtension)); + } FileStream fileStream = file.OpenRead(); diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index 0b42bd6..c4dfb54 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -310,9 +310,18 @@ namespace skyscraper5 if (args[0].ToLowerInvariant().Equals("pts2bbf")) { - FileInfo fi = new FileInfo(args[1]); - Pts2Bbf.Run(fi); - return; + if (args[1].ToLowerInvariant().Equals("bbfudpdecap")) + { + FileInfo fi = new FileInfo(args[2]); + Pts2Bbf.Run(fi, true); + return; + } + else + { + FileInfo fi = new FileInfo(args[1]); + Pts2Bbf.Run(fi, false); + return; + } } } diff --git a/skyscraper8/Skyscraper/IO/StreamExtensions.cs b/skyscraper8/Skyscraper/IO/StreamExtensions.cs index 9b7b93c..97a04fa 100644 --- a/skyscraper8/Skyscraper/IO/StreamExtensions.cs +++ b/skyscraper8/Skyscraper/IO/StreamExtensions.cs @@ -322,5 +322,16 @@ namespace skyscraper5.Skyscraper.IO stream.Write(buffer, 0, 8); } + public static byte Peek(this Stream stream) + { + if (!stream.CanSeek) + throw new NotSupportedException("Stream is not peekable"); + if (stream.Position == stream.Length) + throw new EndOfStreamException(); + + byte readUInt8 = stream.ReadUInt8(); + stream.Position--; + return readUInt8; + } } } diff --git a/skyscraper8/skyscraper8.csproj b/skyscraper8/skyscraper8.csproj index dc8b3e8..5ee6e44 100644 --- a/skyscraper8/skyscraper8.csproj +++ b/skyscraper8/skyscraper8.csproj @@ -13,11 +13,13 @@ False False + true False False + true