anidex: fix ddos protection bypass. resolves #8095 (#8106)

This commit is contained in:
Diego Heras 2020-04-11 04:46:15 +02:00 committed by GitHub
parent dd8556d21d
commit 8d8622479d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 24 additions and 70 deletions

View File

@ -4,6 +4,7 @@ using System.Collections.Specialized;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AngleSharp.Dom; using AngleSharp.Dom;
@ -21,7 +22,7 @@ namespace Jackett.Common.Indexers
public class Anidex : BaseWebIndexer public class Anidex : BaseWebIndexer
{ {
public Anidex(IIndexerConfigurationService configService, Utils.Clients.WebClient wc, Logger l, IProtectionService ps) public Anidex(IIndexerConfigurationService configService, Utils.Clients.WebClient wc, Logger l, IProtectionService ps)
: base(name: "Anidex", : base("Anidex",
description: "Anidex is a Public torrent tracker and indexer, primarily for English fansub groups of anime", description: "Anidex is a Public torrent tracker and indexer, primarily for English fansub groups of anime",
link: "https://anidex.info/", link: "https://anidex.info/",
caps: new TorznabCapabilities(), caps: new TorznabCapabilities(),
@ -130,15 +131,6 @@ namespace Jackett.Common.Indexers
protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query) protected override async Task<IEnumerable<ReleaseInfo>> PerformQuery(TorznabQuery query)
{ {
try
{
await ConfigureDDoSGuardCookie();
}
catch (Exception ex)
{
logger.Log(LogLevel.Warn, ex, $"Exception while configuring DDoS Guard cookie. Attempting search without. (Exception: {ex})");
}
// Get specified categories. If none were specified, use all available. // Get specified categories. If none were specified, use all available.
var searchCategories = MapTorznabCapsToTrackers(query); var searchCategories = MapTorznabCapsToTrackers(query);
if (searchCategories.Count == 0) if (searchCategories.Count == 0)
@ -159,12 +151,15 @@ namespace Jackett.Common.Indexers
var searchUri = GetAbsoluteUrl("?" + queryParameters.GetQueryString()); var searchUri = GetAbsoluteUrl("?" + queryParameters.GetQueryString());
var response = await RequestStringWithCookiesAndRetry(searchUri.AbsoluteUri); var response = await RequestStringWithCookiesAndRetry(searchUri.AbsoluteUri);
// Check for DDOS Guard or other error // Check for DDOS Guard
if (response.Status == System.Net.HttpStatusCode.Forbidden) if (response.Status == System.Net.HttpStatusCode.Forbidden)
throw new IOException("Anidex search was forbidden. This was likely caused by DDOS protection."); {
await ConfigureDDoSGuardCookie();
response = await RequestStringWithCookiesAndRetry(searchUri.AbsoluteUri);
}
if (response.Status != System.Net.HttpStatusCode.OK) if (response.Status != System.Net.HttpStatusCode.OK)
throw new IOException($"Anidex search returned unexpected result. Expected 200 OK but got {response.Status.ToString()}."); throw new WebException($"Anidex search returned unexpected result. Expected 200 OK but got {response.Status}.", WebExceptionStatus.ProtocolError);
// Search seems to have been a success so parse it // Search seems to have been a success so parse it
return ParseResult(response.Content); return ParseResult(response.Content);
@ -219,55 +214,14 @@ namespace Jackett.Common.Indexers
private async Task ConfigureDDoSGuardCookie() private async Task ConfigureDDoSGuardCookie()
{ {
const string pathAndQueryBase64Encoded = "Lw=="; // "/" const string ddosPostUrl = "https://check.ddos-guard.net/check.js";
const string baseUriBase64Encoded = "aHR0cHM6Ly9hbmlkZXguaW5mbw=="; // "http://anidex.info" var response = await RequestStringWithCookies(ddosPostUrl, string.Empty);
const string ddosPostUrl = "https://ddgu.ddos-guard.net/ddgu/"; if (response.Status != System.Net.HttpStatusCode.OK)
throw new WebException($"Unexpected DDOS Guard response: Status: {response.Status}", WebExceptionStatus.ProtocolError);
try if (response.IsRedirect)
{ throw new WebException($"Unexpected DDOS Guard response: Redirect: {response.RedirectingTo}", WebExceptionStatus.UnknownError);
// Check if the cookie already exists, if so exit without doing anything if (string.IsNullOrWhiteSpace(response.Cookies))
if (IsCookiePresent("__ddgu") && IsCookiePresent("__ddg1")) throw new WebException("Unexpected DDOS Guard response: Empty cookie", WebExceptionStatus.ReceiveFailure);
{
logger.Debug("DDOS Guard cookies are already present. Skipping bypass.");
return;
}
// Make a request to DDoS Guard to get the redirect URL
var ddosPostData = new List<KeyValuePair<string, string>>
{
{ "u", pathAndQueryBase64Encoded },
{ "h", baseUriBase64Encoded },
{ "p", string.Empty }
};
var result = await PostDataWithCookiesAndRetry(ddosPostUrl, ddosPostData);
if (!result.IsRedirect)
// Success returns a redirect. For anything else, assume a failure.
throw new IOException($"Unexpected result from DDOS Guard while attempting to bypass: {result.Content}");
// Call the redirect URL to retrieve the cookie
result = await RequestStringWithCookiesAndRetry(result.RedirectingTo);
if (!result.IsRedirect)
// Success is another redirect. For anything else, assume a failure.
throw new IOException($"Unexpected result when returning from DDOS Guard bypass: {result.Content}");
// If we got to this point, the bypass should have succeeded and we have stored the necessary cookies to access the site normally.
}
catch (Exception ex)
{
throw new IOException($"Error while configuring DDoS Guard cookie: {ex}");
}
}
private bool IsCookiePresent(string name)
{
var rawCookies = CookieHeader.Split(';');
IDictionary<string, string> cookies = rawCookies
.Where(e => e.Contains('='))
.ToDictionary((e) => e.Split('=')[0].Trim(), (e) => e.Split('=')[1].Trim());
return cookies.ContainsKey(name);
} }
private static TResult ParseValueFromRow<TResult>(IElement row, string propertyName, string selector, private static TResult ParseValueFromRow<TResult>(IElement row, string propertyName, string selector,