Skip to content

Instantly share code, notes, and snippets.

@wwerner
Last active February 27, 2023 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wwerner/dcaa0e51cc3b1be752ae8dee6cb68c80 to your computer and use it in GitHub Desktop.
Save wwerner/dcaa0e51cc3b1be752ae8dee6cb68c80 to your computer and use it in GitHub Desktop.

transparent-proxy

Reproducer for gr3p1p3/transparent-proxy#21

  • run yarn
  • run node index.js
  • run curl --proxy localhost:8888 --insecure --proxy-insecure -F "foo=bar" -F"baz=qux" https:/httpbin.org/anything form another shell
  • verify the result contains the form fields foo and baz and their values
  • Comment index.js:L34 and un-comment index.js:L38
  • restart the server
  • run the curl command again

working: no async header - response

$ curl --proxy localhost:8888 --insecure --proxy-insecure -F "foo=bar" -F"baz=qux" https:/httpbin.org/anything
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "baz": "qux", 
    "foo": "bar"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "236", 
    "Content-Type": "multipart/form-data; boundary=------------------------49e0ef59d2018523", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.82.0", 
    "X-Amzn-Trace-Id": "Root=1-63cea77b-1665e9b06bda113b3049b28d", 
    "X-Test": "sync"
  }, 
  "json": null, 
  "method": "POST", 
  "origin": "178.27.174.62", 
  "url": "https://httpbin.org/anything"
}

working: no asnyc header - server log

Proxy started
### 2023-01-23T15:27:55.297Z 127.0.0.1:51635 => { ADDRESS: 'httpbin.org', PORT: 443 }
[
  'POST /anything HTTP/1.1',
  'Host: httpbin.org',
  'User-Agent: curl/7.82.0',
  'Accept: */*',
  'Content-Length: 236',
  'Content-Type: multipart/form-data; boundary=------------------------49e0ef59d2018523',
  'x-test: sync',
  '',
  ''
]
[
  '--------------------------49e0ef59d2018523',
  'Content-Disposition: form-data; name="foo"',
  '',
  'bar',
  '--------------------------49e0ef59d2018523',
  'Content-Disposition: form-data; name="baz"',
  '',
  'qux',
  '--------------------------49e0ef59d2018523--',
  ''
]

broken: async header - response

$ curl --proxy localhost:8888 --insecure --proxy-insecure -F "foo=bar" -F"baz=qux" https:/httpbin.org/anything
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
</body>
</html>

broken: async header - server log

