Don't crash on broken FLUTE messages. Instead, discard them.

This commit is contained in:
feyris-tan 2025-09-19 21:58:47 +02:00
parent f83b920af4
commit d95d8c0235
8 changed files with 248 additions and 68 deletions

View File

@ -72,6 +72,9 @@ namespace skyscraper8.Ietf.FLUTE
if (blocks == null)
blocks = new Dictionary<Tuple<ushort, ushort>, FluteBlock>();
if (lctFrame.FecHeader == null)
return;
ushort sbn = lctFrame.FecHeader.SourceBlockNumber;
ushort esi = lctFrame.FecHeader.EncodingSymbolId;

View File

@ -1,9 +1,11 @@
using skyscraper5.Skyscraper.IO;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper;
namespace skyscraper8.Ietf.FLUTE
{
@ -25,7 +27,10 @@ namespace skyscraper8.Ietf.FLUTE
this.CloseObjectFlag = (byteB & 0x01) != 0;
if (this.Version != 1)
throw new NotSupportedException(String.Format("FLUTE Version {0}", Version));
{
Debug.WriteLine(String.Format("FLUTE Version {0}", Version));
return;
}
int HeaderLength = ms.ReadUInt8();
HeaderLength *= 4;
@ -35,6 +40,8 @@ namespace skyscraper8.Ietf.FLUTE
byte[] headerBuffer = ms.ReadBytes(HeaderLength);
this.LctHeader = new LctHeader(headerBuffer,CongestionControlFlag,TransportSessionIdentifierFlag,TransportObjectIdentifierFlag,HalfWordFlag);
if (!this.LctHeader.Valid)
return;
if (ms.GetAvailableBytes() < 4)
return;

View File

@ -2,13 +2,15 @@
using skyscraper8.DvbNip;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper;
namespace skyscraper8.Ietf.FLUTE
{
internal class LctHeader
internal class LctHeader : Validatable
{
/// <summary>
///
@ -32,6 +34,11 @@ namespace skyscraper8.Ietf.FLUTE
CongestionControlInformation = ReadField(ms, cciLength);
TransportSessionIdentifier = ReadField(ms, tsiLength);
TransportObjectIdentifier = ReadField(ms, toiLength);
if (CongestionControlInformation == UInt64.MaxValue || TransportSessionIdentifier == UInt64.MaxValue || TransportObjectIdentifier == UInt64.MaxValue)
{
Valid = false;
return;
}
while (ms.GetAvailableBytes() >= 1)
{
@ -49,7 +56,9 @@ namespace skyscraper8.Ietf.FLUTE
this.ContentEncoding = new ContentEncodingOfFdtInstance(fixedHeaderExtension);
break;
default:
throw new NotImplementedException(String.Format("LCT Header Extension {0}", extensionId));
Debug.WriteLine(String.Format("LCT Header Extension {0}", extensionId));
Valid = false;
return;
}
}
else
@ -58,6 +67,11 @@ namespace skyscraper8.Ietf.FLUTE
headerExtensionLength *= 4;
if (headerExtensionLength >= 2)
headerExtensionLength -= 2;
if (headerExtensionLength > ms.GetAvailableBytes())
{
Valid = false;
return;
}
byte[] extensionBuffer = ms.ReadBytes(headerExtensionLength);
switch(extensionId)
{
@ -73,11 +87,15 @@ namespace skyscraper8.Ietf.FLUTE
this.NipActualCarrierInformation = new NipActualCarrierInformation(extensionBuffer);
break;
default:
throw new NotImplementedException(String.Format("LCT Header Extension {0}", extensionId));
Debug.WriteLine(String.Format("LCT Header Extension {0}", extensionId));
Valid = false;
return;
}
}
}
Valid = true;
}
private ulong ReadField(Stream stream, int bits)
@ -93,7 +111,7 @@ namespace skyscraper8.Ietf.FLUTE
case 64:
return stream.ReadUInt64BE();
default:
throw new NotImplementedException(String.Format("{0} bits.", bits));
return UInt64.MaxValue;
}
}
public ulong CongestionControlInformation { get; private set; }

View File

