Last active
October 9, 2025 04:23
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| 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