jschan - Anonymous imageboard software. Classic look, modern features and feel. Works without JavaScript and supports Tor, I2P, Lokinet, etc.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

59 lines
1.6 KiB

'use strict';
const config = require(__dirname+'/../config.js')
, { createCIDR, parse } = require('ip6addr')
, deleteTempFiles = require(__dirname+'/files/deletetempfiles.js')
, dynamicResponse = require(__dirname+'/dynamic.js')
, hashIp = require(__dirname+'/haship.js');
module.exports = (req, res, next) => {
//tor user ip uses bypass id, if they dont have one send to blockbypass
if (res.locals.anonymizer) {
const pseudoIp = res.locals.preFetchedBypassId || req.signedCookies.bypassid;
res.locals.ip = {
raw: pseudoIp,
single: pseudoIp,
qrange: pseudoIp,
hrange: pseudoIp,
};
return next();
}
//ip for normal user
const { ipHeader, ipHashPermLevel } = config.get;
const ip = req.headers[ipHeader] || req.connection.remoteAddress;
normalize IP addresses Currently jschan takes the IP address as a string from the `X-Real-Ip` header, which based on the frontend proxy configuration, OS settings, etc. can take various forms: IPv4 addresses can be given in normal IPv4 dotted notation (e.g. `1.2.3.4`) or as an IPv4-mapped IPv6 address (e.g. `::ffff:1.2.3.4`). The problem is, that in the latter case, node's `isIP` will report 6, so the code will try to split it along colons, breaking hrange and qrange. With IPv6 addresses, it's possible to elide runs of zeroes, so `::1` and `0:0:0:0:0:0:0:1` (and also `0000:0000:0000:0000:0000:0000:0000:0001`) represents the same address. Since it's pretty easy to get a /64 IPv6 block, a spammer can abuse it, by spamming from `a:b:c:d::1` (`qrange=a:b:c:d`, `hrange=a:b:c`), then from `a:b:c:d::1:1` (`qrange=a:b:c:d:`, `hrange=a:b:c`), `a:b:c:d::1:1:1` (`qrange=a:b:c:d::1`, `hrange=a:b:c:d`) and `a:b:c:d:1:1:1:1` (`qrange=a:b:c:d:1:1`, `hrange=a:b:c:d`). He practically got two hranges and qrange is pretty much pointless for IPv6 addresses. This change uses the `ip6addr` package to parse IP addresses and convert it to some canonical form. This means: * IPv4 and IPv4-mapped IPv6 addresses are converted to normal IPv4 notation. * Zero are not elided in IPv6 (so you'll never see `::`). * IPv6 addresses are not zero padded (so `..:1` instead of `..:0001`). * Even though it's not documented, it seems like `ip6addr` always generates lower-case letters. This will unfortunately mean that some IP hashes may change after the update. Normal IPv4 hashes will most probably remain the same though.
4 years ago
try {
const ipParsed = parse(ip);
const ipKind = ipParsed.kind();
normalize IP addresses Currently jschan takes the IP address as a string from the `X-Real-Ip` header, which based on the frontend proxy configuration, OS settings, etc. can take various forms: IPv4 addresses can be given in normal IPv4 dotted notation (e.g. `1.2.3.4`) or as an IPv4-mapped IPv6 address (e.g. `::ffff:1.2.3.4`). The problem is, that in the latter case, node's `isIP` will report 6, so the code will try to split it along colons, breaking hrange and qrange. With IPv6 addresses, it's possible to elide runs of zeroes, so `::1` and `0:0:0:0:0:0:0:1` (and also `0000:0000:0000:0000:0000:0000:0000:0001`) represents the same address. Since it's pretty easy to get a /64 IPv6 block, a spammer can abuse it, by spamming from `a:b:c:d::1` (`qrange=a:b:c:d`, `hrange=a:b:c`), then from `a:b:c:d::1:1` (`qrange=a:b:c:d:`, `hrange=a:b:c`), `a:b:c:d::1:1:1` (`qrange=a:b:c:d::1`, `hrange=a:b:c:d`) and `a:b:c:d:1:1:1:1` (`qrange=a:b:c:d:1:1`, `hrange=a:b:c:d`). He practically got two hranges and qrange is pretty much pointless for IPv6 addresses. This change uses the `ip6addr` package to parse IP addresses and convert it to some canonical form. This means: * IPv4 and IPv4-mapped IPv6 addresses are converted to normal IPv4 notation. * Zero are not elided in IPv6 (so you'll never see `::`). * IPv6 addresses are not zero padded (so `..:1` instead of `..:0001`). * Even though it's not documented, it seems like `ip6addr` always generates lower-case letters. This will unfortunately mean that some IP hashes may change after the update. Normal IPv4 hashes will most probably remain the same though.
4 years ago
const ipStr = ipParsed.toString({
format: ipKind === 'ipv4' ? 'v4' : 'v6',
normalize IP addresses Currently jschan takes the IP address as a string from the `X-Real-Ip` header, which based on the frontend proxy configuration, OS settings, etc. can take various forms: IPv4 addresses can be given in normal IPv4 dotted notation (e.g. `1.2.3.4`) or as an IPv4-mapped IPv6 address (e.g. `::ffff:1.2.3.4`). The problem is, that in the latter case, node's `isIP` will report 6, so the code will try to split it along colons, breaking hrange and qrange. With IPv6 addresses, it's possible to elide runs of zeroes, so `::1` and `0:0:0:0:0:0:0:1` (and also `0000:0000:0000:0000:0000:0000:0000:0001`) represents the same address. Since it's pretty easy to get a /64 IPv6 block, a spammer can abuse it, by spamming from `a:b:c:d::1` (`qrange=a:b:c:d`, `hrange=a:b:c`), then from `a:b:c:d::1:1` (`qrange=a:b:c:d:`, `hrange=a:b:c`), `a:b:c:d::1:1:1` (`qrange=a:b:c:d::1`, `hrange=a:b:c:d`) and `a:b:c:d:1:1:1:1` (`qrange=a:b:c:d:1:1`, `hrange=a:b:c:d`). He practically got two hranges and qrange is pretty much pointless for IPv6 addresses. This change uses the `ip6addr` package to parse IP addresses and convert it to some canonical form. This means: * IPv4 and IPv4-mapped IPv6 addresses are converted to normal IPv4 notation. * Zero are not elided in IPv6 (so you'll never see `::`). * IPv6 addresses are not zero padded (so `..:1` instead of `..:0001`). * Even though it's not documented, it seems like `ip6addr` always generates lower-case letters. This will unfortunately mean that some IP hashes may change after the update. Normal IPv4 hashes will most probably remain the same though.
4 years ago
zeroElide: false,
zeroPad: false,
});
let qrange = ''
, hrange = '';
if (ipKind === 'ipv4') {
qrange = createCIDR(ipStr, 24).toString();
hrange = createCIDR(ipStr, 16).toString();
} else {
qrange = createCIDR(ipStr, 64).toString();
hrange = createCIDR(ipStr, 48).toString();
}
res.locals.ip = {
normalize IP addresses Currently jschan takes the IP address as a string from the `X-Real-Ip` header, which based on the frontend proxy configuration, OS settings, etc. can take various forms: IPv4 addresses can be given in normal IPv4 dotted notation (e.g. `1.2.3.4`) or as an IPv4-mapped IPv6 address (e.g. `::ffff:1.2.3.4`). The problem is, that in the latter case, node's `isIP` will report 6, so the code will try to split it along colons, breaking hrange and qrange. With IPv6 addresses, it's possible to elide runs of zeroes, so `::1` and `0:0:0:0:0:0:0:1` (and also `0000:0000:0000:0000:0000:0000:0000:0001`) represents the same address. Since it's pretty easy to get a /64 IPv6 block, a spammer can abuse it, by spamming from `a:b:c:d::1` (`qrange=a:b:c:d`, `hrange=a:b:c`), then from `a:b:c:d::1:1` (`qrange=a:b:c:d:`, `hrange=a:b:c`), `a:b:c:d::1:1:1` (`qrange=a:b:c:d::1`, `hrange=a:b:c:d`) and `a:b:c:d:1:1:1:1` (`qrange=a:b:c:d:1:1`, `hrange=a:b:c:d`). He practically got two hranges and qrange is pretty much pointless for IPv6 addresses. This change uses the `ip6addr` package to parse IP addresses and convert it to some canonical form. This means: * IPv4 and IPv4-mapped IPv6 addresses are converted to normal IPv4 notation. * Zero are not elided in IPv6 (so you'll never see `::`). * IPv6 addresses are not zero padded (so `..:1` instead of `..:0001`). * Even though it's not documented, it seems like `ip6addr` always generates lower-case letters. This will unfortunately mean that some IP hashes may change after the update. Normal IPv4 hashes will most probably remain the same though.
4 years ago
raw: ipHashPermLevel === -1 ? hashIp(ipStr) : ipStr,
single: hashIp(ipStr),
qrange: hashIp(qrange),
hrange: hashIp(hrange),
}
next();
normalize IP addresses Currently jschan takes the IP address as a string from the `X-Real-Ip` header, which based on the frontend proxy configuration, OS settings, etc. can take various forms: IPv4 addresses can be given in normal IPv4 dotted notation (e.g. `1.2.3.4`) or as an IPv4-mapped IPv6 address (e.g. `::ffff:1.2.3.4`). The problem is, that in the latter case, node's `isIP` will report 6, so the code will try to split it along colons, breaking hrange and qrange. With IPv6 addresses, it's possible to elide runs of zeroes, so `::1` and `0:0:0:0:0:0:0:1` (and also `0000:0000:0000:0000:0000:0000:0000:0001`) represents the same address. Since it's pretty easy to get a /64 IPv6 block, a spammer can abuse it, by spamming from `a:b:c:d::1` (`qrange=a:b:c:d`, `hrange=a:b:c`), then from `a:b:c:d::1:1` (`qrange=a:b:c:d:`, `hrange=a:b:c`), `a:b:c:d::1:1:1` (`qrange=a:b:c:d::1`, `hrange=a:b:c:d`) and `a:b:c:d:1:1:1:1` (`qrange=a:b:c:d:1:1`, `hrange=a:b:c:d`). He practically got two hranges and qrange is pretty much pointless for IPv6 addresses. This change uses the `ip6addr` package to parse IP addresses and convert it to some canonical form. This means: * IPv4 and IPv4-mapped IPv6 addresses are converted to normal IPv4 notation. * Zero are not elided in IPv6 (so you'll never see `::`). * IPv6 addresses are not zero padded (so `..:1` instead of `..:0001`). * Even though it's not documented, it seems like `ip6addr` always generates lower-case letters. This will unfortunately mean that some IP hashes may change after the update. Normal IPv4 hashes will most probably remain the same though.
4 years ago
} catch(e) {
console.error('Ip parse failed', e);
return res.status(400).render('message', {
'title': 'Bad request',
'message': 'Malformed IP' //should never get here
});
}
}