feat(tracker): add ipV6 seeding support

This commit is contained in:
OldHawk
2018-06-07 22:47:14 +08:00
parent d84f2990c3
commit c5d74bc7c9
4 changed files with 151 additions and 36 deletions

View File

@@ -11,7 +11,7 @@ module.exports = {
'default-case': 0,
eqeqeq: [2, 'smart'],
'func-names': 0,
'guard-for-in': 2,
'guard-for-in': 0,
indent: [2, 2, { SwitchCase: 1 }],
'key-spacing': [2, { beforeColon: false, afterColon: true }],
'keyword-spacing': [2, { before: true, after: true }],

41
config/lib/bencode.js Normal file
View File

@@ -0,0 +1,41 @@
'use strict';
var b = exports;
var encode = function (input) {
var tokens = [];
if (typeof input == 'number') {
tokens.push('i');
tokens.push(input.toString());
tokens.push('e');
} else if (typeof input == 'string') {
tokens.push(input.length.toString());
tokens.push(':');
tokens.push(input);
} else if (input instanceof Array) {
tokens.push('l');
for (var i = 0; i < input.length; i++) {
tokens.push(encode(input[i]));
}
tokens.push('e');
} else if (typeof input == 'object') {
tokens.push('d');
var keys = [];
for (var ky in input) {
keys.push(ky);
}
keys.sort();
for (var j = 0; j < keys.length; j++) {
var k = keys[j];
var v = input[k];
tokens.push(encode(k));
tokens.push(encode(v));
}
tokens.push('e');
} else {
throw new Error('Unknown type for bencode.');
}
return tokens.join('');
};
b.encode = encode;

View File

@@ -13,6 +13,9 @@ var path = require('path'),
Peer = mongoose.model('Peer'),
Complete = mongoose.model('Complete'),
Finished = mongoose.model('Finished'),
bcode = require(path.resolve('./config/lib/bencode')),
benc = require('bncode'),
ipRegex = require('ip-regex'),
moment = require('moment'),
async = require('async'),
sprintf = require('sprintf-js').sprintf,
@@ -85,7 +88,7 @@ const PEER_COMPACT_SIZE = 6;
const ANNOUNCE_INTERVAL = Math.floor(announceConfig.announceInterval / 1000);
const PARAMS_INTEGER = [
'port', 'uploaded', 'downloaded', 'left', 'compact', 'numwant'
'port', 'uploaded', 'downloaded', 'left', 'compact', 'numwant', 'no_peer_id'
];
const PARAMS_STRING = [
@@ -195,8 +198,8 @@ exports.announce = function (req, res) {
done(150);
} else if (query.peer_id.length !== 20) {
done(151);
} else if (typeof query.compact === 'undefined' || query.compact !== '1') {
done(600);
// } else if (typeof query.compact === 'undefined' || query.compact !== '1') {
// done(600);
} else {
for (i = 0; i < PARAMS_INTEGER.length; i++) {
p = PARAMS_INTEGER[i];
@@ -933,26 +936,24 @@ exports.announce = function (req, res) {
if (typeof query.numwant !== 'undefined' && query.numwant > 0)
want = query.numwant;
var peerBuffer = new Buffer(want * PEER_COMPACT_SIZE);
var len = writePeers(peerBuffer, want, req.torrent._peers);
peerBuffer = peerBuffer.slice(0, len);
var peers = getPeers(want, req.torrent._peers);
var v6ip = hasV6IP(peers);
var peersFunction = v6ip ? peersDictionary : peersBinary;
var resPeers = peersFunction(peers);
mtDebug.debugGreen('---------------SEND RESPONSE TO USER----------------', 'ANNOUNCE', true, req.passkeyuser);
var resp = 'd8:intervali' + ANNOUNCE_INTERVAL + 'e8:completei' + req.torrent.torrent_seeds + 'e10:incompletei' + req.torrent.torrent_leechers + 'e10:downloadedi' + req.torrent.torrent_finished + 'e5:peers' + len + ':';
mtDebug.debugRed(resp, 'ANNOUNCE', true, req.passkeyuser);
res.writeHead(200, {
'Content-Length': resp.length + peerBuffer.length + 1,
'Content-Type': 'text/plain'
var resp = bcode.encode({
interval: ANNOUNCE_INTERVAL,
complete: req.torrent.torrent_seeds,
incomplete: req.torrent.torrent_leechers,
downloaded: req.torrent.torrent_finished,
peers: resPeers
});
res.write(resp);
res.write(peerBuffer);
res.end('e');
if (len > 0) {
mtDebug.debug(peerBuffer, 'ANNOUNCE', true, req.passkeyuser);
}
mtDebug.debugGreen('---------------SEND RESPONSE TO USER----------------', 'ANNOUNCE', true, req.passkeyuser);
mtDebug.debug('ip mode: ' + (v6ip ? 'IPv6' : 'IPv4'), 'ANNOUNCE', true, req.passkeyuser);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(resp, 'ascii');
mtDebug.debug(benc.decode(resp, 'utf8'), 'ANNOUNCE', true, req.passkeyuser);
done(null);
},
@@ -1277,14 +1278,13 @@ exports.announce = function (req, res) {
}
/**
* writePeers
* @param buf
* getPeers
* @param count
* @param peers
* @returns {number}
* @returns []
*/
function writePeers(buf, count, peers) {
var c = 0;
function getPeers(count, peers) {
var ps = [];
if (!req.seeder && event(query.event) !== EVENT_STOPPED && event(query.event) !== EVENT_COMPLETED) {
mtDebug.debugGreen('---------------GET PEERS LIST----------------', 'ANNOUNCE', true, req.passkeyuser);
@@ -1292,7 +1292,6 @@ exports.announce = function (req, res) {
mtDebug.debugRed('peers.length = ' + peers.length, 'ANNOUNCE', true, req.passkeyuser);
var p;
var bc;
var m = Math.min(peers.length, count);
for (var i = 0; i < m; i++) {
var index = 0;
@@ -1308,23 +1307,25 @@ exports.announce = function (req, res) {
if (p.user.equals(req.passkeyuser._id)) {
if (announceConfig.peersCheck.peersSendListIncludeOwnSeed) {
mtDebug.debug(p._id.toString() + ' IP:' + p.peer_ip + ' PORT:' + p.peer_port, 'ANNOUNCE', true, req.passkeyuser);
bc = compact(p);
if (bc) {
bc.copy(buf, c++ * PEER_COMPACT_SIZE);
}
ps.push({
id: p.peer_id,
ip: p.peer_ip,
port: p.peer_port
});
}
} else {
mtDebug.debug(p._id.toString() + ' IP:' + p.peer_ip + ' PORT:' + p.peer_port, 'ANNOUNCE', true, req.passkeyuser);
bc = compact(p);
if (bc) {
bc.copy(buf, c++ * PEER_COMPACT_SIZE);
}
ps.push({
id: p.peer_id,
ip: p.peer_ip,
port: p.peer_port
});
}
}
}
}
}
return c * PEER_COMPACT_SIZE;
return ps;
}
/**
@@ -1348,6 +1349,78 @@ exports.announce = function (req, res) {
return b;
}
}
/**
* hasV6IP
* @param peers
* @returns {boolean}
*/
function hasV6IP(peers) {
for (let p of peers) {
if (ipRegex.v6({exact: true}).test(p.ip)) {
return true;
}
}
return false;
}
/**
* peersDictionary
* @param peers
*/
function peersDictionary(peers) {
return peers.map(function (peer) {
if (query.no_peer_id === 1) {
return {
'ip': peer.ip,
'port': peer.port
};
} else {
return {
'peer id': peer.id,
'ip': peer.ip,
'port': peer.port
};
}
});
}
/**
* peersBinary
* @param peers
* @returns {string}
*/
function peersBinary(peers) {
var tokens = [];
peers.forEach(function (peer) {
tokens.push(peerBinary(peer.ip, peer.port));
});
return tokens.join('');
}
/**
* peerBinary
* @param ip
* @param port
* @returns {string}
*/
function peerBinary(ip, port) {
var tokens = [];
var octets = ip.split('.');
if (octets.length !== 4) return '';
octets.forEach(function (octet) {
var val = parseInt(octet, 10);
if (!isNaN(val)) tokens.push(val);
});
if (tokens.length !== 4) return '';
tokens.push((port >> 8) & 0xff);
tokens.push(port & 0xff);
return String.fromCharCode.apply(tokens, tokens);
}
};
/**

View File

@@ -81,6 +81,7 @@
"helmet": "~3.8.1",
"imagemin-pngquant": "~5.0.0",
"inbox": "^1.1.59",
"ip-regex": "^3.0.0",
"irc": "^0.5.2",
"jasmine-core": "~2.7.0",
"lodash": "^4.17.10",