arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/proxy-addr/index.js
server/node_modules/proxy-addr/index.jsRaw
  1/*!
  2 * proxy-addr
  3 * Copyright(c) 2014 Douglas Christopher Wilson
  4 * MIT Licensed
  5 */
  6
  7'use strict'
  8
  9/**
 10 * Module exports.
 11 */
 12
 13module.exports = proxyaddr;
 14module.exports.all = alladdrs;
 15module.exports.compile = compile;
 16
 17/**
 18 * Module dependencies.
 19 */
 20
 21var forwarded = require('forwarded');
 22var ipaddr = require('ipaddr.js');
 23
 24/**
 25 * Variables.
 26 */
 27
 28var digitre = /^[0-9]+$/;
 29var isip = ipaddr.isValid;
 30var parseip = ipaddr.parse;
 31
 32/**
 33 * Pre-defined IP ranges.
 34 */
 35
 36var ipranges = {
 37  linklocal: ['169.254.0.0/16', 'fe80::/10'],
 38  loopback: ['127.0.0.1/8', '::1/128'],
 39  uniquelocal: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7']
 40};
 41
 42/**
 43 * Get all addresses in the request, optionally stopping
 44 * at the first untrusted.
 45 *
 46 * @param {Object} request
 47 * @param {Function|Array|String} [trust]
 48 * @api public
 49 */
 50
 51function alladdrs(req, trust) {
 52  // get addresses
 53  var addrs = forwarded(req);
 54
 55  if (!trust) {
 56    // Return all addresses
 57    return addrs;
 58  }
 59
 60  if (typeof trust !== 'function') {
 61    trust = compile(trust);
 62  }
 63
 64  for (var i = 0; i < addrs.length - 1; i++) {
 65    if (trust(addrs[i], i)) continue;
 66
 67    addrs.length = i + 1;
 68  }
 69
 70  return addrs;
 71}
 72
 73/**
 74 * Compile argument into trust function.
 75 *
 76 * @param {Array|String} val
 77 * @api private
 78 */
 79
 80function compile(val) {
 81  if (!val) {
 82    throw new TypeError('argument is required');
 83  }
 84
 85  var trust = typeof val === 'string'
 86    ? [val]
 87    : val;
 88
 89  if (!Array.isArray(trust)) {
 90    throw new TypeError('unsupported trust argument');
 91  }
 92
 93  for (var i = 0; i < trust.length; i++) {
 94    val = trust[i];
 95
 96    if (!ipranges.hasOwnProperty(val)) {
 97      continue;
 98    }
 99
100    // Splice in pre-defined range
101    val = ipranges[val];
102    trust.splice.apply(trust, [i, 1].concat(val));
103    i += val.length - 1;
104  }
105
106  return compileTrust(compileRangeSubnets(trust));
107}
108
109/**
110 * Compile `arr` elements into range subnets.
111 *
112 * @param {Array} arr
113 * @api private
114 */
115
116function compileRangeSubnets(arr) {
117  var rangeSubnets = new Array(arr.length);
118
119  for (var i = 0; i < arr.length; i++) {
120    rangeSubnets[i] = parseipNotation(arr[i]);
121  }
122
123  return rangeSubnets;
124}
125
126/**
127 * Compile range subnet array into trust function.
128 *
129 * @param {Array} rangeSubnets
130 * @api private
131 */
132
133function compileTrust(rangeSubnets) {
134  // Return optimized function based on length
135  var len = rangeSubnets.length;
136  return len === 0
137    ? trustNone
138    : len === 1
139    ? trustSingle(rangeSubnets[0])
140    : trustMulti(rangeSubnets);
141}
142
143/**
144 * Parse IP notation string into range subnet.
145 *
146 * @param {String} note
147 * @api private
148 */
149
150function parseipNotation(note) {
151  var ip;
152  var kind;
153  var max;
154  var pos = note.lastIndexOf('/');
155  var range;
156
157  ip = pos !== -1
158    ? note.substring(0, pos)
159    : note;
160
161  if (!isip(ip)) {
162    throw new TypeError('invalid IP address: ' + ip);
163  }
164
165  ip = parseip(ip);
166
167  kind = ip.kind();
168  max = kind === 'ipv6'
169    ? 128
170    : 32;
171
172  range = pos !== -1
173    ? note.substring(pos + 1, note.length)
174    : max;
175
176  if (typeof range !== 'number') {
177    range = digitre.test(range)
178      ? parseInt(range, 10)
179      : isip(range)
180      ? parseNetmask(range)
181      : 0;
182  }
183
184  if (ip.kind() === 'ipv6' && ip.isIPv4MappedAddress()) {
185    // Store as IPv4
186    ip = ip.toIPv4Address();
187    range = range <= max
188      ? range - 96
189      : range;
190  }
191
192  if (range <= 0 || range > max) {
193    throw new TypeError('invalid range on address: ' + note);
194  }
195
196  return [ip, range];
197}
198
199/**
200 * Parse netmask string into CIDR range.
201 *
202 * @param {String} note
203 * @api private
204 */
205
206function parseNetmask(netmask) {
207  var ip = parseip(netmask);
208  var parts;
209  var size;
210
211  switch (ip.kind()) {
212    case 'ipv4':
213      parts = ip.octets;
214      size = 8;
215      break;
216    case 'ipv6':
217      parts = ip.parts;
218      size = 16;
219      break;
220  }
221
222  var max = Math.pow(2, size) - 1;
223  var part;
224  var range = 0;
225
226  for (var i = 0; i < parts.length; i++) {
227    part = parts[i] & max;
228
229    if (part === max) {
230      range += size;
231      continue;
232    }
233
234    while (part) {
235      part = (part << 1) & max;
236      range += 1;
237    }
238
239    break;
240  }
241
242  return range;
243}
244
245/**
246 * Determine address of proxied request.
247 *
248 * @param {Object} request
249 * @param {Function|Array|String} trust
250 * @api public
251 */
252
253function proxyaddr(req, trust) {
254  if (!req) {
255    throw new TypeError('req argument is required');
256  }
257
258  if (!trust) {
259    throw new TypeError('trust argument is required');
260  }
261
262  var addrs = alladdrs(req, trust);
263  var addr = addrs[addrs.length - 1];
264
265  return addr;
266}
267
268/**
269 * Static trust function to trust nothing.
270 *
271 * @api private
272 */
273
274function trustNone() {
275  return false;
276}
277
278/**
279 * Compile trust function for multiple subnets.
280 *
281 * @param {Array} subnets
282 * @api private
283 */
284
285function trustMulti(subnets) {
286  return function trust(addr) {
287    if (!isip(addr)) return false;
288
289    var ip = parseip(addr);
290    var ipv4;
291    var kind = ip.kind();
292    var subnet;
293    var subnetip;
294    var subnetkind;
295    var subnetrange;
296    var trusted;
297
298    for (var i = 0; i < subnets.length; i++) {
299      subnet = subnets[i];
300      subnetip = subnet[0];
301      subnetkind = subnetip.kind();
302      subnetrange = subnet[1];
303      trusted = ip;
304
305      if (kind !== subnetkind) {
306        if (kind !== 'ipv6' || subnetkind !== 'ipv4' || !ip.isIPv4MappedAddress()) {
307          continue;
308        }
309
310        // Store addr as IPv4
311        ipv4 = ipv4 || ip.toIPv4Address();
312        trusted = ipv4;
313      }
314
315      if (trusted.match(subnetip, subnetrange)) return true;
316    }
317
318    return false;
319  };
320}
321
322/**
323 * Compile trust function for single subnet.
324 *
325 * @param {Object} subnet
326 * @api private
327 */
328
329function trustSingle(subnet) {
330  var subnetip = subnet[0];
331  var subnetkind = subnetip.kind();
332  var subnetisipv4 = subnetkind === 'ipv4';
333  var subnetrange = subnet[1];
334
335  return function trust(addr) {
336    if (!isip(addr)) return false;
337
338    var ip = parseip(addr);
339    var kind = ip.kind();
340
341    return kind === subnetkind
342      ? ip.match(subnetip, subnetrange)
343      : subnetisipv4 && kind === 'ipv6' && ip.isIPv4MappedAddress()
344      ? ip.toIPv4Address().match(subnetip, subnetrange)
345      : false;
346  };
347}