diff --git a/config.js b/config.js index 97ecdf2..3ceb0d0 100644 --- a/config.js +++ b/config.js @@ -4,4 +4,5 @@ exports.fetch_regex = /^\/fetch\/(.*)$/; // The URL to look for when parsing the exports.proxy_request_timeout_ms = 10000; // The lenght of time we'll wait for a proxy server to respond before timing out. exports.max_request_length = 100000; // The maximum length of characters allowed for a request or a response. exports.enable_rate_limiting = true; -exports.max_requests_per_second = 10; // The maximum number of requests per second to allow from a given IP. \ No newline at end of file +exports.max_requests_per_second = 10; // The maximum number of requests per second to allow from a given IP. +exports.blacklist_hostname_regex = /^(10\.|192\.|localhost$)/i; // Good for limiting access to internal IP addresses and hosts. \ No newline at end of file diff --git a/package.json b/package.json index 6a1cb2e..e952039 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { - "name": "thingproxy.freeboard.io", - "version": "0.0.1", - "description": "A simple forward proxy server for processing API calls to servers that don't send CORS headers or support HTTPS.", - "main": "server.js", - "author": "Jim Heising ", - "license": "MIT", - "dependencies": { - "request": "2.40.0", - "tokenthrottle": "1.1.0" - } + "name": "thingproxy.freeboard.io", + "version": "0.0.1", + "description": "A simple forward proxy server for processing API calls to servers that don't send CORS headers or support HTTPS.", + "main": "server.js", + "author": "Jim Heising ", + "license": "MIT", + "dependencies": { + "request": "2.40.0", + "tokenthrottle": "1.1.0", + "public-address": "^0.1.1" + } } diff --git a/server.js b/server.js index d0e8d1b..e106de5 100644 --- a/server.js +++ b/server.js @@ -4,6 +4,17 @@ var url = require("url"); var request = require("request"); var throttle = require("tokenthrottle")({rate: config.max_requests_per_second}); +var publicAddressFinder = require("public-address"); +var publicIP; + +// Get our public IP address +publicAddressFinder(function(err, data){ + if(!err && data) + { + publicIP = data.address; + } +}); + function addCORSHeaders(req, res) { if (req.method.toUpperCase() === "OPTIONS") @@ -75,11 +86,30 @@ function processRequest(req, res) return writeResponse(res, 404, "relative URLS are not supported"); } + // Naughty, naughty— deny requests to blacklisted hosts + if(config.blacklist_hostname_regex.test(remoteURL.hostname)) + { + return writeResponse(res, 400, "naughty, naughty..."); + } + // We only support http and https if (remoteURL.protocol != "http:" && remoteURL.protocol !== "https:") { return writeResponse(res, 400, "only http and https are supported"); } + if(publicIP) + { + // Add an X-Forwarded-For header + if(req.headers["x-forwarded-for"]) + { + req.headers["x-forwarded-for"] += ", " + publicIP; + } + else + { + req.headers["x-forwarded-for"] = req.clientIP + ", " + publicIP; + } + } + var proxyRequest = request({ url: remoteURL, headers: req.headers, @@ -140,17 +170,19 @@ http.createServer(function (req, res) { return writeResponse(res, 200); } - var remoteIP = getClientAddress(req); + var clientIP = getClientAddress(req); + + req.clientIP = clientIP; // Log our request if(config.enable_logging) { - console.log("%s %s %s", (new Date()).toJSON(), remoteIP, req.method, req.url); + console.log("%s %s %s", (new Date()).toJSON(), clientIP, req.method, req.url); } if(config.enable_rate_limiting) { - throttle.rateLimit(remoteIP, function(err, limited) { + throttle.rateLimit(clientIP, function(err, limited) { if (limited) { return writeResponse(res, 429, "enhance your calm");