COMMANDS
~/Downloads/arduino-ide_2.3.4_Linux_64bit.AppImage &> /dev/null sudo apt install python3-pip pip3 install pyserial sudo usermod -aG userName dialout sudo chmod a+rw /dev/ttyUSB0
EXAMPLES
(1) HTTP API Endpoints with JSON
// ESP32-WROOM-32U
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
// WiFi credentials
const char* ssid = "wifi_name";
const char* password = "wifi_password";
// Create a WebServer object on port 80
WebServer server(80);
// Handler for "/"
void handleRoot() {
String body = "<!DOCTYPE html><html><head><title>ESP32</title></head><body>";
body += "<h1>ESP32 HTTP Server!</h1>\n\n";
body += "<a href=\"/status\">Show Status</a><br>\n";
body += "<a href=\"/push\">Push Status</a><br>\n";
body += "<a href=\"/serial\">Output Status</a><br>\n";
body += "</body></html>";
server.send(200, "text/html", body);
Serial.println("Client IP: " + server.client().remoteIP().toString());
}
String getStatusJson() {
StaticJsonDocument<512> jsonData;
jsonData["wifi_connected"] = String(WiFi.status() == WL_CONNECTED ? "true" : "false");
jsonData["signal_strength"] = String(WiFi.RSSI());
jsonData["ssid"] = WiFi.SSID();
jsonData["ip"] = WiFi.localIP().toString();
jsonData["uptime"] = String(millis() / 1000);
jsonData["free_heap"] = String(ESP.getFreeHeap());
jsonData["chip_model"] = String(ESP.getChipModel());
jsonData["flash_size"] = String(ESP.getFlashChipSize());
String jsonString;
serializeJson(jsonData, jsonString);
return jsonString;
}
void pushNotification(const String &message = "") {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin("http://ntfy.sh/subscription_topic");
http.addHeader("Content-Type", "application/json");
String payload;
if (message.length() > 0) {
payload = message;
} else {
payload = getStatusJson();
}
int httpResponseCode = http.POST(payload);
if (httpResponseCode == 200) {
Serial.println("Push notification succeeded!");
} else {
Serial.println("Push failed with error: " + String(httpResponseCode));
}
http.end();
}
}
// Handler for "/status"
void handleStatus() {
server.send(200, "application/json", getStatusJson());
}
// Handler for "/push"
void handlePush() {
pushNotification();
server.send(200, "text/plain", "");
}
// Handler for "/serial"
void handleSerial() {
Serial.println(getStatusJson());
server.send(200, "text/plain", "");
}
// Handler for 404
void handleNotFound() {
server.send(404, "text/plain", "404: Not Found");
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("");
Serial.println("Serial Started");
Serial.println("Starting WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting...");
}
Serial.println("Connected to WiFi!");
Serial.println("IP Address: " + WiFi.localIP().toString());
// Define URL routes
server.on("/", handleRoot);
server.on("/status", handleStatus);
server.on("/push", handlePush);
server.on("/serial", handleSerial);
server.onNotFound(handleNotFound);
// Start the server
server.begin();
Serial.println("HTTP server started");
// Send push notification with IP address
StaticJsonDocument<48> jsonData;
jsonData["ip"] = WiFi.localIP().toString();
String jsonString;
serializeJson(jsonData, jsonString);
pushNotification(jsonString);
}
void loop() {
server.handleClient();
}
(2) A TCP/UDP Honey-Pot named Albedu0
Albedo is the property of a material to absorb or reflect radiation. So, when the albedo value is close to 1, it reflects almost the totality. When close to zero, it does not reflect anything.
Analogously, this honey-pot does not respond on the application layer (after the TCP 3-way handshake) but instead notifies the network administrator that someone is probing it.
// ESP32-WROOM-32U - Albedu0
#include <WiFi.h>
#include <WiFiUdp.h>
#include <HTTPClient.h>
const char* ssid = "wifi_name";
const char* password = "wifi_password";
const char* ntfyUrl = "http://ntfy.sh/subscription_topic";
const uint16_t tcpPorts[] = {21, 22, 23, 80, 445, 3389, 8080};
const uint16_t udpPorts[] = {53, 123, 161, 1900};
constexpr size_t N_TCP = sizeof(tcpPorts) / sizeof(tcpPorts[0]);
constexpr size_t N_UDP = sizeof(udpPorts) / sizeof(udpPorts[0]);
WiFiServer* tcpSrv[N_TCP];
WiFiUDP udpSrv[N_UDP];
uint32_t hitCount = 0;
String toHex(const uint8_t* b, size_t n) {
String s;
for (size_t i = 0; i < n; i++) {
if (b[i] < 0x10) s += '0';
s += String(b[i], HEX);
if (i + 1 < n) s += ' ';
}
return s;
}
String toAscii(const uint8_t* b, size_t n) {
String s;
for (size_t i = 0; i < n; i++) s += (b[i] >= 32 && b[i] < 127) ? (char)b[i] : '.'; return s; } void snitch(const String& proto, const IPAddress& src, uint16_t sport, uint16_t dport, const uint8_t* data, size_t len) { hitCount++; String body; body += "proto=" + proto + "\n"; body += "src=" + src.toString() + ":" + String(sport) + "\n"; body += "dst=" + WiFi.localIP().toString() + ":" + String(dport) + "\n"; body += "bytes=" + String(len) + "\n"; if (len > 0) {
body += "hex=" + toHex(data, len) + "\n";
body += "ascii=" + toAscii(data, len) + "\n";
}
body += "rssi=" + String(WiFi.RSSI()) + "dBm\n";
body += "uptime=" + String(millis() / 1000) + "s\n";
body += "hit#" + String(hitCount);
Serial.println("---- HIT ----");
Serial.println(body);
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(ntfyUrl);
http.addHeader("Title", "Honeypot " + proto + " :" + String(dport));
http.addHeader("Tags", "warning");
http.addHeader("Priority", "high");
int code = http.POST(body);
Serial.println("ntfy -> " + String(code));
http.end();
}
}
// TCP
void pollTcp() {
for (size_t i = 0; i < N_TCP; i++) { WiFiClient c = tcpSrv[i]->accept();
if (!c) continue;
IPAddress src = c.remoteIP();
uint16_t sport = c.remotePort();
uint8_t buf[64];
size_t len = 0;
unsigned long t0 = millis();
while (millis() - t0 < 80 && len < sizeof(buf)) {
while (c.available() && len < sizeof(buf)) buf[len++] = c.read();
if (!c.connected()) break;
delay(5);
}
c.stop();
snitch("TCP", src, sport, tcpPorts[i], buf, len);
}
}
// UDP
void pollUdp() {
for (size_t i = 0; i < N_UDP; i++) {
int sz = udpSrv[i].parsePacket();
if (sz <= 0) continue;
IPAddress src = udpSrv[i].remoteIP();
uint16_t sport = udpSrv[i].remotePort();
uint8_t buf[64];
int len = udpSrv[i].read(buf, sizeof(buf));
if (len < 0) len = 0;
snitch("UDP", src, sport, udpPorts[i], buf, len);
}
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\nHoneypot booting");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nWiFi up: " + WiFi.localIP().toString());
for (size_t i = 0; i < N_TCP; i++) { tcpSrv[i] = new WiFiServer(tcpPorts[i]); tcpSrv[i]->begin();
tcpSrv[i]->setNoDelay(true);
}
for (size_t i = 0; i < N_UDP; i++) udpSrv[i].begin(udpPorts[i]);
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(ntfyUrl);
http.addHeader("Title", "Honeypot online");
http.POST("watching " + WiFi.localIP().toString());
http.end();
}
Serial.println("Listening.");
}
void loop() {
if (WiFi.status() != WL_CONNECTED) { WiFi.reconnect(); delay(500); return; }
pollTcp();
pollUdp();
}
DOCUMENTATION
ONLINE SERVICES
ntfy (pronounced “notify”) is a simple HTTP-based pub-sub notification service that sends alerts to your phone or desktop [Link]. It is open-source and can be self-hosted [Link].
healthchecks.io is an open-source, HTTP-based monitoring tool that collects events from multiple sources, displays them in a single dashboard, and sends notifications for failures or missing events [Link]. Read more about self-hosting it at [Link].