Created
October 9, 2021 06:30
-
-
Save InvoxiPlayGames/9d7eb710b3865d37285402f770e2a193 to your computer and use it in GitHub Desktop.
STUN IP request thing in NodeJS (bad)
This file contains 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
var dgram = require("dgram"); | |
var udp4 = dgram.createSocket("udp4"); | |
var udp6 = dgram.createSocket("udp6"); | |
var stunServer = "stun.l.google.com"; | |
var stunPort = 19302; | |
function makeSTUNRequest() { | |
var buffer = Buffer.alloc(20); | |
buffer.writeUInt16BE(0x0001, 0); // STUN request | |
buffer.writeUInt16BE(0x0000, 2); // message size (0 bytes) | |
buffer.writeUInt32BE(0x2112a442, 4); // magic cookie (always 0x2112a442) | |
for (var i = 8; i < 20; i++) { | |
var randInt = Math.floor(Math.random() * 255); | |
buffer.writeUInt8(randInt, i); // write transaction ID | |
} | |
return buffer; | |
} | |
function parseSTUNResponse(buf, rinfo) { | |
if (buf.length < 20) { | |
console.log(`Bad response (packet length ${buf.length}}): ${buf.toString('hex')}`); | |
return; | |
} | |
// parse the STUN header | |
var messageType = buf.readUInt16BE(0); | |
var messageSize = buf.readUInt16BE(2); | |
var magicCookie = buf.readUInt32BE(4); | |
var transID = Buffer.alloc(12); | |
for (var i = 8; i < 20; i++) transID[i-8] = buf.readUInt8(i); | |
// read the STUN message | |
if (messageSize <= 0) { | |
console.log(`Bad response (no message): ${buf.toString('hex')}`); | |
return; | |
} | |
var message = Buffer.alloc(messageSize); | |
for (var i = 0; i < messageSize; i++) message[i] = buf.readUInt8(20+i); | |
// parse the STUN message | |
for (var i = 0; i < messageSize;) { | |
// read attribute header | |
var attribute = message.readUInt16BE(i + 0); | |
var attributeLength = message.readUInt16BE(i + 2); | |
i += 4; | |
if (attribute == 0x0001) { // MAPPED-ADDRESS | |
var reserved = message.readUInt8(i + 0); | |
var addressFamily = message.readUInt8(i + 1); | |
if (addressFamily == 1) { // IPv4 | |
var port = message.readUInt16BE(i + 2); | |
var ip1 = message.readUInt8(i + 4); | |
var ip2 = message.readUInt8(i + 5); | |
var ip3 = message.readUInt8(i + 6); | |
var ip4 = message.readUInt8(i + 7); | |
console.log(`MAPPED-ADDRESS IPv4: ${ip1}.${ip2}.${ip3}.${ip4}:${port}`); | |
} else if (addressFamily == 2) { // IPv6 | |
var port = message.readUInt16BE(i + 2); | |
var ip = ""; | |
// TODO: there's got to be a cleaner way to do this... | |
ip += message.readUInt16BE(i + 4).toString(16) + ":"; | |
ip += message.readUInt16BE(i + 6).toString(16) + ":"; | |
ip += message.readUInt16BE(i + 8).toString(16) + ":"; | |
ip += message.readUInt16BE(i + 10).toString(16) + ":"; | |
ip += message.readUInt16BE(i + 12).toString(16) + ":"; | |
ip += message.readUInt16BE(i + 14).toString(16) + ":"; | |
ip += message.readUInt16BE(i + 16).toString(16) + ":"; | |
ip += message.readUInt16BE(i + 18).toString(16); | |
console.log(`MAPPED-ADDRESS IPv6: [${ip}]:${port}`); | |
} else { | |
console.log(`Unknown MAPPED-ADDRESS family ${addressFamily}: ${message.slice(i+2, i+attributeLength).toString('hex')}`); | |
} | |
} else if (attribute == 0x0020) { // XOR-MAPPED-ADDRESS | |
var reserved = message.readUInt8(i + 0); | |
var addressFamily = message.readUInt8(i + 1); | |
if (addressFamily == 1) { // IPv4 | |
var port = message.readUInt16BE(i + 2) ^ 0x2112; | |
var ip1 = message.readUInt8(i + 4) ^ 0x21; | |
var ip2 = message.readUInt8(i + 5) ^ 0x12; | |
var ip3 = message.readUInt8(i + 6) ^ 0xa4; | |
var ip4 = message.readUInt8(i + 7) ^ 0x42; | |
console.log(`XOR-MAPPED-ADDRESS IPv4: ${ip1}.${ip2}.${ip3}.${ip4}:${port}`); | |
} else if (addressFamily == 2) { // IPv6 | |
var port = message.readUInt16BE(i + 2) ^ 0x2112; | |
var ip = ""; | |
// TODO: there's got to be a cleaner way to do this... | |
ip += (message.readUInt16BE(i + 4) ^ 0x2112).toString(16) + ":"; | |
ip += (message.readUInt16BE(i + 6) ^ 0xa442).toString(16) + ":"; | |
ip += (message.readUInt16BE(i + 8) ^ transID.readUInt16BE(0)).toString(16) + ":"; | |
ip += (message.readUInt16BE(i + 10) ^ transID.readUInt16BE(2)).toString(16) + ":"; | |
ip += (message.readUInt16BE(i + 12) ^ transID.readUInt16BE(4)).toString(16) + ":"; | |
ip += (message.readUInt16BE(i + 14) ^ transID.readUInt16BE(6)).toString(16) + ":"; | |
ip += (message.readUInt16BE(i + 16) ^ transID.readUInt16BE(8)).toString(16) + ":"; | |
ip += (message.readUInt16BE(i + 18) ^ transID.readUInt16BE(10)).toString(16); | |
console.log(`XOR-MAPPED-ADDRESS IPv6: [${ip}]:${port}`); | |
} else { | |
console.log(`Unknown XOR-MAPPED-ADDRESS family ${addressFamily}: ${message.slice(i+2, i+attributeLength).toString('hex')}`); | |
} | |
} else { | |
console.log(`Unknown attribute ${attribute.toString(16)} (length ${attributeLength}): ${message.slice(i, i+attributeLength).toString('hex')}`); | |
} | |
i += attributeLength; | |
} | |
} | |
udp4.on("message", parseSTUNResponse); | |
udp6.on("message", parseSTUNResponse); | |
console.log("Sending STUN request to server..."); | |
udp4.send(makeSTUNRequest(), 0, 20, stunPort, stunServer); | |
udp6.send(makeSTUNRequest(), 0, 20, stunPort, stunServer); | |
setTimeout(process.exit, 2000) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment