Skip to content

Commit

Permalink
Merge pull request Aircoookie#3536 from Aircoookie/ntp_errorchecking
Browse files Browse the repository at this point in the history
NTP validation, and rejecting malformed responses (related to Aircoookie#3515)
  • Loading branch information
softhack007 committed Nov 22, 2023
1 parent d3d08f8 commit ab309b3
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 10 deletions.
3 changes: 2 additions & 1 deletion wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@
#define NL_MODE_SUN 3 //Sunrise/sunset. Target brightness is set immediately, then Sunrise effect is started. Max 60 min.


#define NTP_PACKET_SIZE 48
#define NTP_PACKET_SIZE 48 // size of NTP recive buffer
#define NTP_MIN_PACKET_SIZE 48 // min expected size - NTP v4 allows for "extended information" appended to the standard fields

//maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses
#ifndef MAX_LEDS
Expand Down
31 changes: 26 additions & 5 deletions wled00/ntp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ void handleNetworkTime()
{
if (millis() - ntpPacketSentTime > 10000)
{
#ifdef ARDUINO_ARCH_ESP32 // I had problems using udp.flush() on 8266
while (ntpUdp.parsePacket() > 0) ntpUdp.flush(); // flush any existing packets
#endif
sendNTPPacket();
ntpPacketSentTime = millis();
}
Expand Down Expand Up @@ -239,23 +242,41 @@ void sendNTPPacket()
ntpUdp.endPacket();
}

static bool isValidNtpResponse(byte * ntpPacket) {
// Perform a few validity checks on the packet
// based on https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp
if((ntpPacket[0] & 0b11000000) == 0b11000000) return false; //reject LI=UNSYNC
// if((ntpPacket[0] & 0b00111000) >> 3 < 0b100) return false; //reject Version < 4
if((ntpPacket[0] & 0b00000111) != 0b100) return false; //reject Mode != Server
if((ntpPacket[1] < 1) || (ntpPacket[1] > 15)) return false; //reject invalid Stratum
if( ntpPacket[16] == 0 && ntpPacket[17] == 0 &&
ntpPacket[18] == 0 && ntpPacket[19] == 0 &&
ntpPacket[20] == 0 && ntpPacket[21] == 0 &&
ntpPacket[22] == 0 && ntpPacket[23] == 0) //reject ReferenceTimestamp == 0
return false;

return true;
}

bool checkNTPResponse()
{
#ifdef ARDUINO_ARCH_ESP32
ntpUdp.flush();
#endif
int cb = ntpUdp.parsePacket();
#ifdef ARDUINO_ARCH_ESP32
if (!cb) {ntpUdp.flush(); return false;} // WLEDMM flush buffer
#else
if (!cb) {return false;} // WLEDMM do not flush buffer
#endif
if (cb < NTP_MIN_PACKET_SIZE) {
#ifdef ARDUINO_ARCH_ESP32 // I had problems using udp.flush() on 8266
if (cb > 0) ntpUdp.flush(); // this avoids memory leaks on esp32
#endif
return false;
}

uint32_t ntpPacketReceivedTime = millis();
DEBUG_PRINT(F("NTP recv, l="));
DEBUG_PRINTLN(cb);
byte pbuf[NTP_PACKET_SIZE];
ntpUdp.read(pbuf, NTP_PACKET_SIZE); // read the packet into the buffer
if (!isValidNtpResponse(pbuf)) return false; // verify we have a valid response to client

Toki::Time arrived = toki.fromNTP(pbuf + 32);
Toki::Time departed = toki.fromNTP(pbuf + 40);
Expand Down
2 changes: 1 addition & 1 deletion wled00/set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)

//start ntp if not already connected
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
ntpLastSyncTime = 0; // force new NTP query
ntpLastSyncTime = NTP_NEVER; // force new NTP query

longitude = request->arg(F("LN")).toFloat();
latitude = request->arg(F("LT")).toFloat();
Expand Down
2 changes: 1 addition & 1 deletion wled00/wled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ void WLED::loop()
if (lastMqttReconnectAttempt > millis()) {
rolloverMillis++;
lastMqttReconnectAttempt = 0;
ntpLastSyncTime = 0;
ntpLastSyncTime = NTP_NEVER; // force new NTP query
strip.restartRuntime();
}
if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) { // lastMqttReconnectAttempt==0 forces immediate broadcast
Expand Down
5 changes: 3 additions & 2 deletions wled00/wled.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,10 +670,11 @@ WLED_GLOBAL String escapedMac;
WLED_GLOBAL DNSServer dnsServer;

// network time
#define NTP_NEVER 999000000L
WLED_GLOBAL bool ntpConnected _INIT(false);
WLED_GLOBAL time_t localTime _INIT(0);
WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(999000000L);
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
WLED_GLOBAL unsigned long ntpLastSyncTime _INIT(NTP_NEVER);
WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(NTP_NEVER);
WLED_GLOBAL IPAddress ntpServerIP;
WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390);
WLED_GLOBAL uint16_t rolloverMillis _INIT(0);
Expand Down

0 comments on commit ab309b3

Please sign in to comment.