index.js 5.8 KB

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