i literally cant remove these fucking files bullshit
parent
9c73ec3acf
commit
d06c108106
326
upnp.js
326
upnp.js
|
|
@ -1,163 +1,163 @@
|
|||
/* node UPNP port forwarding PoC
|
||||
This is a simple way to forward ports on NAT routers with UPNP.
|
||||
This is a not-for-production hack that I found useful when testing apps
|
||||
on my home network behind ny NAT router.
|
||||
-satori / edited by smolleyes for freebox v6
|
||||
usage: (install/clone node-ip from https://github.com/indutny/node-ip)
|
||||
================================================================================
|
||||
|
||||
================================================================================
|
||||
*/
|
||||
var url = require("url");
|
||||
var http = require("http");
|
||||
var dgram = require("dgram");
|
||||
var Buffer = require("buffer").Buffer;
|
||||
|
||||
// some const strings - dont change
|
||||
const SSDP_PORT = 1901;
|
||||
const bcast = "239.255.255.250";
|
||||
const ST = "urn:schemas-upnp-org:device:InternetGatewayDevice:1";
|
||||
const req = "M-SEARCH * HTTP/1.1\r\nHost:239.255.255.250:1900\r\n\
|
||||
ST:"+ST+"\r\nMan:\"ssdp:discover\"\r\nMX:3\r\n\r\n";
|
||||
const WANIP = "urn:schemas-upnp-org:service:WANIPConnection:1";
|
||||
const OK = "HTTP/1.1 200 OK";
|
||||
const SOAP_ENV_PRE = "<?xml version=\"1.0\"?>\n<s:Envelope \
|
||||
xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" \
|
||||
s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\n";
|
||||
const SOAP_ENV_POST = "</s:Body>\n</s:Envelope>\n";
|
||||
|
||||
function searchGateway(timeout, callback) {
|
||||
|
||||
var self = this;
|
||||
var reqbuf = new Buffer(req, "ascii");
|
||||
var socket = new dgram.Socket('udp4');
|
||||
var clients = {};
|
||||
var t;
|
||||
|
||||
if (timeout) {
|
||||
t = setTimeout(function() {
|
||||
onerror(new Error("searchGateway() timed out"));
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
var onlistening = function() {
|
||||
|
||||
socket.setBroadcast(socket.fd, true);
|
||||
// send a few packets just in case.
|
||||
socket.send(reqbuf, 0, reqbuf.length, SSDP_PORT,bcast);
|
||||
|
||||
}
|
||||
|
||||
var onmessage = function(message, rinfo) {
|
||||
|
||||
console.log('message?')
|
||||
message = message.toString();
|
||||
|
||||
if (message.substr(0, OK.length) !== OK ||
|
||||
!message.indexOf(ST) ||
|
||||
!message.indexOf("location:")) return;
|
||||
|
||||
var l = url.parse(message.match(/location:(.+?)\r\n/i)[1].trim());
|
||||
if (clients[l.href]) return;
|
||||
|
||||
var client = clients[l.href] = http.createClient(l.port, l.hostname);
|
||||
var request = client.request("GET", l.pathname, {"host": l.hostname});
|
||||
request.end();
|
||||
request.addListener('response', function (response) {
|
||||
if (response.statusCode !== 200) return;
|
||||
var resbuf = "";
|
||||
response.addListener('data', function (chunk) { resbuf += chunk });
|
||||
response.addListener("end", function() {
|
||||
resbuf = resbuf.substr(resbuf.indexOf(WANIP) + WANIP.length);
|
||||
var ipurl = resbuf.match(/<controlURL>(.+?)<\/controlURL>/i)[1].trim()
|
||||
socket.close();
|
||||
clearTimeout(t);
|
||||
callback(null, new Gateway(l.port, l.hostname, ipurl));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var onerror = function(err) {
|
||||
socket.close() ;
|
||||
clearTimeout(t);
|
||||
callback(err);
|
||||
}
|
||||
|
||||
var onclose = function() {
|
||||
socket.removeListener("listening", onlistening);
|
||||
socket.removeListener("message", onmessage);
|
||||
socket.removeListener("close", onclose);
|
||||
socket.removeListener("error", onerror);
|
||||
}
|
||||
|
||||
socket.addListener("listening", onlistening);
|
||||
socket.addListener("message", onmessage);
|
||||
socket.addListener("close", onclose);
|
||||
socket.addListener("error", onerror);
|
||||
|
||||
socket.bind(SSDP_PORT);
|
||||
|
||||
}
|
||||
exports.searchGateway = searchGateway;
|
||||
|
||||
function Gateway(port, host, path) {
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
Gateway.prototype.getExternalIP = function(callback) {
|
||||
|
||||
var s =
|
||||
"<u:GetExternalIPAddress xmlns:u=\"" + WANIP + "\">\
|
||||
</u:GetExternalIPAddress>\n";
|
||||
|
||||
this._getSOAPResponse(s, "GetExternalIPAddress", function(err, xml) {
|
||||
if (err) callback(err);
|
||||
else callback(null,
|
||||
xml.match(/<NewExternalIPAddress>(.+?)<\/NewExternalIPAddress>/i)[1]);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
Gateway.prototype.AddPortMapping = function(protocol
|
||||
, extPort
|
||||
, intPort
|
||||
, host
|
||||
, description
|
||||
, callback) {
|
||||
var s =
|
||||
"<u:AddPortMapping \
|
||||
xmlns:u=\""+WANIP+"\">\
|
||||
<NewRemoteHost></NewRemoteHost>\
|
||||
<NewExternalPort>"+extPort+"</NewExternalPort>\
|
||||
<NewProtocol>"+protocol+"</NewProtocol>\
|
||||
<NewInternalPort>"+intPort+"</NewInternalPort>\
|
||||
<NewInternalClient>"+host+"</NewInternalClient>\
|
||||
<NewEnabled>1</NewEnabled>\
|
||||
<NewPortMappingDescription>"+description+"</NewPortMappingDescription>\
|
||||
<NewLeaseDuration>0</NewLeaseDuration>\
|
||||
</u:AddPortMapping>";
|
||||
this._getSOAPResponse(s, "AddPortMapping", callback);
|
||||
}
|
||||
|
||||
Gateway.prototype._getSOAPResponse = function(soap, func, callback) {
|
||||
var s = [SOAP_ENV_PRE, soap, SOAP_ENV_POST].join("");
|
||||
var client = http.createClient(this.port, this.host);
|
||||
var hdrs = { "host" : this.host
|
||||
, "SOAPACTION" : "\"" + WANIP + "#" + func + "\""
|
||||
, "content-type" : "text/xml"
|
||||
, "content-length" : s.length };
|
||||
var request = client.request("POST", this.path, hdrs);
|
||||
request.end(s);
|
||||
request.addListener('response', function (response) {
|
||||
if (response.statusCode !== 200) {
|
||||
response.close();
|
||||
callback(new Error("Invalid SOAP action"));
|
||||
return;
|
||||
}
|
||||
var buf = "";
|
||||
response.addListener('data', function (chunk) { buf += chunk });
|
||||
response.addListener('end', function () { callback(null, buf) });
|
||||
});
|
||||
}
|
||||
/* node UPNP port forwarding PoC
|
||||
This is a simple way to forward ports on NAT routers with UPNP.
|
||||
This is a not-for-production hack that I found useful when testing apps
|
||||
on my home network behind ny NAT router.
|
||||
-satori / edited by smolleyes for freebox v6
|
||||
usage: (install/clone node-ip from https://github.com/indutny/node-ip)
|
||||
================================================================================
|
||||
|
||||
================================================================================
|
||||
*/
|
||||
var url = require("url");
|
||||
var http = require("http");
|
||||
var dgram = require("dgram");
|
||||
var Buffer = require("buffer").Buffer;
|
||||
|
||||
// some const strings - dont change
|
||||
const SSDP_PORT = 1901;
|
||||
const bcast = "239.255.255.250";
|
||||
const ST = "urn:schemas-upnp-org:device:InternetGatewayDevice:1";
|
||||
const req = "M-SEARCH * HTTP/1.1\r\nHost:239.255.255.250:1900\r\n\
|
||||
ST:"+ST+"\r\nMan:\"ssdp:discover\"\r\nMX:3\r\n\r\n";
|
||||
const WANIP = "urn:schemas-upnp-org:service:WANIPConnection:1";
|
||||
const OK = "HTTP/1.1 200 OK";
|
||||
const SOAP_ENV_PRE = "<?xml version=\"1.0\"?>\n<s:Envelope \
|
||||
xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" \
|
||||
s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>\n";
|
||||
const SOAP_ENV_POST = "</s:Body>\n</s:Envelope>\n";
|
||||
|
||||
function searchGateway(timeout, callback) {
|
||||
|
||||
var self = this;
|
||||
var reqbuf = new Buffer(req, "ascii");
|
||||
var socket = new dgram.Socket('udp4');
|
||||
var clients = {};
|
||||
var t;
|
||||
|
||||
if (timeout) {
|
||||
t = setTimeout(function() {
|
||||
onerror(new Error("searchGateway() timed out"));
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
var onlistening = function() {
|
||||
|
||||
socket.setBroadcast(socket.fd, true);
|
||||
// send a few packets just in case.
|
||||
socket.send(reqbuf, 0, reqbuf.length, SSDP_PORT,bcast);
|
||||
|
||||
}
|
||||
|
||||
var onmessage = function(message, rinfo) {
|
||||
|
||||
console.log('message?')
|
||||
message = message.toString();
|
||||
|
||||
if (message.substr(0, OK.length) !== OK ||
|
||||
!message.indexOf(ST) ||
|
||||
!message.indexOf("location:")) return;
|
||||
|
||||
var l = url.parse(message.match(/location:(.+?)\r\n/i)[1].trim());
|
||||
if (clients[l.href]) return;
|
||||
|
||||
var client = clients[l.href] = http.createClient(l.port, l.hostname);
|
||||
var request = client.request("GET", l.pathname, {"host": l.hostname});
|
||||
request.end();
|
||||
request.addListener('response', function (response) {
|
||||
if (response.statusCode !== 200) return;
|
||||
var resbuf = "";
|
||||
response.addListener('data', function (chunk) { resbuf += chunk });
|
||||
response.addListener("end", function() {
|
||||
resbuf = resbuf.substr(resbuf.indexOf(WANIP) + WANIP.length);
|
||||
var ipurl = resbuf.match(/<controlURL>(.+?)<\/controlURL>/i)[1].trim()
|
||||
socket.close();
|
||||
clearTimeout(t);
|
||||
callback(null, new Gateway(l.port, l.hostname, ipurl));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var onerror = function(err) {
|
||||
socket.close() ;
|
||||
clearTimeout(t);
|
||||
callback(err);
|
||||
}
|
||||
|
||||
var onclose = function() {
|
||||
socket.removeListener("listening", onlistening);
|
||||
socket.removeListener("message", onmessage);
|
||||
socket.removeListener("close", onclose);
|
||||
socket.removeListener("error", onerror);
|
||||
}
|
||||
|
||||
socket.addListener("listening", onlistening);
|
||||
socket.addListener("message", onmessage);
|
||||
socket.addListener("close", onclose);
|
||||
socket.addListener("error", onerror);
|
||||
|
||||
socket.bind(SSDP_PORT);
|
||||
|
||||
}
|
||||
exports.searchGateway = searchGateway;
|
||||
|
||||
function Gateway(port, host, path) {
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
Gateway.prototype.getExternalIP = function(callback) {
|
||||
|
||||
var s =
|
||||
"<u:GetExternalIPAddress xmlns:u=\"" + WANIP + "\">\
|
||||
</u:GetExternalIPAddress>\n";
|
||||
|
||||
this._getSOAPResponse(s, "GetExternalIPAddress", function(err, xml) {
|
||||
if (err) callback(err);
|
||||
else callback(null,
|
||||
xml.match(/<NewExternalIPAddress>(.+?)<\/NewExternalIPAddress>/i)[1]);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
Gateway.prototype.AddPortMapping = function(protocol
|
||||
, extPort
|
||||
, intPort
|
||||
, host
|
||||
, description
|
||||
, callback) {
|
||||
var s =
|
||||
"<u:AddPortMapping \
|
||||
xmlns:u=\""+WANIP+"\">\
|
||||
<NewRemoteHost></NewRemoteHost>\
|
||||
<NewExternalPort>"+extPort+"</NewExternalPort>\
|
||||
<NewProtocol>"+protocol+"</NewProtocol>\
|
||||
<NewInternalPort>"+intPort+"</NewInternalPort>\
|
||||
<NewInternalClient>"+host+"</NewInternalClient>\
|
||||
<NewEnabled>1</NewEnabled>\
|
||||
<NewPortMappingDescription>"+description+"</NewPortMappingDescription>\
|
||||
<NewLeaseDuration>0</NewLeaseDuration>\
|
||||
</u:AddPortMapping>";
|
||||
this._getSOAPResponse(s, "AddPortMapping", callback);
|
||||
}
|
||||
|
||||
Gateway.prototype._getSOAPResponse = function(soap, func, callback) {
|
||||
var s = [SOAP_ENV_PRE, soap, SOAP_ENV_POST].join("");
|
||||
var client = http.createClient(this.port, this.host);
|
||||
var hdrs = { "host" : this.host
|
||||
, "SOAPACTION" : "\"" + WANIP + "#" + func + "\""
|
||||
, "content-type" : "text/xml"
|
||||
, "content-length" : s.length };
|
||||
var request = client.request("POST", this.path, hdrs);
|
||||
request.end(s);
|
||||
request.addListener('response', function (response) {
|
||||
if (response.statusCode !== 200) {
|
||||
response.close();
|
||||
callback(new Error("Invalid SOAP action"));
|
||||
return;
|
||||
}
|
||||
var buf = "";
|
||||
response.addListener('data', function (chunk) { buf += chunk });
|
||||
response.addListener('end', function () { callback(null, buf) });
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +1,45 @@
|
|||
import React from 'react';
|
||||
import styles from './style.module.css';
|
||||
import { apiRoot } from '../lib/constants.js';
|
||||
|
||||
class ActiveConnections extends React.Component {
|
||||
|
||||
state = {
|
||||
connections: []
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
async refreshData() {
|
||||
const req = await fetch(`${apiRoot}/clients`);
|
||||
const res = await req.json();
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div>active connections!</div>
|
||||
{this.state.connections.map(connection => {
|
||||
return (<div>
|
||||
{connection.toLocaleString()};
|
||||
</div>)
|
||||
})}
|
||||
<br />
|
||||
<button onClick={() => this.addConnection.bind(this)()}>
|
||||
Add Connection
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
addConnection() {
|
||||
this.state.connections.push(new Date());
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
import React from 'react';
|
||||
import styles from './style.module.css';
|
||||
import { apiRoot } from '../lib/constants.js';
|
||||
|
||||
class ActiveConnections extends React.Component {
|
||||
|
||||
state = {
|
||||
connections: []
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
async refreshData() {
|
||||
const req = await fetch(`${apiRoot}/clients`);
|
||||
const res = await req.json();
|
||||
console.log(res);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div>active connections!</div>
|
||||
{this.state.connections.map(connection => {
|
||||
return (<div>
|
||||
{connection.toLocaleString()};
|
||||
</div>)
|
||||
})}
|
||||
<br />
|
||||
<button onClick={() => this.addConnection.bind(this)()}>
|
||||
Add Connection
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
addConnection() {
|
||||
this.state.connections.push(new Date());
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
export default ActiveConnections;
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
.red {
|
||||
color: red;
|
||||
}
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +1,47 @@
|
|||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
--b1: #001;
|
||||
--b2: #112;
|
||||
--b3: #223;
|
||||
--b4: #334;
|
||||
--t1: #EEF;
|
||||
--t2: #DDE;
|
||||
--t3: #CCD;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
--b1: #EEF;
|
||||
--b2: #DDE;
|
||||
--b3: #CCD;
|
||||
--b4: #BBC;
|
||||
--t1: #001;
|
||||
--t2: #112;
|
||||
--t3: #223;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
html {
|
||||
background: var(--b1);
|
||||
color: var(--t1);
|
||||
}
|
||||
td:not(:last-child), th:not(:last-child) {
|
||||
border-right: 1px solid var(--t3);
|
||||
}
|
||||
td, th {
|
||||
padding-left: 8px;
|
||||
}
|
||||
th {
|
||||
border-bottom: 3px solid var(--t3);
|
||||
}
|
||||
table {
|
||||
border-spacing: 0px;
|
||||
font-family: sans-serif;
|
||||
font-size: 13px;
|
||||
}
|
||||
tr:nth-child(2n) {
|
||||
background: #111;
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
--b1: #001;
|
||||
--b2: #112;
|
||||
--b3: #223;
|
||||
--b4: #334;
|
||||
--t1: #EEF;
|
||||
--t2: #DDE;
|
||||
--t3: #CCD;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
--b1: #EEF;
|
||||
--b2: #DDE;
|
||||
--b3: #CCD;
|
||||
--b4: #BBC;
|
||||
--t1: #001;
|
||||
--t2: #112;
|
||||
--t3: #223;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
html {
|
||||
background: var(--b1);
|
||||
color: var(--t1);
|
||||
}
|
||||
td:not(:last-child), th:not(:last-child) {
|
||||
border-right: 1px solid var(--t3);
|
||||
}
|
||||
td, th {
|
||||
padding-left: 8px;
|
||||
}
|
||||
th {
|
||||
border-bottom: 3px solid var(--t3);
|
||||
}
|
||||
table {
|
||||
border-spacing: 0px;
|
||||
font-family: sans-serif;
|
||||
font-size: 13px;
|
||||
}
|
||||
tr:nth-child(2n) {
|
||||
background: #111;
|
||||
}
|
||||
Reference in New Issue