1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "base/weak_ptr.h"
11 
12 #include <QtCore/QPointer>
13 #include <QtNetwork/QNetworkReply>
14 #include <optional>
15 
16 namespace MTP::details {
17 
18 [[nodiscard]] const std::vector<QString> &DnsDomains();
19 [[nodiscard]] QString GenerateDnsRandomPadding();
20 [[nodiscard]] QByteArray DnsUserAgent();
21 
22 struct DnsEntry {
23 	QString data;
24 	crl::time TTL = 0;
25 };
26 
27 [[nodiscard]] std::vector<DnsEntry> ParseDnsResponse(
28 	const QByteArray &bytes,
29 	std::optional<int> typeRestriction = std::nullopt);
30 
31 struct ServiceWebRequest {
32 	ServiceWebRequest(not_null<QNetworkReply*> reply);
33 	ServiceWebRequest(ServiceWebRequest &&other);
34 	ServiceWebRequest &operator=(ServiceWebRequest &&other);
35 	~ServiceWebRequest();
36 
37 	void destroy();
38 
39 	QPointer<QNetworkReply> reply;
40 };
41 
42 class DomainResolver : public QObject {
43 public:
44 	DomainResolver(Fn<void(
45 		const QString &domain,
46 		const QStringList &ips,
47 		crl::time expireAt)> callback);
48 
49 	void resolve(const QString &domain);
50 
51 private:
52 	enum class Type {
53 		Mozilla,
54 		Google,
55 	};
56 	struct Attempt {
57 		Type type;
58 		QString data;
59 		QString host;
60 	};
61 	struct AttemptKey {
62 		QString domain;
63 		bool ipv6 = false;
64 
65 		inline bool operator<(const AttemptKey &other) const {
66 			return (domain < other.domain)
67 				|| (domain == other.domain && !ipv6 && other.ipv6);
68 		}
69 		inline bool operator==(const AttemptKey &other) const {
70 			return (domain == other.domain) && (ipv6 == other.ipv6);
71 		}
72 	};
73 	struct CacheEntry {
74 		QStringList ips;
75 		crl::time expireAt = 0;
76 	};
77 	struct Attempts {
78 		std::vector<Attempt> list;
79 		base::has_weak_ptr guard;
80 	};
81 
82 	void resolve(const AttemptKey &key);
83 	void sendNextRequest(const AttemptKey &key);
84 	void performRequest(const AttemptKey &key, const Attempt &attempt);
85 	void checkExpireAndPushResult(const QString &domain);
86 	void requestFinished(
87 		const AttemptKey &key,
88 		not_null<QNetworkReply*> reply);
89 	QByteArray finalizeRequest(
90 		const AttemptKey &key,
91 		not_null<QNetworkReply*> reply);
92 
93 	Fn<void(
94 		const QString &domain,
95 		const QStringList &ips,
96 		crl::time expireAt)> _callback;
97 
98 	QNetworkAccessManager _manager;
99 	std::map<AttemptKey, Attempts> _attempts;
100 	std::map<AttemptKey, std::vector<ServiceWebRequest>> _requests;
101 	std::map<AttemptKey, CacheEntry> _cache;
102 	crl::time _lastTimestamp = 0;
103 
104 };
105 
106 } // namespace MTP::details
107