mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-09 14:42:05 +00:00
Use IPAddress.fromString for parsing private IPs (#5621)
This commit is contained in:
parent
960626e498
commit
58d80b8557
@ -26,6 +26,14 @@
|
|||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <IPAddress.h>
|
||||||
|
#if defined(ARCH_PORTDUINO)
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#elif !defined(ntohl)
|
||||||
|
#include <machine/endian.h>
|
||||||
|
#define ntohl __ntohl
|
||||||
|
#endif
|
||||||
|
|
||||||
MQTT *mqtt;
|
MQTT *mqtt;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -196,6 +204,29 @@ inline void onReceiveJson(byte *payload, size_t length)
|
|||||||
LOG_DEBUG("JSON ignore downlink message with unsupported type");
|
LOG_DEBUG("JSON ignore downlink message with unsupported type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines if the given IPAddress is a private IPv4 address, i.e. not routable on the public internet.
|
||||||
|
bool isPrivateIpAddress(const IPAddress &ip)
|
||||||
|
{
|
||||||
|
constexpr struct {
|
||||||
|
uint32_t network;
|
||||||
|
uint32_t mask;
|
||||||
|
} privateCidrRanges[] = {
|
||||||
|
{.network = 192u << 24 | 168 << 16, .mask = 0xffff0000}, // 192.168.0.0/16
|
||||||
|
{.network = 172u << 24 | 16 << 16, .mask = 0xfff00000}, // 172.16.0.0/12
|
||||||
|
{.network = 169u << 24 | 254 << 16, .mask = 0xffff0000}, // 169.254.0.0/16
|
||||||
|
{.network = 10u << 24, .mask = 0xff000000}, // 10.0.0.0/8
|
||||||
|
{.network = 127u << 24 | 1, .mask = 0xffffffff}, // 127.0.0.1/32
|
||||||
|
};
|
||||||
|
const uint32_t addr = ntohl(ip);
|
||||||
|
for (const auto &cidrRange : privateCidrRanges) {
|
||||||
|
if (cidrRange.network == (addr & cidrRange.mask)) {
|
||||||
|
LOG_INFO("MQTT server on a private IP");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
|
void MQTT::mqttCallback(char *topic, byte *payload, unsigned int length)
|
||||||
@ -270,10 +301,8 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
|
|||||||
moduleConfig.mqtt.map_report_settings.publish_interval_secs, default_map_publish_interval_secs);
|
moduleConfig.mqtt.map_report_settings.publish_interval_secs, default_map_publish_interval_secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
isMqttServerAddressPrivate = isPrivateIpAddress(moduleConfig.mqtt.address);
|
IPAddress ip;
|
||||||
if (isMqttServerAddressPrivate) {
|
isMqttServerAddressPrivate = ip.fromString(moduleConfig.mqtt.address) && isPrivateIpAddress(ip);
|
||||||
LOG_INFO("MQTT server on a private IP");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HAS_NETWORKING
|
#if HAS_NETWORKING
|
||||||
if (!moduleConfig.mqtt.proxy_to_client_enabled)
|
if (!moduleConfig.mqtt.proxy_to_client_enabled)
|
||||||
@ -717,69 +746,3 @@ void MQTT::perhapsReportToMap()
|
|||||||
// Update the last report time
|
// Update the last report time
|
||||||
last_report_to_map = millis();
|
last_report_to_map = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MQTT::isPrivateIpAddress(const char address[])
|
|
||||||
{
|
|
||||||
// Min. length like 10.0.0.0 (8), max like 192.168.255.255:65535 (21)
|
|
||||||
size_t length = strlen(address);
|
|
||||||
if (length < 8 || length > 21) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure the address contains only digits and dots and maybe a colon.
|
|
||||||
// Some limited validation is done.
|
|
||||||
// Even if it's not a valid IP address, we will know it's not a domain.
|
|
||||||
bool hasColon = false;
|
|
||||||
int numDots = 0;
|
|
||||||
for (size_t i = 0; i < length; i++) {
|
|
||||||
if (!isdigit(address[i]) && address[i] != '.' && address[i] != ':') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dots can't be the first character, immediately follow another dot,
|
|
||||||
// occur more than 3 times, or occur after a colon.
|
|
||||||
if (address[i] == '.') {
|
|
||||||
if (++numDots > 3 || i == 0 || address[i - 1] == '.' || hasColon) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// There can only be a single colon, and it can only occur after 3 dots
|
|
||||||
else if (address[i] == ':') {
|
|
||||||
if (hasColon || numDots < 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasColon = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final validation for IPv4 address and port format.
|
|
||||||
// Note that the values of octets haven't been tested, only the address format.
|
|
||||||
if (numDots != 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the easy ones first.
|
|
||||||
if (strcmp(address, "127.0.0.1") == 0 || strncmp(address, "10.", 3) == 0 || strncmp(address, "192.168", 7) == 0 ||
|
|
||||||
strncmp(address, "169.254", 7) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if it's definitely not a 172 address.
|
|
||||||
if (strncmp(address, "172", 3) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We know it's a 172 address, now see if the second octet is 2 digits.
|
|
||||||
if (address[6] != '.') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the second octet into a secondary buffer we can null-terminate and parse.
|
|
||||||
char octet2[3];
|
|
||||||
strncpy(octet2, address + 4, 2);
|
|
||||||
octet2[2] = 0;
|
|
||||||
|
|
||||||
int octet2Num = atoi(octet2);
|
|
||||||
return octet2Num >= 16 && octet2Num <= 31;
|
|
||||||
}
|
|
||||||
|
@ -121,10 +121,6 @@ class MQTT : private concurrency::OSThread
|
|||||||
// Check if we should report unencrypted information about our node for consumption by a map
|
// Check if we should report unencrypted information about our node for consumption by a map
|
||||||
void perhapsReportToMap();
|
void perhapsReportToMap();
|
||||||
|
|
||||||
/// Determines if the given address is a private IPv4 address, i.e. not routable on the public internet.
|
|
||||||
/// These are the ranges: 127.0.0.1, 10.0.0.0-10.255.255.255, 172.16.0.0-172.31.255.255, 192.168.0.0-192.168.255.255.
|
|
||||||
bool isPrivateIpAddress(const char address[]);
|
|
||||||
|
|
||||||
/// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server
|
/// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server
|
||||||
// int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; }
|
// int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; }
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user