-
Notifications
You must be signed in to change notification settings - Fork 811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add IPv6 block rotating #713
Conversation
I would like to also give our test results about IP Bans (tested on a 6.5k+ servers discord music bot):
|
Fixing the format of files so eslint does not throw any errors.
I guess you already spottet that the CI asks you to add tests for the new code lines 😉 |
How do we make tests? |
Done |
hi, thanks for the PR Roki and Million900o! it's pretty impressive that there are no bans with this on your bot during your testing. how long have you ran it for using the PR?
I'm going to start looking at this within the next day or so, but I will say that generally a PR is one change. keeping PRs small and contained to their scope not only makes the review process simpler, but it makes history cleaner, release changes easier to list, and if we ever have to please separate the above two changes into 2 PRs. I'd keep this one, remove any changes about disabling chunking since those changes should be smaller than IPv6 rotating, and create another one with only the chunking changes. but also, chunking can be disabled with |
The bot currently runs on a /64 block for over a week now and there are no bans so far Also, what do i do to remove chunking changes from this pr? like just remove them and make a commit or there is a command for that? I am not sure about the |
remove the changes for it and make a commit
how about |
will do in a sec
Hmm wouldnt it make ytdl go crazy? let start = (options.range && options.range.start) || 0;
let end = start + dlChunkSize; so like start and end will be the same |
oh i meant have it be turned off if it detects that |
Hmmm, i might change it to that then i guess(with addition to readme), but first of all i have to remove chunking stuff from this pr and open second one |
Okay, i think i've removed every change for chunking |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
boy typing with a broken hand suxx
next time i'll send a voice memo
README.md
Outdated
@@ -149,11 +151,16 @@ ytdl cannot download videos that fall into the following | |||
* YouTube Premium content (if you have access, requires [cookies](example/cookies.js)) | |||
|
|||
Generated download links are valid for 6 hours, and may only be downloadable from the same IP address. | |||
Using IPv6 should not cause same IP address limitation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you check with
- different ip from same /64 blocks or
- even different /64 blocks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i did check with multiple ipv4's and ipv6 in same /64
lib/utils.js
Outdated
*/ | ||
exports.getRandomIPv6 = block => { | ||
let subnet = parseInt(block.split('/')[1]); | ||
block = block.split('/')[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm personally not a fan of reassigning to passed variables
also calling the expensive split function twice....
how about sth like
const [net, rawSubnet] = block.split('/');
const subnet = parseInt(rawSubnet)
?
lib/utils.js
Outdated
block = block.split('/')[0]; | ||
if (!subnet || subnet > 128 || subnet < 24) throw Error('Invalid IPv6 subnet'); | ||
// Other errors will be thrown by ip6 itself | ||
return ip6.randomSubnet(block, subnet, 128, 1, true)[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i see we're not first rolling the /64 net
like it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea it was a requested change by you so i changed 👀
test/full-info-test.js
Outdated
describe('With IPv6 Block', () => { | ||
it('Sends request with IPv6 address', async() => { | ||
const id = '_HSylqgVYQI'; | ||
const scope = nock(id, 'regular'); | ||
let info = await ytdl.getInfo(id, { IPv6Block: '2001:2::/48' }); | ||
nock.url(info.formats[0].url).reply(function checkAddr() { | ||
// "this" is assigned by the function checkAddr | ||
// eslint-disable-next-line no-invalid-this | ||
assert.ok(net.isIPv6(this.req.options.localAddress)); | ||
scope.done(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('With invalid IPv6 Block', () => { | ||
it('Should give an error', async() => { | ||
const id = '_HSylqgVYQI'; | ||
await assert.rejects(ytdl.getInfo(id, { IPv6Block: '2001:2::/200' }), /Invalid IPv6 subnet/); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could test the getRandomIPv6
(but not here) function instead of doing the same pass an ipv6
test (like above) twice
so that we do
a) test the whole usage via ytdl-core once
b) do white box tests only on the getRandomIPv6
function for error like
b.a) no subnet (2001:2::
) or
b.b) subnet only (/64
) or
b.c) passing errors from ip6.randomSubnet
if you wanna get rid of that ipv6 library 😉 const randomIP = (ip) => {
const [addr, mask] = ip.split('/');
// normalize inputs
let base10Mask = parseInt(mask);
const base10addr = normalizeIP(addr);
// get random addr to pad with
// using Math.random since we're not requiring high level of randomness
const randomAddr = new Array(8).fill(1).map(x => Math.floor(Math.random() * 0xffff));
// merge base10addr with randomAddr
const mergedAddr = randomAddr.map((randomItem, idx) => {
// calculate the amount of static bits
const staticBits = Math.min(base10Mask, 16);
// adjust the bitmask with the staticBits
base10Mask -= staticBits;
// calculate the bitmask
// lsb makes the calculation way more complicated
const mask = 0xffff - ((2**(16 - staticBits)) - 1);
// combine base10addr and random
return (base10addr[idx] & mask) + (randomItem & (mask ^ 0xffff));
});
// return new addr
return mergedAddr.map(x => x.toString('16')).join(':');
}
const normalizeIP = (ip) => {
// split by fill position
const parts = ip.split('::').map(x => x.split(':'));
// normalize start and end
const partStart = parts[0] || [];
const partEnd = parts[1] || [];
// placeholder for full ip
const fullIP = new Array(8).fill(0);
// fill in start and end parts
for (let i = 0; i < Math.min(partStart.length, 7); i++) {
fullIP[i] = parseInt(partStart[i], 16) || 0;
}
for (let i = 0; i < Math.min(partEnd.length, 7) ; i++) {
fullIP[7 - i] = parseInt(partEnd[i], 16) || 0;
}
return fullIP;
} |
Can anyone help me to setup IPv6 on AWS console and setting it up with? (I already have all the codes in place in the latest version.) I really can’t get it working. |
@Roki100 can you have another look, pls |
oh, yea sure, i have to come back from holiday tho as i dont have pc atm (3 days) |
sure - just tell me when you had a look 😉 |
Co-authored-by: Voltrex <mohammadkeyvanzade94@gmail.com>
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
@TimeForANinja aww, my bad on not responding, yeah everything seems to be fine 👍 |
🎉 This PR is included in version 4.11.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This feature was coded in a collab with @Million900o
Hello! I would like to present the new feature(s):
How does the method implemented work: in short, it uses different IPv6 address each time you download/request something via ytdl, for larger blocks(that include more that one /64) it also uses random /64 to make IP Bans impossible to get.
Feel free to propose changes, as this code is for sure not the cleanest
Note: The IPv6 rotating will work only if the block provided is owned by you and configured in the OS!
For setting up guide i recommend reading:
https://contabo.com/blog/adding-ipv6-connectivity-to-your-server
https://contabo.com/blog/configuring-additional-ip-addresses/
https://support.us.ovhcloud.com/hc/en-us/articles/360002296020-How-to-Configure-an-IPv6-Address-in-Ubuntu
Or googling for more tutorials.
Also note: This functionality has been tested with /64, /58 and /48 blocks, and it works, however its a first version and i will keep improving that.
Adding new ytdl dependency was needed because its kinda complex/huge math to get a random ipv6 subnet.
closes #635
Inspired by Lavalink's rotator.