diff --git a/upnp.js b/upnp.js index f1ae2fb..3a48d83 100644 --- a/upnp.js +++ b/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 = "\n\n"; -const SOAP_ENV_POST = "\n\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>/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 = - "\ - \n"; - - this._getSOAPResponse(s, "GetExternalIPAddress", function(err, xml) { - if (err) callback(err); - else callback(null, - xml.match(/(.+?)<\/NewExternalIPAddress>/i)[1]); - }); - -} - -Gateway.prototype.AddPortMapping = function(protocol - , extPort - , intPort - , host - , description - , callback) { - var s = - "\ - \ - "+extPort+"\ - "+protocol+"\ - "+intPort+"\ - "+host+"\ - 1\ - "+description+"\ - 0\ - "; - 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 = "\n\n"; +const SOAP_ENV_POST = "\n\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>/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 = + "\ + \n"; + + this._getSOAPResponse(s, "GetExternalIPAddress", function(err, xml) { + if (err) callback(err); + else callback(null, + xml.match(/(.+?)<\/NewExternalIPAddress>/i)[1]); + }); + +} + +Gateway.prototype.AddPortMapping = function(protocol + , extPort + , intPort + , host + , description + , callback) { + var s = + "\ + \ + "+extPort+"\ + "+protocol+"\ + "+intPort+"\ + "+host+"\ + 1\ + "+description+"\ + 0\ + "; + 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) }); + }); +} diff --git a/valnet-webapp/src/ActiveConnections/index.js b/valnet-webapp/src/ActiveConnections/index.js index 7e479e0..fc4dfec 100644 --- a/valnet-webapp/src/ActiveConnections/index.js +++ b/valnet-webapp/src/ActiveConnections/index.js @@ -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 ( -
-
active connections!
- {this.state.connections.map(connection => { - return (
- {connection.toLocaleString()}; -
) - })} -
- -
- ); - } - - 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 ( +
+
active connections!
+ {this.state.connections.map(connection => { + return (
+ {connection.toLocaleString()}; +
) + })} +
+ +
+ ); + } + + addConnection() { + this.state.connections.push(new Date()); + this.forceUpdate(); + } +} + export default ActiveConnections; \ No newline at end of file diff --git a/valnet-webapp/src/ActiveConnections/style.module.css b/valnet-webapp/src/ActiveConnections/style.module.css index 7fdf161..7a7e856 100644 --- a/valnet-webapp/src/ActiveConnections/style.module.css +++ b/valnet-webapp/src/ActiveConnections/style.module.css @@ -1,3 +1,3 @@ -.red { - color: red; -} +.red { + color: red; +} diff --git a/valnet-webapp/src/app.css b/valnet-webapp/src/app.css index 80c8bc6..0df9133 100644 --- a/valnet-webapp/src/app.css +++ b/valnet-webapp/src/app.css @@ -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; } \ No newline at end of file