@ -40,7 +40,7 @@ namespace skyscraper5
class Program
{
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
private const int PUBLIC_RELEASE = 8;
private const int PUBLIC_RELEASE = 9;
private static void IntegrationTest()
{
/*List<SsdpDevice> ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList();

View File

@ -2,7 +2,7 @@
"profiles": {
"skyscraper8": {
"commandName": "Project",
"commandLineArgs": "\"C:\\devel\\skyscraper8\\skyscraper8\\bin\\Debug\\net8.0\\638938290099956387.ts\"",
"commandLineArgs": "satip auto 1 H 11141 S2 23500",
"remoteDebugEnabled": false
},
"Container (Dockerfile)": {

View File

@ -20,7 +20,7 @@ namespace skyscraper8
internal class QuickAndDirtySatIpClient
{
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
private const bool ENABLE_TS_WRITER = true;
private const bool ENABLE_TS_WRITER = false;
public QuickAndDirtySatIpClient(string[] args)
{
@ -106,6 +106,11 @@ namespace skyscraper8
packetQueue = new Queue<byte[]>();
RtspSetupResponse setup = rtspClient.GetSetup(url);
if (setup.RtspStatusCode == 404)
{
logger.Fatal("Your SAT>IP server doesn't have a tuner available that can talk to the requested frequency.");
return;
}
setup.OnRtcpPacket += Setup_OnRtcpPacket;
setup.OnRtpPacket += Setup_OnRtpPacket;

View File

@ -1,12 +1,14 @@
using System;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.IO;
namespace skyscraper8.Skyscraper
{
@ -15,6 +17,7 @@ namespace skyscraper8.Skyscraper
private bool interruptedGseHem;
private MemoryStream interruptedGseHemBuffer;
private bool interruptedGseHemWantsCrc32;
public IGsEventHandler MpeEventHandler { get; set; }
public void PushPacket(byte[] bbframe)
{
@ -49,37 +52,202 @@ namespace skyscraper8.Skyscraper
}
}
private bool isGseSynced;
private int gseNeeded;
private MemoryStream gseNeededBuffer;
private bool gseNeedMore;
private MemoryStream gseAssembler;
public int PID;
private void HandleGse(MemoryStream ms)
{
if (!isGseSynced)
ms.Position = 10;
byte syncByte = ms.ReadUInt8();
ms.Position = 10;
long availableBytes = ms.GetAvailableBytes();
byte[] readBytes = ms.ReadBytes(availableBytes);
GseAssemblyState assemblyState = ValidateGse(gseAssembler);
if (assemblyState == GseAssemblyState.NOT_YET_BEGUN)
{
ms.Position = 10;
byte syncByte = ms.ReadUInt8();
ms.Position = 10;
if ((syncByte & 0xc0) == 0xc0)
{
isGseSynced = true;
//Aktuell ist der GSE Assembler nicht beschäftigt, aber wir haben ein Sync-Byte, also kann er loslegen.
gseAssembler = new MemoryStream();
gseAssembler.Write(readBytes, 0, readBytes.Length);
return;
}
else
{
//Aktuell ist der GSE Assembler nicht beschäftigt, und wir haben kein gültiges Sync-Byte, also weg damit.
//Console.WriteLine("gse not in sync yet. sync byte = {0}", syncByte);
return;
}
}
if (gseNeeded > 0)
else if (assemblyState == GseAssemblyState.NEED_MORE_DATA)
{
int blockSize = (int)System.Math.Min(gseNeeded, ms.GetAvailableBytes());
gseNeededBuffer.Write(ms.ReadBytes(blockSize), 0, blockSize);
gseNeeded -= blockSize;
if (gseNeeded == 0)
gseAssembler.Write(readBytes, 0, readBytes.Length);
return;
}
else if (assemblyState == GseAssemblyState.VALID)
{
gseAssembler.Position = 0;
AssembleGse(gseAssembler);
//Console.WriteLine("assembled {0} next sync byte is {1}", sucessfulAssembles++,syncByte);
if (sucessfulAssembles == 181)
{
int payloadSize = (int)gseNeededBuffer.Position;
gseNeededBuffer.Position = 0;
byte[] payloadBuffer = gseNeededBuffer.ReadBytes(payloadSize);
}
gseAssembler = null;
HandleGse(ms);
return;
}
else if (assemblyState == GseAssemblyState.BROKEN_SUSPECT_ETHERTYPE)
{
gseAssembler = null;
HandleGse(ms);
return;
}
else if (assemblyState == GseAssemblyState.BROKEN_NEGATIVE_LENGTH)
{
gseAssembler = null;
HandleGse(ms);
return;
}
else
{
throw new NotImplementedException(String.Format("Unknown GSE assembler state: {0}, sync byte 0x{1}", assemblyState, syncByte));
}
}
private long sucessfulAssembles;
enum GseAssemblyState
{
NOT_YET_BEGUN,
VALID,
BROKEN_NEGATIVE_LENGTH,
NEED_MORE_DATA,
BROKEN_SUSPECT_LENGTH,
BROKEN_SUSPECT_ETHERTYPE
}
private GseAssemblyState ValidateGse(MemoryStream ms)
{
if (ms == null)
return GseAssemblyState.NOT_YET_BEGUN;
long backupPosition = ms.Position;
ms.Position = 0;
while (ms.GetAvailableBytes() > 2)
{
//GSE-Header
byte byteA = ms.ReadUInt8();
bool startIndicator = (byteA & 0x80) != 0;
bool endIndicator = (byteA & 0x40) != 0;
int labelIndicator = (byteA & 0x30) >> 4;
if (!startIndicator && !endIndicator && labelIndicator == 0)
{
//end of base band frame
ms.Position = backupPosition;
return GseAssemblyState.VALID;
}
else
{
byte byteB = ms.ReadUInt8();
int gseLength = byteA & 0x0f;
gseLength <<= 8;
gseLength += byteB;
//Console.WriteLine("GSE Length: {0}", gseLength);
if (gseLength > 9000)
{
ms.Position = backupPosition;
return GseAssemblyState.BROKEN_SUSPECT_LENGTH;
}
if (!startIndicator || !endIndicator)
{
byte fragId = ms.ReadUInt8();
gseLength--;
}
if (startIndicator && !endIndicator)
{
ushort totalLength = ms.ReadUInt16BE();
gseLength -= 2;
}
if (startIndicator)
{
if (2 > ms.GetAvailableBytes())
{
ms.Position = backupPosition;
return GseAssemblyState.NEED_MORE_DATA;
}
ushort protocolType = ms.ReadUInt16BE();
if (!ValidateEthertype(protocolType))
{
ms.Position = backupPosition;
return GseAssemblyState.BROKEN_SUSPECT_ETHERTYPE;
}
gseLength -= 2;
if (labelIndicator == 0)
{
if (6 > ms.GetAvailableBytes())
{
ms.Position = backupPosition;
return GseAssemblyState.NEED_MORE_DATA;
}
PhysicalAddress sixByteLabel = new PhysicalAddress(ms.ReadBytes(6));
gseLength -= 6;
}
else if (labelIndicator == 1)
{
byte[] threeByteLabel = ms.ReadBytes(3);
gseLength -= 3;
}
}
if (!startIndicator && endIndicator)
gseLength -= 4;
int startCrc32 = (int)ms.Position;
if (gseLength < 0)
{
ms.Position = backupPosition;
return GseAssemblyState.BROKEN_NEGATIVE_LENGTH;
}
if (gseLength > ms.GetAvailableBytes())
{
ms.Position = backupPosition;
return GseAssemblyState.NEED_MORE_DATA;
}
ms.Position += gseLength;
if (!startIndicator && endIndicator)
{
uint crc32 = ms.ReadUInt32BE();
int endCrc32 = (int)ms.Position;
DvbCrc32.ValidateCrc(ms, startCrc32, endCrc32);
}
}
}
ms.Position = backupPosition;
return GseAssemblyState.VALID;
}
private bool ValidateEthertype(ushort ethertype)
{
if (ethertype == 0x0800)
return true; //IPv4
if (ethertype == 0x86DD)
return true; //IPv6
else
return false; //There are many more valid values, but since we don't speak anything aside from IPv4/IPv6, we discard it.
}
private void AssembleGse(MemoryStream ms)
{
ushort protocolType = 0;
while (ms.GetAvailableBytes() > 2)
{
//GSE-Header
@ -98,7 +266,7 @@ namespace skyscraper8.Skyscraper
int gseLength = byteA & 0x0f;
gseLength <<= 8;
gseLength += byteB;
if (!startIndicator || !endIndicator)
{
byte fragId = ms.ReadUInt8();
@ -113,7 +281,7 @@ namespace skyscraper8.Skyscraper
if (startIndicator)
{
ushort protocolType = ms.ReadUInt16BE();
protocolType = ms.ReadUInt16BE();
gseLength -= 2;
if (labelIndicator == 0)
{
@ -131,15 +299,7 @@ namespace skyscraper8.Skyscraper
gseLength -= 4;
int startCrc32 = (int)ms.Position;
if (gseLength > ms.GetAvailableBytes())
{
gseNeeded = gseLength;
gseNeededBuffer = new MemoryStream();
gseNeeded -= (int)ms.GetAvailableBytes();
gseNeededBuffer.Write(ms.ReadBytes(ms.GetAvailableBytes()));
return;
}
byte[] payload = ms.ReadBytes(gseLength);
if (!startIndicator && endIndicator)
{
@ -148,9 +308,19 @@ namespace skyscraper8.Skyscraper
DvbCrc32.ValidateCrc(ms, startCrc32, endCrc32);
}
switch (protocolType)
{
case 0x0800: //IPv4
MpeEventHandler.OnIpDatagram(PID, payload);
break;
default:
//throw new NotImplementedException(String.Format("Unknown GSE Protocol ID 0x{0:X4}", protocolType));
break;
}
}
}
}
}
}

View File

@ -40,36 +40,13 @@ namespace skyscraper5.src.Skyscraper
{
byte[] chi = outbuf.ToArray();
if (deencapsulator == null)
{
deencapsulator = new BbframeDeencapsulator();
deencapsulator.MpeEventHandler = mpeEventHandler;
deencapsulator.PID = pid;
}
deencapsulator.PushPacket(chi);
/*List<byte[]> ipPackets = IpPacketFinder.LookForIpPackets(outbuf.ToArray());
if (ipPackets != null)
{
foreach (byte[] ipPacket in ipPackets)
{
mpeEventHandler.OnIpDatagram(0x118, ipPacket);
packetsRecovered++;
}
}
else
{
packetsLost++;
}*/
/*byte[] ipPacket = IpPacketFinder.LookForIpPacket(outbuf.ToArray(), 32);
if (ipPacket != null)
{
if (!annoncementDone)
{
mpeEventHandler.GsIpTrafficDetected();
annoncementDone = true;
}
mpeEventHandler.OnIpDatagram(0x0118, ipPacket);
packetsRecovered++;
}
else
{
packetsLost++;
}*/
}
outbuf = new MemoryStream();
outbuf.Write(packets,9, packets[7] - 1);