|
1 | 1 | 'use strict'; |
2 | 2 |
|
3 | 3 | var crypto = require('crypto'); |
| 4 | +var parseForwarded = require('forwarded-parse'); |
| 5 | +var ipaddr = require('ipaddr.js'); |
| 6 | +var _ = require('underscore'); |
4 | 7 |
|
5 | 8 | exports.hookNameMapping = { |
6 | 9 | beforeSave: '__before_save_for_', |
@@ -70,9 +73,37 @@ exports.prepareResponseObject = function(res, callback) { |
70 | 73 | }; |
71 | 74 |
|
72 | 75 | var getRemoteAddress = exports.getRemoteAddress = function(req) { |
73 | | - return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress |
| 76 | + var forwardedClient = exports.getForwardedClient(req) |
| 77 | + |
| 78 | + if (forwardedClient) { |
| 79 | + return forwardedClient.for |
| 80 | + } else { |
| 81 | + return req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress |
| 82 | + } |
74 | 83 | }; |
75 | 84 |
|
76 | 85 | exports.endsWith = function(str, suffix) { |
77 | 86 | return str.indexOf(suffix, str.length - suffix.length) !== -1; |
78 | 87 | }; |
| 88 | + |
| 89 | +exports.getForwardedClient = function getForwardedClient(req) { |
| 90 | + if (req.headers['forwarded']) { |
| 91 | + try { |
| 92 | + const forwards = parseForwarded(req.headers['forwarded']).reverse() |
| 93 | + |
| 94 | + for (var i = 0; i < forwards.length; i++) { |
| 95 | + if (!forwards[i].for) { |
| 96 | + return |
| 97 | + } |
| 98 | + |
| 99 | + var range = ipaddr.parse(forwards[i].for).range() |
| 100 | + |
| 101 | + if (!_.include(['loopback', 'private'], range) || i === forwards.length - 1) { |
| 102 | + return _.extend(forwards[i], {range: range}) |
| 103 | + } |
| 104 | + } |
| 105 | + } catch (err) { |
| 106 | + console.error('LeanEngine: parse Forwarded header failed', req.headers['forwarded'], err.stack) |
| 107 | + } |
| 108 | + } |
| 109 | +} |
0 commit comments