node index.js
Proxy started
### 2023-01-23T15:30:51.834Z 127.0.0.1:51673 => { ADDRESS: 'httpbin.org', PORT: 443 }
[
  '--------------------------d05fcb0e05557989',
  'Content-Disposition: form-data; name="foo"',
  '',
  'bar',
  '--------------------------d05fcb0e05557989',
  'Content-Disposition: form-data; name="baz"',
  '',
  'qux',
  '--------------------------d05fcb0e05557989--',
  ''
]
[
  'POST /anything HTTP/1.1',
  'Host: httpbin.org',
  'User-Agent: curl/7.82.0',
  'Accept: */*',
  'Content-Length: 236',
  'Content-Type: multipart/form-data; boundary=------------------------d05fcb0e05557989',
  'x-test: added async',
  '',
  ''
]
const ProxyServer = require("transparent-proxy");
const fs = require("fs");
const getHeader = async () =>
new Promise((resolve) =>
setTimeout(() => resolve("x-test: added async"), 500)
);
//init ProxyServer
/*
* self-signed certificates:
openssl req -x509 -out localhost.crt -keyout localhost.key \
-newkey rsa:2048 -nodes -sha256 \
-subj '/CN=localhost' -extensions EXT -config <( \
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
*/
const server = new ProxyServer({
verbose: true,
intercept: true,
keys: () => {
return {
key: fs.readFileSync("./localhost.key"),
cert: fs.readFileSync("./localhost.crt"),
};
},
injectData: async (data) => {
let result = data.toString().split("\r\n");
const separatorIndex = result.findIndex((e) => e === ""); // index to insert header, i.e. as last header
if (
result[0] &&
!result[0].startsWith("--") // don't add header in content chunks
) {
// this works
const header = "x-test: sync";
// this jumbles the chunks so the content chunks are sent before the first
// one, resulting in 400
//const header = await getHeader();
result.splice(separatorIndex, 0, header);
}
console.log(result);
return result.join("\r\n");
},
});
server.listen(8888, "0.0.0.0", () => {
console.log("Proxy started");
});
-----BEGIN CERTIFICATE-----
MIIC8DCCAdigAwIBAgIUcB1drcvfy5Oi6igO3UYRokaBzK8wDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDEyMzE0MjAwMVoXDTIzMDIy
MjE0MjAwMVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA5cNI3Jf3UFDhDv2v7Sh6SZM0pnJ35OKdApz4ZwoE5t+x
Q6JwMFrdMFydTyXHshd/m7DMbNwIB9E1K7DzxMXS+9BAG7DJo/LomCyr+eWit28D
jDJs2fMCDYRcBlwPUNONAEgqJzbGEJAp3F6RvTfadzeM93IQL3oas/CY49yywta3
tU56yCsOC1lcG0Oj1Rwwjt93PmC1o0mRyU3jJe6OP00LgBNcJgxcUy/VRGV4ZkBw
R1T/WrVprerrJTHgk/eezGbap1TBGIcewac1TXR7cMG8HYtkFkMMcmLM2y6J3B92
SFRMH2eE8VoPLAfCNCu8+nBPARfPo+n9aBEYm/AQMQIDAQABozowODAUBgNVHREE
DTALgglsb2NhbGhvc3QwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMB
MA0GCSqGSIb3DQEBCwUAA4IBAQDbHHR3MOcGI/x/NU724RjVnkgQ7jfc3AZlIAaD
D3fL4FJi9j+z+xGuCxpNOZQa0aWf3gx8PLIdMse+vBQmTc72KJOYcMbn7CfILr1v
1wdlFsy5qeMUR2Yv8Cx3XeYVL0VMXCXwnwynKCMCHX2/wh7d/0hb1w8IeQ4gxC5V
gfI6OtoCKP2NaxKCi1echRCLBtvfLRrj0TvuHYXzlaKkUosTQVsfrwXTvE2aR7ba
rexvb04/luHvNNkQhNQg4GgzInNfe8hssgSuUoD0J7DWnOXZvXmKC9kb+CEM9zIl
LjojT2NmkcDT5CWrXBH/JIQfBYTu51EtMbpcO6GfvbKQMHQ5
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDlw0jcl/dQUOEO
/a/tKHpJkzSmcnfk4p0CnPhnCgTm37FDonAwWt0wXJ1PJceyF3+bsMxs3AgH0TUr
sPPExdL70EAbsMmj8uiYLKv55aK3bwOMMmzZ8wINhFwGXA9Q040ASConNsYQkCnc
XpG9N9p3N4z3chAvehqz8Jjj3LLC1re1TnrIKw4LWVwbQ6PVHDCO33c+YLWjSZHJ
TeMl7o4/TQuAE1wmDFxTL9VEZXhmQHBHVP9atWmt6uslMeCT957MZtqnVMEYhx7B
pzVNdHtwwbwdi2QWQwxyYszbLoncH3ZIVEwfZ4TxWg8sB8I0K7z6cE8BF8+j6f1o
ERib8BAxAgMBAAECggEAbtZhDMFmdeE+YJvyxUZUj6+qo2zu94R2V69fiV1k9fcN
LWJsGneK4mybGnZQOlJppbKJOy591T+QFc6cGd2QpRdWBcWn0CY7HEXYhInJkBHG
tVgR+KXo5JpoRk0culIDYBJv+1DKBW12NC+OwKf0BLTQlQH6WtzditZS+wEZXzGJ
Ymbp+6iI4P1N1hW/0whzqVvVDryUq4IZq/cMkRx99DCAubwr7mCbwdy+1oeYU9cK
cKsjQB/srH4fhwlePSlNQZWIGQ6hi/8XwzzvJTTzX+GoM5nC0eprgoofph2b0YB8
pKw/+F0PIRhN+utbUEXHlyvVb3fkLO/TMTaWBz+IwQKBgQD9JsCbOjM5fldVp1rU
oqigSXtsosQ/UDtjcAiO/2IGGW7ER7nJ26ohEUmJ59LQF9hQL6mPSpJaVOsdfIsp
kRlNl87O9rpR38FUq8Gyoe0DE+ih08zdCd61ncb/NQ2IJgBN8ddspYQxi7NCPpSK
VIc3JDNWBj3C/bQVV98qFnIHaQKBgQDoWShJuSv3GSgXtInNlFCLcD0EPyyHOyt7
8h65V7+X+Q2uYy+jOdYYrXhCzOeoQRE6ysF0jhMiStBu6uvfa9CSj4eaNTNjzrMF
goSOkGLGqobAUMXqxVGlmkDiSY6fPN5SAYGWqs/4DH7UvV95kBnW4FL5+TJ+CfJO
5GG2cKcxiQKBgD8BQRihMJSTnDrmLxYS8bMK9tv/2qYDWvSRsp+cchIgjE/vpg7W
TA501f+roe1GsgCrDCFspuYykl3BXIVY5ppIOSGLiK3N6bkgElJaOLn2X4S/SRKO
XU6IWTm1Q4vqIVNE6J/SxgbqxQ+ssZ2IEisoKFq1rPN13zccqp83/ONZAoGBAJgz
HxL7+3LHxd2RY9uI1iIhCbcoctC6z8dHWRzsABNbD702N9RiZH6R039enjk3NkQe
4Q6qqpoCC/s8Y/pcs6nt31QCmYE9u0NWteJ1bl7ZAaAkySD61Hr4Spxwtr5UrwVk
+zBpAAZqmQJecpY88NAy7efVd1/cwB8xt1g8/yiRAn84VizipQBMxt9Zi7P5t6fp
AB9Wn6dVPS4GDScUX5fIO16ZIKv4D5vy8mVoZbF4fX7QTyAqYPi6touWAgmBKxnP
dWiwQTPl8oRRCqOl6Q01ia21I1csuyI9LZTPkGo8WLC+O4vv2eDTMXNuwlfNOrjm
wLFYq+phn9xJQg5m3hmB
-----END PRIVATE KEY-----
{
"dependencies": {
"transparent-proxy": "^1.10.1"
}
}
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
transparent-proxy@^1.10.1:
version "1.10.1"
resolved "https://registry.yarnpkg.com/transparent-proxy/-/transparent-proxy-1.10.1.tgz#4b475ea22965e4e83899fed7ca247d0a35957cf5"
integrity sha512-bqxIhg41XEFeUNCz11vOLmdkrGtqx/r3yU8g6lR6xUVJ42pBAeX3Vr1pzpUREQarGbpWI+0h/ddpPfIJj4FBVg==
@wwerner
Copy link
Author

wwerner commented Feb 27, 2023

Seems to be fixed as of v1.11.7. 🙌 , thanks @gr3p1p3!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment