Skip to content

Instantly share code, notes, and snippets.

@The3ven
Last active October 9, 2025 04:23
Show Gist options
  • Select an option

  • Save The3ven/21d9befcd7f15b2b1bad522d8b486395 to your computer and use it in GitHub Desktop.

Select an option

Save The3ven/21d9befcd7f15b2b1bad522d8b486395 to your computer and use it in GitHub Desktop.
try to build a proxy to redirect to right endpoint i have mistekenly push in production
/*
ESP32 single-domain HTTP interceptor (target: example.com)
- Spoofs DNS only for "example.com" -> AP IP
- Receives HTTP requests from clients, logs them (plain text)
- Fetches response from real backend and returns to client
- No HTTPS handling. Other domains ignored.
#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <WiFiUdp.h>
#include <DNSServer.h>
// -------- CONFIG --------
const char *apSSID = "oright";
const char *apPass = "oright1234";
const bool startSTA = true;
const char *staSSID = "firmwareK";
const char *staPass = "adminK1234";
// Domain to intercept
const char *targetDomain = "oright";
// Real backend URL (HTTP)
const char *backendHost = "www.oright.in";
IPAddress apIP(192, 168, 4, 1);
IPAddress apNetmask(255, 255, 255, 0);
const uint16_t DNS_PORT = 53;
WiFiUDP Udp;
HTTPClient http;
WiFiClient client;
WebServer webServer(80);
DNSServer dnsServer;
uint8_t dnsBuf[512];
uint8_t dnsResp[512];
// ---------- DNS helpers ----------
int dnsReadName(const uint8_t *buf, int buflen, String &name)
{
int idx = 0;
name = "";
while (idx < buflen)
{
uint8_t len = buf[idx];
if (len == 0)
{
idx++;
break;
}
if ((len & 0xC0) == 0xC0)
{
idx += 2;
break;
}
if (idx != 0)
name += '.';
if (idx + 1 + len > buflen)
return -1;
for (int i = 0; i < len; ++i)
name += (char)buf[idx + 1 + i];
idx += (1 + len);
}
return idx;
}
void makeAResponse(const uint8_t *req, int reqLen, uint8_t *resp, int &respLen, IPAddress ip)
{
resp[0] = req[0];
resp[1] = req[1];
resp[2] = 0x81;
resp[3] = 0x80;
resp[4] = 0x00;
resp[5] = 0x01;
resp[6] = 0x00;
resp[7] = 0x01;
resp[8] = 0x00;
resp[9] = 0x00;
resp[10] = 0x00;
resp[11] = 0x00;
int qlen = reqLen - 12;
memcpy(resp + 12, req + 12, qlen);
int pos = 12 + qlen;
resp[pos++] = 0xC0;
resp[pos++] = 0x0C; // pointer to qname
resp[pos++] = 0x00;
resp[pos++] = 0x01; // TYPE A
resp[pos++] = 0x00;
resp[pos++] = 0x01; // CLASS IN
resp[pos++] = 0x00;
resp[pos++] = 0x00;
resp[pos++] = 0x00;
resp[pos++] = 60; // TTL
resp[pos++] = 0x00;
resp[pos++] = 0x04; // RDLENGTH
resp[pos++] = ip[0];
resp[pos++] = ip[1];
resp[pos++] = ip[2];
resp[pos++] = ip[3];
respLen = pos;
}
// ---------- HTTP helpers ----------
String readRequestBody()
{
if (webServer.hasArg("plain"))
return webServer.arg("plain");
if (webServer.args() > 0)
{
String body;
body.reserve(128);
for (uint8_t i = 0; i < webServer.args(); ++i)
{
body += webServer.argName(i);
body += "=";
body += webServer.arg(i);
if (i + 1 < webServer.args())
body += "&";
}
return body;
}
return String();
}
// void handleClientRequest()
// {
// String method = (webServer.method() == HTTP_GET) ? "GET" : (webServer.method() == HTTP_POST) ? "POST"
// : (webServer.method() == HTTP_PUT) ? "PUT"
// : (webServer.method() == HTTP_DELETE) ? "DELETE"
// : "OTHER";
// String hostHeader = webServer.hostHeader();
// if (hostHeader.length() == 0)
// hostHeader = String(targetDomain);
// String uri = webServer.uri();
// String fullUrl = String("http://") + hostHeader + uri;
// IPAddress clientIp = webServer.client().remoteIP();
// // --- LOG PLAIN TEXT ---
// Serial.println("----- Client Request -----");
// Serial.print("Client IP: ");
// Serial.println(clientIp.toString());
// Serial.print("Method: ");
// Serial.println(method);
// Serial.print("Requested URL: ");
// Serial.println(fullUrl);
// if (webServer.headers() > 0)
// {
// Serial.println("Headers:");
// for (int i = 0; i < webServer.headers(); ++i)
// {
// Serial.print(" ");
// Serial.print(webServer.headerName(i));
// Serial.print(": ");
// Serial.println(webServer.header(i));
// }
// }
// String body = readRequestBody();
// if (body.length())
// {
// Serial.println("Body:");
// Serial.println(body);
// }
// Serial.println("--------------------------");
// // ---------- FETCH FROM BACKEND ----------
// String targetURL = String("http://") + backendHost + uri;
// Serial.printf("Fetching backend URL: %s\n", targetURL.c_str());
// http.setTimeout(5000); // optional
// http.begin(client, targetURL);
// int code = http.GET();
// Serial.printf("Backend response code: %d\n", code);
// if (code == 200)
// {
// WiFiClient *stream = http.getStreamPtr();
// String ct = http.header("Content-Type");
// if(ct.length() == 0) ct = "text/plain";
// Serial.printf("Backend Content-Type: %s\n", ct.c_str());
// webServer.sendHeader("Content-Type", ct); // or real content-type
// webServer.send(code);
// uint8_t buf[512];
// Serial.printf("Sending response to client...\n");
// int totalSent = 0;
// while (stream->connected() && (stream->available() || stream->availableForWrite()))
// {
// int len = stream->read(buf, sizeof(buf));
// totalSent += len;
// if (len > 0)
// {
// webServer.client().write(buf, len);
// Serial.printf("Sending ");
// Serial.write(buf, len);
// Serial.println();
// Serial.printf("Sent %d bytes (total %d bytes)\n", len, totalSent);
// }
// }
// }
// else
// {
// webServer.send(502, "text/plain", "Failed to fetch backend content");
// Serial.printf("Sent %d, text/plain, Failed to fetch backend content", 502);
// }
// http.end();
// }
void handleClientRequest()
{
String method = (webServer.method() == HTTP_GET) ? "GET" : (webServer.method() == HTTP_POST) ? "POST"
: (webServer.method() == HTTP_PUT) ? "PUT"
: (webServer.method() == HTTP_DELETE) ? "DELETE"
: "OTHER";
String hostHeader = webServer.hostHeader();
Serial.println("got header : " + hostHeader);
if (hostHeader.length() == 0)
{
hostHeader = String(targetDomain);
}
Serial.println("got header : " + hostHeader);
String uri = webServer.uri();
Serial.println("uri : " + uri);
String fullUrl = String("http://") + hostHeader + uri;
IPAddress clientIp = webServer.client().remoteIP();
// --- LOG PLAIN TEXT ---
Serial.println("----- Client Request -----");
Serial.print("Client IP: ");
Serial.println(clientIp.toString());
Serial.print("Method: ");
Serial.println(method);
Serial.print("Requested URL: ");
Serial.println(fullUrl);
if (webServer.headers() > 0)
{
Serial.println("Headers:");
for (int i = 0; i < webServer.headers(); ++i)
{
Serial.print(" ");
Serial.print(webServer.headerName(i));
Serial.print(": ");
Serial.println(webServer.header(i));
}
}
String body = readRequestBody();
if (body.length())
{
Serial.println("Body:");
Serial.println(body);
}
Serial.println("--------------------------");
// ---------- FETCH FROM BACKEND ----------
Serial.printf("requested url : %s\n", uri.c_str());
if (uri[0] != '/')
{
uri = String("/") + uri; // ensure leading slash
}
String targetURL = String("http://") + backendHost + uri;
Serial.printf("Fetching backend URL: %s\n", targetURL.c_str());
http.setTimeout(5000);
http.begin(client, targetURL);
int code = http.GET();
Serial.printf("Backend response code: %d\n", code);
if (code == 200)
{
String ct = http.header("Content-Type");
if (ct.length() == 0)
ct = "text/plain";
webServer.sendHeader("Content-Type", ct);
webServer.send(code); // send headers first
Serial.printf("Backend Content-Type: %s\n", ct.c_str());
Serial.printf("Sending response to client...\n");
WiFiClient *stream = http.getStreamPtr();
uint8_t buf[128]; // smaller chunk for LWIP safety
int totalSent = 0;
while (stream->connected() && stream->available())
{
int len = stream->read(buf, sizeof(buf));
if (len > 0)
{
totalSent += len;
webServer.client().write(buf, len);
delay(1); // tiny delay to prevent TCP flooding
Serial.printf("Sending ");
Serial.write(buf, len);
Serial.println();
Serial.printf("Sent %d bytes (total %d bytes)\n", len, totalSent);
}
}
Serial.println("Response sent to client safely.");
}
else
{
webServer.send(502, "text/plain", "Failed to fetch backend content");
Serial.println("Failed to fetch backend content");
}
http.end(); // reuse global instance safely
}
// ---------- SETUP ----------
void setup()
{
Serial.begin(115200);
delay(1500);
Serial.println("\n== ESP32 example.com interceptor ==");
// Start AP
WiFi.softAPConfig(apIP, apIP, apNetmask);
WiFi.softAP(apSSID, apPass);
Serial.printf("AP started: %s IP: %s\n", apSSID, WiFi.softAPIP().toString().c_str());
// Start STA for internet
if (startSTA)
{
WiFi.mode(WIFI_AP_STA);
WiFi.begin(staSSID, staPass);
Serial.print("Connecting STA...");
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 20000)
{
Serial.print(".");
delay(500);
}
if (WiFi.status() == WL_CONNECTED)
{
Serial.printf("\nSTA IP: %s\n", WiFi.localIP().toString().c_str());
}
else
{
Serial.println("\nSTA connect failed or timed out.");
}
}
else
{
WiFi.mode(WIFI_AP);
}
// Start UDP for DNS
if (!Udp.begin(DNS_PORT))
{
Serial.println("Failed to start UDP on port 53");
}
else
{
Serial.println("DNS responder listening on port 53");
}
// dnsServer.start(DNS_PORT, "*", apIP);
// Start HTTP server
webServer.onNotFound(handleClientRequest);
webServer.on("/", HTTP_ANY, handleClientRequest);
webServer.begin();
Serial.println("HTTP server started (interceptor/proxy)");
}
// ---------- LOOP ----------
void loop()
{
// DNS handler
int packetSize = Udp.parsePacket();
if (packetSize > 0)
{
int len = Udp.read(dnsBuf, sizeof(dnsBuf));
if (len > 12)
{
String qname;
int consumed = dnsReadName(dnsBuf + 12, len - 12, qname);
if (consumed > 0)
{
String qlower = qname;
qlower.toLowerCase();
if (qlower.indexOf(targetDomain) > -1)
{
int respLen;
makeAResponse(dnsBuf, len, dnsResp, respLen, apIP);
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(dnsResp, respLen);
Udp.endPacket();
Serial.printf("DNS: Spoofed %s -> %s\n", qname.c_str(), apIP.toString().c_str());
}
else
{
Serial.printf("DNS: Ignoring %s\n", qname.c_str());
}
}
}
}
webServer.handleClient();
// dnsServer.processNextRequest();
}
*/
/*
ESP32 Dual-Core Optimized HTTP Interceptor
-------------------------------------------
- Core0: DNS responder + optional forwarding
- Core1: HTTP interceptor/proxy
- Spoofs DNS only for targetDomain -> AP IP
- Forwards intercepted HTTP requests to real backend
- Designed for performance, non-blocking operation
*/
#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <WiFiUdp.h>
// ========== CONFIG ==========
const char *apSSID = "oright";
const char *apPass = "oright1234";
const bool startSTA = true;
const char *staSSID = "firmwareK";
const char *staPass = "adminK1234";
const char *targetDomain = "oright";
const char *backendHost = "www.oright.in";
IPAddress apIP(192, 168, 4, 1);
IPAddress apNetmask(255, 255, 255, 0);
const uint16_t DNS_PORT = 53;
WiFiUDP dnsUDP;
WebServer webServer(80);
HTTPClient http;
WiFiClient client;
// Buffers
uint8_t dnsBuf[512];
uint8_t dnsResp[512];
// ========== DNS HELPERS ==========
int dnsReadName(const uint8_t *buf, int buflen, String &name) {
int idx = 0; name = "";
while (idx < buflen) {
uint8_t len = buf[idx];
if (len == 0) { idx++; break; }
if ((len & 0xC0) == 0xC0) { idx += 2; break; }
if (idx != 0) name += '.';
if (idx + 1 + len > buflen) return -1;
for (int i = 0; i < len; ++i) name += (char)buf[idx + 1 + i];
idx += (1 + len);
}
return idx;
}
void makeAResponse(const uint8_t *req, int reqLen, uint8_t *resp, int &respLen, IPAddress ip) {
resp[0] = req[0]; resp[1] = req[1];
resp[2] = 0x81; resp[3] = 0x80;
resp[4] = 0x00; resp[5] = 0x01;
resp[6] = 0x00; resp[7] = 0x01;
memcpy(resp + 12, req + 12, reqLen - 12);
int pos = reqLen;
resp[pos++] = 0xC0; resp[pos++] = 0x0C;
resp[pos++] = 0x00; resp[pos++] = 0x01;
resp[pos++] = 0x00; resp[pos++] = 0x01;
resp[pos++] = 0x00; resp[pos++] = 0x00;
resp[pos++] = 0x00; resp[pos++] = 60;
resp[pos++] = 0x00; resp[pos++] = 0x04;
resp[pos++] = ip[0]; resp[pos++] = ip[1];
resp[pos++] = ip[2]; resp[pos++] = ip[3];
respLen = pos;
}
// ========== HTTP HANDLER ==========
void handleClientRequest() {
String uri = webServer.uri();
if (uri[0] != '/') uri = "/" + uri;
String targetURL = String("http://") + backendHost + uri;
Serial.printf("Forward: %s\n", targetURL.c_str());
WiFiClient backendClient;
HTTPClient backend;
backend.setTimeout(4000);
if (!backend.begin(backendClient, targetURL)) {
webServer.send(502, "text/plain", "Backend begin failed");
return;
}
int code = backend.GET();
if (code <= 0) {
webServer.send(502, "text/plain", "Backend GET failed");
backend.end();
return;
}
if (code == 400)
{
webClient.print("HTTP/1.1 400 Bad Request");
webClient.print("Server: awselb/2.0");
webClient.print("Date: Sun, 05 Oct 2025 21:31:02 GMT");
webClient.print("Content-Type: text/html");
webClient.print("Content-Length: 122");
webClient.print("Connection: close");
webClient.print("\n");
webClient.print("<html>");
webClient.print("<head><title>400 Bad Request</title></head>");
webClient.print("<body>");
webClient.print("<center><h1>400 Bad Request</h1></center>");
webClient.print("</body>");
webClient.print("</html>");
delay(10);
webClient.flush();
webClient.stop();
backend.end();
return;
}
// Get content-type
String contentType = backend.header("Content-Type");
if (contentType.isEmpty()) contentType = "text/plain";
// Get pointer to backend stream
WiFiClient* backendStream = backend.getStreamPtr();
// Get web client (active connection)
WiFiClient webClient = webServer.client();
// Manually send raw HTTP response headers to client:
// Note: we send Connection: close so client will expect EOF and not wait.
webClient.printf("HTTP/1.1 %d OK\r\n", code);
webClient.printf("Content-Type: %s\r\n", contentType.c_str());
webClient.print("Connection: close\r\n");
webClient.print("\r\n"); // end headers
// date Sun, 05 Oct 2025 21:41:28 GMT
// content-type text/plain
// content-length 58
// connection close
// last-modified Mon, 22 Sep 2025 08:58:58 GMT
// accept-ranges bytes
// etag "d091f7219f2bdc1:0"
// x-powered-by ASP.NET
// access-control-allow-origin *
// access-control-allow-headers x-requested-with, Content-Type, origin, authorization, accept, client-securit
// Stream backend response directly to client until backend closes or no data.
uint8_t buffer[512];
while (backendStream->connected() || backendStream->available()) {
int r = backendStream->read(buffer, sizeof(buffer));
if (r > 0) {
webClient.write(buffer, r);
} else {
// avoid busy spin
delay(1);
}
}
// Make sure everything is flushed then close connection
webClient.flush();
webClient.stop();
backend.end();
}
// ========== TASKS ==========
void dnsTask(void *param) {
Serial.println("[DNS] Task started on core " + String(xPortGetCoreID()));
for (;;) {
int packetSize = dnsUDP.parsePacket();
if (packetSize > 0) {
int len = dnsUDP.read(dnsBuf, sizeof(dnsBuf));
if (len > 12) {
String qname;
int consumed = dnsReadName(dnsBuf + 12, len - 12, qname);
if (consumed > 0) {
qname.toLowerCase();
if (qname.indexOf(targetDomain) > -1) {
int respLen;
makeAResponse(dnsBuf, len, dnsResp, respLen, apIP);
dnsUDP.beginPacket(dnsUDP.remoteIP(), dnsUDP.remotePort());
dnsUDP.write(dnsResp, respLen);
dnsUDP.endPacket();
Serial.printf("[DNS] Spoofed %s -> %s\n", qname.c_str(), apIP.toString().c_str());
}
}
}
}
vTaskDelay(1); // yield to scheduler
}
}
void httpTask(void *param) {
Serial.println("[HTTP] Task started on core " + String(xPortGetCoreID()));
for (;;) {
webServer.handleClient();
vTaskDelay(1);
}
}
// ========== SETUP ==========
void setup() {
Serial.begin(115200);
delay(1000);
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(apIP, apIP, apNetmask);
WiFi.softAP(apSSID, apPass);
Serial.printf("AP: %s | IP: %s\n", apSSID, WiFi.softAPIP().toString().c_str());
if (startSTA) {
WiFi.begin(staSSID, staPass);
Serial.print("Connecting STA");
unsigned long t0 = millis();
while (WiFi.status() != WL_CONNECTED && millis() - t0 < 15000) {
delay(500); Serial.print(".");
}
Serial.println((WiFi.status() == WL_CONNECTED) ? "\nSTA Connected" : "\nSTA Failed");
}
if (!dnsUDP.begin(DNS_PORT)) Serial.println("DNS UDP start failed!");
else Serial.println("DNS UDP started on port 53");
webServer.onNotFound(handleClientRequest);
webServer.begin();
Serial.println("HTTP server started");
// Spawn dual-core tasks
xTaskCreatePinnedToCore(dnsTask, "dnsTask", 4096, NULL, 1, NULL, 0);
xTaskCreatePinnedToCore(httpTask, "httpTask", 8192, NULL, 1, NULL, 1);
vTaskDelete(NULL); // 🧨 deletes the default loop() task
}
void loop() {
// Minimal loop – nothing here, all work in tasks
// vTaskDelay(1000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment