index.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*!
  2. * proxy-addr
  3. * Copyright(c) 2014-2016 Douglas Christopher Wilson
  4. * MIT Licensed
  5. */
  6. 'use strict'
  7. /**
  8. * Module exports.
  9. */
  10. module.exports = proxyaddr;
  11. module.exports.all = alladdrs;
  12. module.exports.compile = compile;
  13. /**
  14. * Module dependencies.
  15. */
  16. var forwarded = require('forwarded');
  17. var ipaddr = require('ipaddr.js');
  18. /**
  19. * Variables.
  20. */
  21. var digitre = /^[0-9]+$/;
  22. var isip = ipaddr.isValid;
  23. var parseip = ipaddr.parse;
  24. /**
  25. * Pre-defined IP ranges.
  26. */
  27. var ipranges = {
  28. linklocal: ['169.254.0.0/16', 'fe80::/10'],
  29. loopback: ['127.0.0.1/8', '::1/128'],
  30. uniquelocal: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', 'fc00::/7']
  31. };
  32. /**
  33. * Get all addresses in the request, optionally stopping
  34. * at the first untrusted.
  35. *
  36. * @param {Object} request
  37. * @param {Function|Array|String} [trust]
  38. * @api public
  39. */
  40. function alladdrs(req, trust) {
  41. // get addresses
  42. var addrs = forwarded(req);
  43. if (!trust) {
  44. // Return all addresses
  45. return addrs;
  46. }
  47. if (typeof trust !== 'function') {
  48. trust = compile(trust);
  49. }
  50. for (var i = 0; i < addrs.length - 1; i++) {
  51. if (trust(addrs[i], i)) continue;
  52. addrs.length = i + 1;
  53. }
  54. return addrs;
  55. }
  56. /**
  57. * Compile argument into trust function.
  58. *
  59. * @param {Array|String} val
  60. * @api private
  61. */
  62. function compile(val) {
  63. if (!val) {
  64. throw new TypeError('argument is required');
  65. }
  66. var trust = typeof val === 'string'
  67. ? [val]
  68. : val;
  69. if (!Array.isArray(trust)) {
  70. throw new TypeError('unsupported trust argument');
  71. }
  72. for (var i = 0; i < trust.length; i++) {
  73. val = trust[i];
  74. if (!ipranges.hasOwnProperty(val)) {
  75. continue;
  76. }
  77. // Splice in pre-defined range
  78. val = ipranges[val];
  79. trust.splice.apply(trust, [i, 1].concat(val));
  80. i += val.length - 1;
  81. }
  82. return compileTrust(compileRangeSubnets(trust));
  83. }
  84. /**
  85. * Compile `arr` elements into range subnets.
  86. *
  87. * @param {Array} arr
  88. * @api private
  89. */
  90. function compileRangeSubnets(arr) {
  91. var rangeSubnets = new Array(arr.length);
  92. for (var i = 0; i < arr.length; i++) {
  93. rangeSubnets[i] = parseipNotation(arr[i]);
  94. }
  95. return rangeSubnets;
  96. }
  97. /**
  98. * Compile range subnet array into trust function.
  99. *
  100. * @param {Array} rangeSubnets
  101. * @api private
  102. */
  103. function compileTrust(rangeSubnets) {
  104. // Return optimized function based on length
  105. var len = rangeSubnets.length;
  106. return len === 0
  107. ? trustNone
  108. : len === 1
  109. ? trustSingle(rangeSubnets[0])
  110. : trustMulti(rangeSubnets);
  111. }
  112. /**
  113. * Parse IP notation string into range subnet.
  114. *
  115. * @param {String} note
  116. * @api private
  117. */
  118. function parseipNotation(note) {
  119. var pos = note.lastIndexOf('/');
  120. var str = pos !== -1
  121. ? note.substring(0, pos)
  122. : note;
  123. if (!isip(str)) {
  124. throw new TypeError('invalid IP address: ' + str);
  125. }
  126. var ip = parseip(str);
  127. if (pos === -1 && ip.kind() === 'ipv6' && ip.isIPv4MappedAddress()) {
  128. // Store as IPv4
  129. ip = ip.toIPv4Address();
  130. }
  131. var max = ip.kind() === 'ipv6'
  132. ? 128
  133. : 32;
  134. var range = pos !== -1
  135. ? note.substring(pos + 1, note.length)
  136. : null;
  137. if (range === null) {
  138. range = max;
  139. } else if (digitre.test(range)) {
  140. range = parseInt(range, 10);
  141. } else if (ip.kind() === 'ipv4' && isip(range)) {
  142. range = parseNetmask(range);
  143. } else {
  144. range = null;
  145. }
  146. if (range <= 0 || range > max) {
  147. throw new TypeError('invalid range on address: ' + note);
  148. }
  149. return [ip, range];
  150. }
  151. /**
  152. * Parse netmask string into CIDR range.
  153. *
  154. * @param {String} netmask
  155. * @api private
  156. */
  157. function parseNetmask(netmask) {
  158. var ip = parseip(netmask);
  159. var kind = ip.kind();
  160. return kind === 'ipv4'
  161. ? ip.prefixLengthFromSubnetMask()
  162. : null;
  163. }
  164. /**
  165. * Determine address of proxied request.
  166. *
  167. * @param {Object} request
  168. * @param {Function|Array|String} trust
  169. * @api public
  170. */
  171. function proxyaddr(req, trust) {
  172. if (!req) {
  173. throw new TypeError('req argument is required');
  174. }
  175. if (!trust) {
  176. throw new TypeError('trust argument is required');
  177. }
  178. var addrs = alladdrs(req, trust);
  179. var addr = addrs[addrs.length - 1];
  180. return addr;
  181. }
  182. /**
  183. * Static trust function to trust nothing.
  184. *
  185. * @api private
  186. */
  187. function trustNone() {
  188. return false;
  189. }
  190. /**
  191. * Compile trust function for multiple subnets.
  192. *
  193. * @param {Array} subnets
  194. * @api private
  195. */
  196. function trustMulti(subnets) {
  197. return function trust(addr) {
  198. if (!isip(addr)) return false;
  199. var ip = parseip(addr);
  200. var ipconv;
  201. var kind = ip.kind();
  202. for (var i = 0; i < subnets.length; i++) {
  203. var subnet = subnets[i];
  204. var subnetip = subnet[0];
  205. var subnetkind = subnetip.kind();
  206. var subnetrange = subnet[1];
  207. var trusted = ip;
  208. if (kind !== subnetkind) {
  209. if (subnetkind === 'ipv4' && !ip.isIPv4MappedAddress()) {
  210. // Incompatible IP addresses
  211. continue;
  212. }
  213. if (!ipconv) {
  214. // Convert IP to match subnet IP kind
  215. ipconv = subnetkind === 'ipv4'
  216. ? ip.toIPv4Address()
  217. : ip.toIPv4MappedAddress();
  218. }
  219. trusted = ipconv;
  220. }
  221. if (trusted.match(subnetip, subnetrange)) {
  222. return true;
  223. }
  224. }
  225. return false;
  226. };
  227. }
  228. /**
  229. * Compile trust function for single subnet.
  230. *
  231. * @param {Object} subnet
  232. * @api private
  233. */
  234. function trustSingle(subnet) {
  235. var subnetip = subnet[0];
  236. var subnetkind = subnetip.kind();
  237. var subnetisipv4 = subnetkind === 'ipv4';
  238. var subnetrange = subnet[1];
  239. return function trust(addr) {
  240. if (!isip(addr)) return false;
  241. var ip = parseip(addr);
  242. var kind = ip.kind();
  243. if (kind !== subnetkind) {
  244. if (subnetisipv4 && !ip.isIPv4MappedAddress()) {
  245. // Incompatible IP addresses
  246. return false;
  247. }
  248. // Convert IP to match subnet IP kind
  249. ip = subnetisipv4
  250. ? ip.toIPv4Address()
  251. : ip.toIPv4MappedAddress();
  252. }
  253. return ip.match(subnetip, subnetrange);
  254. };
  255. }