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}