DDP input: reject packets with unsupported data type or non-display destination (#5390)
* Fix: reject invalid DDP packets with wrong destination or unsupported data type Co-authored-by: DedeHai <6280424+DedeHai@users.noreply.github.com>
This commit is contained in:
@@ -187,7 +187,7 @@ function sendDDP(ws, start, len, colors) {
|
|||||||
pkt[0] = 0x02; // DDP protocol indicator for WLED websocket. Note: below DDP protocol bytes are offset by 1
|
pkt[0] = 0x02; // DDP protocol indicator for WLED websocket. Note: below DDP protocol bytes are offset by 1
|
||||||
pkt[1] = 0x40; // flags: 0x40 = no push, 0x41 = push (i.e. render), note: this is DDP protocol byte 0
|
pkt[1] = 0x40; // flags: 0x40 = no push, 0x41 = push (i.e. render), note: this is DDP protocol byte 0
|
||||||
pkt[2] = 0x00; // reserved
|
pkt[2] = 0x00; // reserved
|
||||||
pkt[3] = 0x01; // 1 = RGB (currently only supported mode)
|
pkt[3] = 0x0B; // RGB, 8bit per channel
|
||||||
pkt[4] = 0x01; // destination id (not used but 0x01 is default output)
|
pkt[4] = 0x01; // destination id (not used but 0x01 is default output)
|
||||||
pkt[5] = (off >> 24) & 255; // DDP protocol 4-7 is offset
|
pkt[5] = (off >> 24) & 255; // DDP protocol 4-7 is offset
|
||||||
pkt[6] = (off >> 16) & 255;
|
pkt[6] = (off >> 16) & 255;
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ void handleDDPPacket(e131_packet_t* p) {
|
|||||||
static bool ddpSeenPush = false; // have we seen a push yet?
|
static bool ddpSeenPush = false; // have we seen a push yet?
|
||||||
[[maybe_unused]] int lastPushSeq = e131LastSequenceNumber[0];
|
[[maybe_unused]] int lastPushSeq = e131LastSequenceNumber[0];
|
||||||
|
|
||||||
|
// reject unsupported color data types (only RGB and RGBW are supported)
|
||||||
|
// WLEDMM allow legacy "undefined" datatype, and legacy (but wrong) datatype=0x01
|
||||||
|
if ( p->dataType != 0 && p->dataType != 0x01 &&
|
||||||
|
p->dataType != DDP_TYPE_RGB24 && p->dataType != DDP_TYPE_RGBW32) return;
|
||||||
|
|
||||||
|
// reject status and config packets (not implemented)
|
||||||
|
if (p->destination == DDP_ID_STATUS || p->destination == DDP_ID_CONFIG) return;
|
||||||
|
|
||||||
//reject late packets belonging to previous frame (assuming 4 packets max. before push)
|
//reject late packets belonging to previous frame (assuming 4 packets max. before push)
|
||||||
#if 0 // WLEDMM fixme - we definitely have more than 5-10 packets per frame !!!
|
#if 0 // WLEDMM fixme - we definitely have more than 5-10 packets per frame !!!
|
||||||
if (e131SkipOutOfSequence && lastPushSeq) {
|
if (e131SkipOutOfSequence && lastPushSeq) {
|
||||||
@@ -41,8 +49,8 @@ void handleDDPPacket(e131_packet_t* p) {
|
|||||||
uint16_t dataLen = htons(p->dataLen);
|
uint16_t dataLen = htons(p->dataLen);
|
||||||
unsigned stop = start + dataLen / ddpChannelsPerLed;
|
unsigned stop = start + dataLen / ddpChannelsPerLed;
|
||||||
uint8_t* data = p->data;
|
uint8_t* data = p->data;
|
||||||
uint16_t c = 0;
|
unsigned c = 0;
|
||||||
if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later
|
if (p->flags & DDP_FLAGS_TIME) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later
|
||||||
|
|
||||||
unsigned numLeds = stop - start; // stop >= start is guaranteed
|
unsigned numLeds = stop - start; // stop >= start is guaranteed
|
||||||
unsigned maxDataIndex = c + numLeds * ddpChannelsPerLed; // validate bounds before accessing data array
|
unsigned maxDataIndex = c + numLeds * ddpChannelsPerLed; // validate bounds before accessing data array
|
||||||
@@ -67,7 +75,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool push = p->flags & DDP_PUSH_FLAG;
|
bool push = p->flags & DDP_FLAGS_PUSH;
|
||||||
ddpSeenPush |= push;
|
ddpSeenPush |= push;
|
||||||
if (!ddpSeenPush || push) { // if we've never seen a push, or this is one, render display
|
if (!ddpSeenPush || push) { // if we've never seen a push, or this is one, render display
|
||||||
#ifdef WLED_DEBUG
|
#ifdef WLED_DEBUG
|
||||||
|
|||||||
@@ -49,13 +49,26 @@ typedef struct ip_addr ip4_addr_t;
|
|||||||
#define E131_DEFAULT_PORT 5568
|
#define E131_DEFAULT_PORT 5568
|
||||||
#define ARTNET_DEFAULT_PORT 6454
|
#define ARTNET_DEFAULT_PORT 6454
|
||||||
#define DDP_DEFAULT_PORT 4048
|
#define DDP_DEFAULT_PORT 4048
|
||||||
|
#define DDP_HEADER_LEN 10
|
||||||
|
#define DDP_SYNCPACKET_LEN 10
|
||||||
|
|
||||||
#define DDP_PUSH_FLAG 0x01
|
#define DDP_FLAGS_VER 0xc0 // version mask
|
||||||
#define DDP_TIMECODE_FLAG 0x10
|
#define DDP_FLAGS_VER1 0x40 // version=1
|
||||||
|
#define DDP_FLAGS_PUSH 0x01
|
||||||
|
#define DDP_FLAGS_QUERY 0x02
|
||||||
|
#define DDP_FLAGS_REPLY 0x04
|
||||||
|
#define DDP_FLAGS_STORAGE 0x08
|
||||||
|
#define DDP_FLAGS_TIME 0x10
|
||||||
|
|
||||||
|
#define DDP_CHANNELS_PER_PACKET 1440 // 480 leds
|
||||||
|
|
||||||
#define DDP_TYPE_RGB24 0x0B // 00 001 011 (RGB , 8 bits per channel, 3 channels)
|
#define DDP_TYPE_RGB24 0x0B // 00 001 011 (RGB , 8 bits per channel, 3 channels)
|
||||||
#define DDP_TYPE_RGBW32 0x1B // 00 011 011 (RGBW, 8 bits per channel, 4 channels)
|
#define DDP_TYPE_RGBW32 0x1B // 00 011 011 (RGBW, 8 bits per channel, 4 channels)
|
||||||
|
|
||||||
|
#define DDP_ID_DISPLAY 1
|
||||||
|
#define DDP_ID_CONFIG 250
|
||||||
|
#define DDP_ID_STATUS 251
|
||||||
|
|
||||||
#define ARTNET_OPCODE_OPDMX 0x5000
|
#define ARTNET_OPCODE_OPDMX 0x5000
|
||||||
#define ARTNET_OPCODE_OPPOLL 0x2000
|
#define ARTNET_OPCODE_OPPOLL 0x2000
|
||||||
#define ARTNET_OPCODE_OPPOLLREPLY 0x2100
|
#define ARTNET_OPCODE_OPPOLLREPLY 0x2100
|
||||||
|
|||||||
@@ -799,24 +799,6 @@ void sendSysInfoUDP()
|
|||||||
* Art-Net, DDP, E131 output - work in progress
|
* Art-Net, DDP, E131 output - work in progress
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
#define DDP_HEADER_LEN 10
|
|
||||||
#define DDP_SYNCPACKET_LEN 10
|
|
||||||
|
|
||||||
#define DDP_FLAGS1_VER 0xc0 // version mask
|
|
||||||
#define DDP_FLAGS1_VER1 0x40 // version=1
|
|
||||||
#define DDP_FLAGS1_PUSH 0x01
|
|
||||||
#define DDP_FLAGS1_QUERY 0x02
|
|
||||||
#define DDP_FLAGS1_REPLY 0x04
|
|
||||||
#define DDP_FLAGS1_STORAGE 0x08
|
|
||||||
#define DDP_FLAGS1_TIME 0x10
|
|
||||||
|
|
||||||
#define DDP_ID_DISPLAY 1
|
|
||||||
#define DDP_ID_CONFIG 250
|
|
||||||
#define DDP_ID_STATUS 251
|
|
||||||
|
|
||||||
// 1440 channels per packet
|
|
||||||
#define DDP_CHANNELS_PER_PACKET 1440 // 480 leds
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Send real time UDP updates to the specified client
|
// Send real time UDP updates to the specified client
|
||||||
//
|
//
|
||||||
@@ -885,11 +867,11 @@ uint8_t IRAM_ATTR_YN realtimeBroadcast(uint8_t type, IPAddress client, uint16_t
|
|||||||
// the amount of data is AFTER the header in the current packet
|
// the amount of data is AFTER the header in the current packet
|
||||||
size_t packetSize = DDP_CHANNELS_PER_PACKET;
|
size_t packetSize = DDP_CHANNELS_PER_PACKET;
|
||||||
|
|
||||||
uint8_t flags = DDP_FLAGS1_VER1;
|
uint8_t flags = DDP_FLAGS_VER1;
|
||||||
if (currentPacket == (packetCount - 1U)) {
|
if (currentPacket == (packetCount - 1U)) {
|
||||||
// last packet, set the push flag
|
// last packet, set the push flag
|
||||||
// TODO: determine if we want to send an empty push packet to each destination after sending the pixel data
|
// TODO: determine if we want to send an empty push packet to each destination after sending the pixel data
|
||||||
flags = DDP_FLAGS1_VER1 | DDP_FLAGS1_PUSH;
|
flags = DDP_FLAGS_VER1 | DDP_FLAGS_PUSH;
|
||||||
if (channelCount % DDP_CHANNELS_PER_PACKET) {
|
if (channelCount % DDP_CHANNELS_PER_PACKET) {
|
||||||
packetSize = channelCount % DDP_CHANNELS_PER_PACKET;
|
packetSize = channelCount % DDP_CHANNELS_PER_PACKET;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
if (len < unsigned(10 + offset)) return; // DDP header is 10 bytes (+1 protocol byte)
|
if (len < unsigned(10 + offset)) return; // DDP header is 10 bytes (+1 protocol byte)
|
||||||
size_t ddpDataLen = (data[8+offset] << 8) | data[9+offset]; // data length in bytes from DDP header
|
size_t ddpDataLen = (data[8+offset] << 8) | data[9+offset]; // data length in bytes from DDP header
|
||||||
uint8_t flags = data[0+offset];
|
uint8_t flags = data[0+offset];
|
||||||
if ((flags & DDP_TIMECODE_FLAG) ) ddpDataLen += 4; // timecode flag adds 4 bytes to data length
|
if ((flags & DDP_FLAGS_TIME) ) ddpDataLen += 4; // timecode flag adds 4 bytes to data length
|
||||||
if (len < (10 + offset + ddpDataLen)) return; // not enough data, prevent out of bounds read
|
if (len < (10 + offset + ddpDataLen)) return; // not enough data, prevent out of bounds read
|
||||||
// could be a valid DDP packet, forward to handler
|
// could be a valid DDP packet, forward to handler
|
||||||
handleE131Packet((e131_packet_t*)&data[offset], client->remoteIP(), P_DDP);
|
handleE131Packet((e131_packet_t*)&data[offset], client->remoteIP(), P_DDP);
|
||||||
|
|||||||
Reference in New Issue
Block a user