Detect broken GS encapsulation.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 1m57s

This commit is contained in:
feyris-tan 2025-10-14 07:08:27 +02:00
parent fe66c643f8
commit a46e4ff556
5 changed files with 117 additions and 9 deletions

1
.gitignore vendored
View File

@ -129,3 +129,4 @@ imgui.ini
/skyscraper8.Manual/skyscraper8.Manual.out /skyscraper8.Manual/skyscraper8.Manual.out
/skyscraper8.Manual/skyscraper8.Manual.pdf /skyscraper8.Manual/skyscraper8.Manual.pdf
/skyscraper8.Manual/skyscraper8.Manual.synctex.gz /skyscraper8.Manual/skyscraper8.Manual.synctex.gz
/.vs/skyscraper8/CopilotIndices/17.14.1231.31060

View File

@ -90,6 +90,11 @@ namespace skyscraper8.GSE
break; break;
} }
if (!packet.Valid)
{
break;
}
if (packet.IsCompletePacket) if (packet.IsCompletePacket)
{ {
if (ValidateEthertype(packet.ProtocolType.Value)) if (ValidateEthertype(packet.ProtocolType.Value))
@ -113,6 +118,25 @@ namespace skyscraper8.GSE
continue; continue;
} }
if (!packet.StartIndicator && packet.EndIndicator)
{
if (gseFragmentations == null)
continue;
if (gseFragmentations[packet.FragmentId.Value] == null)
continue;
gseFragmentations[packet.FragmentId.Value].AddPacket(packet);
continue;
}
if (!packet.StartIndicator && !packet.EndIndicator)
{
if (gseFragmentations == null)
continue;
throw new NotImplementedException();
}
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }
@ -130,7 +154,7 @@ namespace skyscraper8.GSE
long availableBytes = ms.GetAvailableBytes(); long availableBytes = ms.GetAvailableBytes();
byte[] readBytes = ms.ReadBytes(availableBytes); byte[] readBytes = ms.ReadBytes(availableBytes);
GseAssemblyState assemblyState = ValidateGse(gseAssembler); GseAssemblyState assemblyState = ValidateGse(gseAssembler, true);
if (assemblyState == GseAssemblyState.NOT_YET_BEGUN) if (assemblyState == GseAssemblyState.NOT_YET_BEGUN)
{ {
if ((syncByte & 0xc0) == 0xc0) if ((syncByte & 0xc0) == 0xc0)
@ -195,7 +219,7 @@ namespace skyscraper8.GSE
VALID_NULL_PACKET, //somehow these only show up on TBS6903x, not DD Max SX8? VALID_NULL_PACKET, //somehow these only show up on TBS6903x, not DD Max SX8?
} }
private GseAssemblyState ValidateGse(MemoryStream ms) private GseAssemblyState ValidateGse(MemoryStream ms, bool tryFix = false)
{ {
if (ms == null) if (ms == null)
return GseAssemblyState.NOT_YET_BEGUN; return GseAssemblyState.NOT_YET_BEGUN;
@ -204,6 +228,8 @@ namespace skyscraper8.GSE
ms.Position = 0; ms.Position = 0;
while (ms.GetAvailableBytes() > 2) while (ms.GetAvailableBytes() > 2)
{ {
long fixPosition = ms.Position;
//GSE-Header //GSE-Header
byte byteA = ms.ReadUInt8(); byte byteA = ms.ReadUInt8();
bool startIndicator = (byteA & 0x80) != 0; bool startIndicator = (byteA & 0x80) != 0;
@ -224,6 +250,12 @@ namespace skyscraper8.GSE
//Console.WriteLine("GSE Length: {0}", gseLength); //Console.WriteLine("GSE Length: {0}", gseLength);
if (gseLength > 9000) if (gseLength > 9000)
{ {
if (tryFix)
{
ms.Position = fixPosition;
ms.WriteUInt8Repeat(0, (int)ms.GetAvailableBytes());
break;
}
ms.Position = backupPosition; ms.Position = backupPosition;
return GseAssemblyState.BROKEN_SUSPECT_LENGTH; return GseAssemblyState.BROKEN_SUSPECT_LENGTH;
} }
@ -236,6 +268,11 @@ namespace skyscraper8.GSE
if (startIndicator && !endIndicator) if (startIndicator && !endIndicator)
{ {
if (2 > ms.GetAvailableBytes())
{
ms.Position = backupPosition;
return GseAssemblyState.NEED_MORE_DATA;
}
ushort totalLength = ms.ReadUInt16BE(); ushort totalLength = ms.ReadUInt16BE();
gseLength -= 2; gseLength -= 2;
} }
@ -250,6 +287,12 @@ namespace skyscraper8.GSE
ushort protocolType = ms.ReadUInt16BE(); ushort protocolType = ms.ReadUInt16BE();
if (!ValidateEthertype(protocolType)) if (!ValidateEthertype(protocolType))
{ {
if (tryFix)
{
ms.Position = fixPosition;
ms.WriteUInt8Repeat(0, (int)ms.GetAvailableBytes());
break;
}
ms.Position = backupPosition; ms.Position = backupPosition;
return GseAssemblyState.BROKEN_SUSPECT_ETHERTYPE; return GseAssemblyState.BROKEN_SUSPECT_ETHERTYPE;
} }
@ -278,6 +321,12 @@ namespace skyscraper8.GSE
if (gseLength < 0) if (gseLength < 0)
{ {
if (tryFix)
{
ms.Position = fixPosition;
ms.WriteUInt8Repeat(0, (int)ms.GetAvailableBytes());
break;
}
ms.Position = backupPosition; ms.Position = backupPosition;
return GseAssemblyState.BROKEN_NEGATIVE_LENGTH; return GseAssemblyState.BROKEN_NEGATIVE_LENGTH;
} }
@ -291,6 +340,11 @@ namespace skyscraper8.GSE
ms.Position += gseLength; ms.Position += gseLength;
if (!startIndicator && endIndicator) if (!startIndicator && endIndicator)
{ {
if (4 > ms.GetAvailableBytes())
{
ms.Position = backupPosition;
return GseAssemblyState.NEED_MORE_DATA;
}
uint crc32 = ms.ReadUInt32BE(); uint crc32 = ms.ReadUInt32BE();
int endCrc32 = (int)ms.Position; int endCrc32 = (int)ms.Position;
DvbCrc32.ValidateCrc(ms, startCrc32, endCrc32); DvbCrc32.ValidateCrc(ms, startCrc32, endCrc32);

View File

@ -9,7 +9,7 @@ using skyscraper5.Skyscraper;
namespace skyscraper8.GSE namespace skyscraper8.GSE
{ {
internal class GsePacket internal class GsePacket : Validatable
{ {
public static GsePacket Read(MemoryStream ms) public static GsePacket Read(MemoryStream ms)
{ {
@ -62,12 +62,23 @@ namespace skyscraper8.GSE
if (!packet.StartIndicator && packet.EndIndicator) if (!packet.StartIndicator && packet.EndIndicator)
gseLength -= 4; gseLength -= 4;
if (gseLength < 0)
{
packet.Valid = false;
return packet;
}
if (gseLength > ms.GetAvailableBytes())
{
packet.Valid = false;
return packet;
}
packet.GseData = ms.ReadBytes(gseLength); packet.GseData = ms.ReadBytes(gseLength);
if (!packet.StartIndicator && packet.EndIndicator) if (!packet.StartIndicator && packet.EndIndicator)
packet.Crc32 = ms.ReadUInt32BE(); packet.Crc32 = ms.ReadUInt32BE();
} }
packet.Valid = true;
return packet; return packet;
} }

View File

@ -1,15 +1,17 @@
using System; using log4net;
using skyscraper5.Skyscraper;
using skyscraper5.src.Mpeg2.PacketFilter;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using skyscraper5.Skyscraper;
using skyscraper5.src.Mpeg2.PacketFilter;
namespace skyscraper5.Mpeg2 namespace skyscraper5.Mpeg2
{ {
public class TsContext : ITsPacketProcessor public class TsContext : ITsPacketProcessor
{ {
private ITsPacketProcessor[] processors; private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
private ITsPacketProcessor[] processors;
private uint[] continuities; private uint[] continuities;
private ulong[] pidPackets; private ulong[] pidPackets;
@ -42,6 +44,8 @@ namespace skyscraper5.Mpeg2
if (FilterChain == null || FilterChain.Count == 0) if (FilterChain == null || FilterChain.Count == 0)
throw new InvalidOperationException("The filter chain has not been initialized."); throw new InvalidOperationException("The filter chain has not been initialized.");
CheckBrokenEncapsulation(packet);
for (int i = 0; i < FilterChain.Count; i++) for (int i = 0; i < FilterChain.Count; i++)
{ {
if (FilterChain[i] == null) if (FilterChain[i] == null)
@ -61,6 +65,44 @@ namespace skyscraper5.Mpeg2
processors[packet.PID].PushPacket(packet); processors[packet.PID].PushPacket(packet);
} }
private bool encapsulationBrokenConfirmed;
private bool CheckBrokenEncapsulation(TsPacket packet)
{
if (encapsulationBrokenConfirmed)
return true;
switch (packet.PID)
{
case 0x0000:
case 0x0001:
break;
default:
return false;
}
int occupiedPids = CountOccupiedPids();
if (occupiedPids < 1000)
return false;
if (packet.TSC == 0)
return false;
logger.WarnFormat("It looks like you're either having bad reception or this is a GS with broken encapsulation. This means that you either have FrameMode enabled, or are not using a STiD135.");
encapsulationBrokenConfirmed = true;
return true;
}
private int CountOccupiedPids()
{
int result = 0;
for (int i = 0; i < pidPackets.Length; i++)
{
if (pidPackets[i] > 0)
result++;
}
return result;
}
private bool EnsureContinuity(TsPacket packet) private bool EnsureContinuity(TsPacket packet)
{ {
//Found in ISO 13818-1.pdf, page 38 //Found in ISO 13818-1.pdf, page 38

View File

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"skyscraper8": { "skyscraper8": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "\"\\\\utena\\mergerfs\\Skyscraper\\ipProto253_eutelsat7_10803h-max-sx8.ts\"", "commandLineArgs": "cscan tcp://172.20.20.203:6969",
"remoteDebugEnabled": false "remoteDebugEnabled": false
}, },
"Container (Dockerfile)": { "Container (Dockerfile)": {