cloudcheck 8.7.1__cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. cloudcheck/__init__.py +3 -0
  2. cloudcheck/cloudcheck.cpython-311-i386-linux-gnu.so +0 -0
  3. cloudcheck/helpers.py +249 -0
  4. cloudcheck/providers/__init__.py +51 -0
  5. cloudcheck/providers/akamai.py +35 -0
  6. cloudcheck/providers/alibaba.py +13 -0
  7. cloudcheck/providers/amazon.py +39 -0
  8. cloudcheck/providers/arvancloud.py +22 -0
  9. cloudcheck/providers/backblaze.py +13 -0
  10. cloudcheck/providers/baidu.py +17 -0
  11. cloudcheck/providers/base.py +317 -0
  12. cloudcheck/providers/cachefly.py +26 -0
  13. cloudcheck/providers/cdnetworks.py +14 -0
  14. cloudcheck/providers/cisco.py +41 -0
  15. cloudcheck/providers/cloudflare.py +42 -0
  16. cloudcheck/providers/cloudfront.py +20 -0
  17. cloudcheck/providers/ddosguard.py +14 -0
  18. cloudcheck/providers/dell.py +13 -0
  19. cloudcheck/providers/digitalocean.py +32 -0
  20. cloudcheck/providers/dod.py +31 -0
  21. cloudcheck/providers/fastly.py +24 -0
  22. cloudcheck/providers/fbi.py +18 -0
  23. cloudcheck/providers/gabia.py +12 -0
  24. cloudcheck/providers/gcore.py +27 -0
  25. cloudcheck/providers/github.py +30 -0
  26. cloudcheck/providers/gocache.py +17 -0
  27. cloudcheck/providers/google.py +63 -0
  28. cloudcheck/providers/heroku.py +9 -0
  29. cloudcheck/providers/hetzner.py +20 -0
  30. cloudcheck/providers/hostway.py +13 -0
  31. cloudcheck/providers/hpe.py +14 -0
  32. cloudcheck/providers/huawei.py +19 -0
  33. cloudcheck/providers/ibm.py +59 -0
  34. cloudcheck/providers/imperva.py +27 -0
  35. cloudcheck/providers/kamatera.py +19 -0
  36. cloudcheck/providers/kinx.py +14 -0
  37. cloudcheck/providers/ktcloud.py +14 -0
  38. cloudcheck/providers/leaseweb.py +32 -0
  39. cloudcheck/providers/lgtelecom.py +13 -0
  40. cloudcheck/providers/microsoft.py +39 -0
  41. cloudcheck/providers/microsoft365.py +33 -0
  42. cloudcheck/providers/navercloud.py +15 -0
  43. cloudcheck/providers/nhncloud.py +15 -0
  44. cloudcheck/providers/oracle.py +33 -0
  45. cloudcheck/providers/ovh.py +17 -0
  46. cloudcheck/providers/qrator.py +16 -0
  47. cloudcheck/providers/quiccloud.py +38 -0
  48. cloudcheck/providers/rackspace.py +23 -0
  49. cloudcheck/providers/ru_fso.py +13 -0
  50. cloudcheck/providers/salesforce.py +17 -0
  51. cloudcheck/providers/scaleway.py +17 -0
  52. cloudcheck/providers/skbroadband.py +13 -0
  53. cloudcheck/providers/stormwall.py +14 -0
  54. cloudcheck/providers/sucuri.py +14 -0
  55. cloudcheck/providers/tencent.py +17 -0
  56. cloudcheck/providers/uk_mod.py +16 -0
  57. cloudcheck/providers/wasabi.py +17 -0
  58. cloudcheck/providers/x4b.py +14 -0
  59. cloudcheck/providers/zoho.py +27 -0
  60. cloudcheck/providers/zscaler.py +25 -0
  61. cloudcheck-8.7.1.dist-info/METADATA +251 -0
  62. cloudcheck-8.7.1.dist-info/RECORD +63 -0
  63. cloudcheck-8.7.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,317 @@
1
+ import ipaddress
2
+ import os
3
+ import traceback
4
+ import subprocess
5
+ import time
6
+ from concurrent.futures import ThreadPoolExecutor, as_completed
7
+ from pathlib import Path
8
+ from typing import Dict, List, Union
9
+ from pydantic import BaseModel, field_validator, computed_field
10
+
11
+ from ..helpers import defrag_cidrs, parse_v2fly_domain_file, request
12
+
13
+
14
+ v2fly_repo_pulled = False
15
+
16
+
17
+ class BaseProvider(BaseModel):
18
+ """
19
+ Base class for all cloud providers.
20
+
21
+ Each provider inherits from this class and overrides any of the default values.
22
+ They can also override the update_cidrs() method to fetch cidrs from a different source.
23
+ """
24
+
25
+ # these values are static and always loaded from the class definition
26
+ regexes: Dict[str, List[str]] = {}
27
+ tags: List[str] = [] # Tags for the provider (e.g. "cdn", "waf", etc.)
28
+ org_ids: List[str] = [] # ASN Organization IDs (e.g. GOGL-ARIN)
29
+ v2fly_company: str = "" # Company name for v2fly domain fetching
30
+ short_description: str = "" # Short description of the provider
31
+ long_description: str = "" # Long description of the provider
32
+
33
+ # these values are dynamic and set by the update() method
34
+ last_updated: float = time.time()
35
+
36
+ # these we allow static values but they are later merged with dynamic values
37
+ asns: List[int] = []
38
+ cidrs: List[str] = []
39
+ domains: List[str] = []
40
+
41
+ @field_validator("cidrs")
42
+ @classmethod
43
+ def validate_cidrs(cls, value):
44
+ ips = []
45
+ for v in value:
46
+ try:
47
+ ips.append(ipaddress.ip_network(v, strict=False))
48
+ except ValueError:
49
+ print(f"Invalid CIDR: from {cls.__name__}: {v}")
50
+ continue
51
+ ips = [str(ip) for ip in defrag_cidrs(ips)]
52
+ return sorted(ips)
53
+
54
+ @field_validator("domains")
55
+ @classmethod
56
+ def validate_domains(cls, value):
57
+ return sorted(list(set([d.lower().strip(".") for d in value])))
58
+
59
+ @computed_field(return_type=str)
60
+ @property
61
+ def name(self):
62
+ return self.__class__.__name__
63
+
64
+ def __init__(self, **data):
65
+ super().__init__(**data)
66
+ self._cidrs = []
67
+ self._cache_dir = Path.home() / ".cache" / "cloudcheck"
68
+ self._repo_url = "https://github.com/v2fly/domain-list-community.git"
69
+ self._asndb_url = os.getenv("ASNDB_URL", "https://asndb.api.bbot.io/v1")
70
+ self._bbot_io_api_key = os.getenv("BBOT_IO_API_KEY")
71
+
72
+ def update(self):
73
+ print(f"Updating {self.name}")
74
+ errors = []
75
+ errors.extend(self.update_domains())
76
+ errors.extend(self.update_cidrs())
77
+ return errors
78
+
79
+ def update_domains(self):
80
+ # update dynamic domains
81
+ errors = []
82
+ domains = set()
83
+
84
+ # fetch any dynamically-updated lists of domains
85
+ try:
86
+ dynamic_domains = self.fetch_domains()
87
+ print(f"Got {len(dynamic_domains)} dynamic domains for {self.name}")
88
+ domains.update(dynamic_domains)
89
+ except Exception as e:
90
+ errors.append(
91
+ f"Failed to fetch dynamic domains for {self.name}: {e}:\n{traceback.format_exc()}"
92
+ )
93
+
94
+ if self.v2fly_company:
95
+ _domains, _errors = self.fetch_v2fly_domains()
96
+ if _domains:
97
+ domains.update(_domains)
98
+ else:
99
+ errors.append(
100
+ f"No v2fly domains were found for {self.name} (company name: {self.v2fly_company})"
101
+ )
102
+ errors.extend(_errors)
103
+
104
+ # finally, put in any manually-specified domains
105
+ print(f"Adding {len(self.domains)} manually-specified domains for {self.name}")
106
+ if self.domains:
107
+ domains.update(self.domains)
108
+
109
+ print(f"Total {len(domains)} domains for {self.name}")
110
+
111
+ try:
112
+ self.domains = self.validate_domains(domains)
113
+ except Exception as e:
114
+ errors.append(
115
+ f"Error validating domains for {self.name}: {e}:\n{traceback.format_exc()}"
116
+ )
117
+
118
+ return errors
119
+
120
+ def update_cidrs(self):
121
+ cidrs = set()
122
+ errors = []
123
+
124
+ # query by direct ASNs
125
+ if self.asns:
126
+ _cidrs, _errors = self.fetch_asns()
127
+ print(f"Got {len(_cidrs)} ASN cidrs for {self.name}'s ASNs {self.asns}")
128
+ if not _cidrs:
129
+ errors.append(
130
+ f"No ASN cidrs were found for {self.name}'s ASNs {self.asns}"
131
+ )
132
+ errors.extend(_errors)
133
+ cidrs.update(_cidrs)
134
+
135
+ # query by org IDs
136
+ if self.org_ids:
137
+ _cidrs, _asns, _errors = self.fetch_org_ids()
138
+ _asns = _asns.copy()
139
+ _asns.update(self.asns)
140
+ self.asns = list(sorted(_asns))
141
+ print(
142
+ f"Got {len(_cidrs)} org id cidrs for {self.name}'s org ids {self.org_ids}"
143
+ )
144
+ if not _cidrs:
145
+ errors.append(
146
+ f"No cidrs were found for {self.name}'s org ids {self.org_ids}"
147
+ )
148
+ errors.extend(_errors)
149
+ cidrs.update(_cidrs)
150
+
151
+ # fetch any dynamically-updated lists of CIDRs
152
+ try:
153
+ dynamic_cidrs = self.fetch_cidrs()
154
+ print(f"Got {len(dynamic_cidrs)} dynamic cidrs for {self.name}")
155
+ cidrs.update(dynamic_cidrs)
156
+ except Exception as e:
157
+ errors.append(
158
+ f"Failed to fetch dynamic cidrs for {self.name}: {e}:\n{traceback.format_exc()}"
159
+ )
160
+
161
+ # finally, put in any manually-specified CIDRs
162
+ print(f"Adding {len(self.cidrs)} manually-specified cidrs for {self.name}")
163
+ if self.cidrs:
164
+ cidrs.update(self.cidrs)
165
+
166
+ print(f"Total {len(cidrs)} cidrs for {self.name}")
167
+
168
+ try:
169
+ self.cidrs = self.validate_cidrs(cidrs)
170
+ except Exception as e:
171
+ errors.append(
172
+ f"Error validating ASN cidrs for {self.name}: {e}:\n{traceback.format_exc()}"
173
+ )
174
+
175
+ self.last_updated = time.time()
176
+
177
+ return errors
178
+
179
+ def _fetch_org_id(self, org_id: str):
180
+ """Fetch ASNs for a single org_id."""
181
+ print(f"Fetching cidrs for {org_id} from asndb")
182
+ try:
183
+ url = f"{self._asndb_url}/org/{org_id}"
184
+ print(f"Fetching {url}")
185
+ res = self.request(url, include_api_key=True)
186
+ print(f"{url} -> {res}: {res.text}")
187
+ j = res.json()
188
+ return j.get("asns", []), []
189
+ except Exception as e:
190
+ error = f"Failed to fetch cidrs for {org_id} from asndb: {e}:\n{traceback.format_exc()}"
191
+ return [], [error]
192
+
193
+ def fetch_org_ids(
194
+ self,
195
+ ) -> List[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
196
+ """Takes org_ids and populates the .asns and .cidrs attributes."""
197
+ errors = []
198
+ cidrs = set()
199
+ print(f"Fetching {len(self.org_ids)} org ids for {self.name}")
200
+ asns = set()
201
+
202
+ # Parallelize org_id fetching
203
+ with ThreadPoolExecutor() as executor:
204
+ org_futures = {
205
+ executor.submit(self._fetch_org_id, org_id): org_id
206
+ for org_id in self.org_ids
207
+ }
208
+ for future in as_completed(org_futures):
209
+ _asns, _errors = future.result()
210
+ errors.extend(_errors)
211
+ asns.update(_asns)
212
+
213
+ # Parallelize ASN fetching
214
+ with ThreadPoolExecutor() as executor:
215
+ asn_futures = {executor.submit(self.fetch_asn, asn): asn for asn in asns}
216
+ for future in as_completed(asn_futures):
217
+ asn_cidrs, _errors = future.result()
218
+ errors.extend(_errors)
219
+ cidrs.update(asn_cidrs)
220
+
221
+ return cidrs, asns, errors
222
+
223
+ def fetch_asns(self) -> List[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
224
+ """Fetch CIDRs for a given list of ASNs from ASNDB."""
225
+ cidrs = []
226
+ errors = []
227
+ print(f"Fetching {len(self.asns)} ASNs for {self.name}")
228
+ for asn in self.asns:
229
+ asn_cidrs, _errors = self.fetch_asn(asn)
230
+ errors.extend(_errors)
231
+ cidrs.update(asn_cidrs)
232
+ return cidrs, errors
233
+
234
+ def fetch_asn(
235
+ self, asn: int
236
+ ) -> List[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
237
+ """Fetch CIDRs for a given ASN from ASNDB."""
238
+ cidrs = []
239
+ errors = []
240
+ url = f"{self._asndb_url}/asn/{asn}"
241
+ print(f"Fetching {url}")
242
+ try:
243
+ res = self.request(url, include_api_key=True)
244
+ print(f"{url} -> {res.text}")
245
+ j = res.json()
246
+ cidrs = j.get("subnets", [])
247
+ except Exception as e:
248
+ errors.append(
249
+ f"Failed to fetch cidrs for {asn} from asndb: {e}:\n{traceback.format_exc()}"
250
+ )
251
+ print(f"Got {len(cidrs)} cidrs for {asn}")
252
+ return cidrs, errors
253
+
254
+ def fetch_v2fly_domains(self) -> List[str]:
255
+ """Fetch domains from the v2fly community repository."""
256
+ if not self.v2fly_company:
257
+ return [], []
258
+
259
+ errors = []
260
+ repo_path, _success = self._ensure_v2fly_repo_cached()
261
+ company_file = repo_path / "data" / self.v2fly_company
262
+ try:
263
+ domains = parse_v2fly_domain_file(company_file)
264
+ except Exception as e:
265
+ errors.append(
266
+ f"Failed to parse {self.v2fly_company} domains: {e}:\n{traceback.format_exc()}"
267
+ )
268
+ return sorted(list(domains)), errors
269
+
270
+ def fetch_cidrs(self) -> List[str]:
271
+ """Fetch CIDRs from a custom source."""
272
+ return []
273
+
274
+ def fetch_domains(self) -> List[str]:
275
+ """Fetch domains from a custom source."""
276
+ return []
277
+
278
+ def _ensure_v2fly_repo_cached(self) -> Path:
279
+ """Ensure the community repo is cloned and up-to-date."""
280
+ global v2fly_repo_pulled
281
+ errors = []
282
+ repo_dir = self._cache_dir / "domain-list-community"
283
+ if not repo_dir.exists():
284
+ self._cache_dir.mkdir(parents=True, exist_ok=True)
285
+ try:
286
+ subprocess.run(
287
+ ["git", "clone", "--depth", "1", self._repo_url, str(repo_dir)],
288
+ check=True,
289
+ capture_output=True,
290
+ )
291
+ v2fly_repo_pulled = True
292
+ except subprocess.CalledProcessError as e:
293
+ errors.append(
294
+ f"Failed to clone v2fly repo: {e}:\n{traceback.format_exc()}"
295
+ )
296
+ elif not v2fly_repo_pulled:
297
+ try:
298
+ subprocess.run(
299
+ ["git", "pull"], cwd=repo_dir, check=True, capture_output=True
300
+ )
301
+ except subprocess.CalledProcessError as e:
302
+ errors.append(
303
+ f"Failed to pull v2fly repo: {e}:\n{traceback.format_exc()}"
304
+ )
305
+ return repo_dir, errors
306
+
307
+ def request(self, *args, **kwargs):
308
+ headers = kwargs.get("headers", {})
309
+ headers["x-rate-limit-blocking"] = "true"
310
+ kwargs["headers"] = headers
311
+ return request(*args, **kwargs)
312
+
313
+ def __str__(self):
314
+ return self.name
315
+
316
+ def __repr__(self):
317
+ return f"{self.__class__.__name__}(name='{self.name}')"
@@ -0,0 +1,26 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Cachefly(BaseProvider):
6
+ tags: List[str] = ["cdn"]
7
+ short_description: str = "CacheFly"
8
+ long_description: str = (
9
+ "A content delivery network provider offering global CDN services."
10
+ )
11
+ # {"org_id": "CL-1923-ARIN", "org_name": "CacheFly", "country": "US", "asns": [30081]}
12
+ org_ids: List[str] = [
13
+ "CL-1923-ARIN",
14
+ ]
15
+
16
+ _ips_url = "https://cachefly.cachefly.net/ips/rproxy.txt"
17
+
18
+ def fetch_cidrs(self):
19
+ response = self.request(self._ips_url)
20
+ ranges = set()
21
+ if getattr(response, "status_code", 0) == 200:
22
+ for line in response.text.splitlines():
23
+ line = line.strip()
24
+ if line and not line.startswith("#"):
25
+ ranges.add(line)
26
+ return list(ranges)
@@ -0,0 +1,14 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Cdnetworks(BaseProvider):
6
+ tags: List[str] = ["cdn"]
7
+ short_description: str = "CDNetworks (씨디네트웍스)"
8
+ long_description: str = (
9
+ "A Korean content delivery network provider offering CDN and cloud services."
10
+ )
11
+ # {"org_id": "CDNET-ARIN", "org_name": "CDNetworks Inc.", "country": "US", "asns": [36408,40366]}
12
+ org_ids: List[str] = [
13
+ "CDNET-ARIN",
14
+ ]
@@ -0,0 +1,41 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Cisco(BaseProvider):
6
+ v2fly_company: str = "cisco"
7
+ tags: List[str] = ["cloud"]
8
+ short_description: str = "Cisco"
9
+ long_description: str = "A multinational technology corporation that designs, manufactures, and sells networking hardware, software, and telecommunications equipment."
10
+ # {"org_id": "CISCO-25-ARIN", "org_name": "Cisco Systems Inc.", "country": "US", "asns": [25949]}
11
+ # {"org_id": "CISCO-32-ARIN", "org_name": "Cisco Systems, Inc.", "country": "US", "asns": [63096]}
12
+ # {"org_id": "CISCOR-ARIN", "org_name": "CIS Corporation", "country": "US", "asns": [3792]}
13
+ # {"org_id": "CISL-7-ARIN", "org_name": "Cisco Systems Ironport Division", "country": "US", "asns": [16417,30214,30215,30238,40427]}
14
+ # {"org_id": "CS-2787-ARIN", "org_name": "Cisco Systems Inc", "country": "US", "asns": [398699]}
15
+ # {"org_id": "CS-2821-ARIN", "org_name": "Cisco IoT", "country": "US", "asns": [36180,393544]}
16
+ # {"org_id": "CS-2825-ARIN", "org_name": "Cisco Systems, Inc.", "country": "US", "asns": [396922]}
17
+ # {"org_id": "CS-2831-ARIN", "org_name": "CISCO SYSTEMS, INC.", "country": "US", "asns": [109,2051,3943,22183,23460,26092,36519,40590,54140,399780]}
18
+ # {"org_id": "CS-691-ARIN", "org_name": "Cisco Systems Cloud Division", "country": "US", "asns": [1343,32644]}
19
+ # {"org_id": "CS-985-ARIN", "org_name": "Cisco Systems, Inc.", "country": "US", "asns": [55219]}
20
+ # {"org_id": "OPEND-2-ARIN", "org_name": "Cisco OpenDNS, LLC", "country": "US", "asns": [25605,30607,36692]}
21
+ # {"org_id": "ORG-CIL21-RIPE", "org_name": "Cisco International Limited", "country": "GB", "asns": [201799]}
22
+ # {"org_id": "ORG-CL586-RIPE", "org_name": "CISCOM Ltd", "country": "RU", "asns": [61035]}
23
+ # {"org_id": "ORG-CSNA1-RIPE", "org_name": "Cisco Systems Norway AS", "country": "NO", "asns": [58298]}
24
+ # {"org_id": "WEX-ARIN", "org_name": "Cisco Webex LLC", "country": "US", "asns": [6577,13445,16472,26152,53258,399937]}
25
+ org_ids: List[str] = [
26
+ "CISCO-25-ARIN",
27
+ "CISCO-32-ARIN",
28
+ "CISCOR-ARIN",
29
+ "CISL-7-ARIN",
30
+ "CS-2787-ARIN",
31
+ "CS-2821-ARIN",
32
+ "CS-2825-ARIN",
33
+ "CS-2831-ARIN",
34
+ "CS-691-ARIN",
35
+ "CS-985-ARIN",
36
+ "OPEND-2-ARIN",
37
+ "ORG-CIL21-RIPE",
38
+ "ORG-CL586-RIPE",
39
+ "ORG-CSNA1-RIPE",
40
+ "WEX-ARIN",
41
+ ]
@@ -0,0 +1,42 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List, Dict
3
+
4
+
5
+ class Cloudflare(BaseProvider):
6
+ v2fly_company: str = "cloudflare"
7
+ tags: List[str] = ["cdn"]
8
+ short_description: str = "Cloudflare"
9
+ long_description: str = "A web infrastructure and security company providing content delivery network services, DDoS mitigation, and web security solutions."
10
+ # {"org_id": "CLOUD14-ARIN", "org_name": "Cloudflare, Inc.", "country": "US", "asns": [13335,14789,394536,395747,400095]}
11
+ # {"org_id": "ORG-CHKL1-AP-APNIC", "org_name": "Cloudflare Hong Kong, LLC", "country": "US", "asns": [133877]}
12
+ # {"org_id": "ORG-CI4-AP-APNIC", "org_name": "Cloudflare, Inc.", "country": "US", "asns": [132892]}
13
+ # {"org_id": "ORG-CI40-RIPE", "org_name": "Cloudflare Inc", "country": "US", "asns": [202623,203898]}
14
+ # {"org_id": "ORG-CLL6-RIPE", "org_name": "Cloudflare London, LLC", "country": "US", "asns": [209242]}
15
+ # {"org_id": "ORG-CSL5-AP-APNIC", "org_name": "Cloudflare Sydney, LLC", "country": "US", "asns": [139242]}
16
+ org_ids: List[str] = [
17
+ "CLOUD14-ARIN",
18
+ "ORG-CHKL1-AP-APNIC",
19
+ "ORG-CI4-AP-APNIC",
20
+ "ORG-CI40-RIPE",
21
+ "ORG-CLL6-RIPE",
22
+ "ORG-CSL5-AP-APNIC",
23
+ ]
24
+ _bucket_name_regex = r"[a-z0-9_][a-z0-9-\.]{1,61}[a-z0-9]"
25
+ regexes: Dict[str, List[str]] = {
26
+ "STORAGE_BUCKET_NAME": [_bucket_name_regex],
27
+ "STORAGE_BUCKET_HOSTNAME": [
28
+ r"(" + _bucket_name_regex + r")\.(r2\.dev)",
29
+ r"(" + _bucket_name_regex + r")\.(r2\.cloudflarestorage\.com)",
30
+ ],
31
+ }
32
+
33
+ _ips_url = "https://api.cloudflare.com/client/v4/ips"
34
+
35
+ def fetch_cidrs(self):
36
+ response = self.request(self._ips_url)
37
+ ranges = set()
38
+ response_json = response.json()
39
+ for ip_type in ("ipv4_cidrs", "ipv6_cidrs"):
40
+ for ip_range in response_json.get("result", {}).get(ip_type, []):
41
+ ranges.add(ip_range)
42
+ return list(ranges)
@@ -0,0 +1,20 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Cloudfront(BaseProvider):
6
+ tags: List[str] = ["cdn"]
7
+ short_description: str = "Amazon CloudFront"
8
+ long_description: str = "A content delivery network service provided by Amazon Web Services that delivers data, videos, applications, and APIs to customers globally."
9
+
10
+ _ips_url = "https://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips"
11
+
12
+ def fetch_cidrs(self):
13
+ response = self.request(self._ips_url)
14
+ ranges = set()
15
+ response_json = response.json()
16
+ if not isinstance(response_json, dict):
17
+ raise ValueError(f"Invalid response format: {type(response_json)}")
18
+ for r in response_json.values():
19
+ ranges.update(r)
20
+ return list(ranges)
@@ -0,0 +1,14 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class DDoSGuard(BaseProvider):
6
+ tags: List[str] = ["cdn"]
7
+ short_description: str = "DDoS Guard"
8
+ long_description: str = (
9
+ "A DDoS protection and content delivery network service provider."
10
+ )
11
+ # {"org_id": "ORG-DL236-RIPE", "org_name": "DDOS-GUARD LTD", "country": "RU", "asns": [44556,49612,57724]}
12
+ org_ids: List[str] = [
13
+ "ORG-DL236-RIPE",
14
+ ]
@@ -0,0 +1,13 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Dell(BaseProvider):
6
+ v2fly_company: str = "dell"
7
+ tags: List[str] = ["cloud"]
8
+ short_description: str = "Dell"
9
+ long_description: str = "A multinational technology company that develops, sells, repairs, and supports computers and related products and services."
10
+ # {"org_id": "DCC-25-ARIN", "org_name": "Dell, Inc.", "country": "US", "asns": [3612,3613,3614,3615,7977,12257,14876,17187,23144,30614,46507,46977,53878,54701,64208]}
11
+ org_ids: List[str] = [
12
+ "DCC-25-ARIN",
13
+ ]
@@ -0,0 +1,32 @@
1
+ import csv
2
+ from cloudcheck.providers.base import BaseProvider
3
+ from typing import List, Dict
4
+
5
+
6
+ class DigitalOcean(BaseProvider):
7
+ v2fly_company: str = "digitalocean"
8
+ tags: List[str] = ["cloud"]
9
+ short_description: str = "DigitalOcean"
10
+ long_description: str = "A cloud infrastructure provider offering virtual private servers, managed databases, and other cloud services for developers and businesses."
11
+ # {"org_id": "DO-13-ARIN", "org_name": "DigitalOcean, LLC", "country": "US", "asns": [14061,46652,62567,393406,394362]}
12
+ org_ids: List[str] = [
13
+ "DO-13-ARIN",
14
+ ]
15
+ _bucket_name_regex = r"[a-z0-9][a-z0-9-]{2,62}"
16
+ regexes: Dict[str, List[str]] = {
17
+ "STORAGE_BUCKET_NAME": [_bucket_name_regex],
18
+ "STORAGE_BUCKET_HOSTNAME": [
19
+ r"(" + _bucket_name_regex + r")\.([a-z]{3}[\d]{1}\.digitaloceanspaces\.com)"
20
+ ],
21
+ }
22
+
23
+ _ips_url = "https://www.digitalocean.com/geo/google.csv"
24
+
25
+ def fetch_cidrs(self):
26
+ response = self.request(self._ips_url)
27
+ do_ips = csv.DictReader(
28
+ response.content.decode("utf-8").splitlines(),
29
+ fieldnames=["range", "country", "region", "city", "postcode"],
30
+ )
31
+ ranges = set(i["range"] for i in do_ips)
32
+ return list(ranges)
@@ -0,0 +1,31 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class DoD(BaseProvider):
6
+ """Department of Defense"""
7
+
8
+ tags: List[str] = ["gov"]
9
+ short_description: str = "Department of Defense"
10
+ long_description: str = "A U.S. government agency responsible for coordinating and supervising all agencies and functions of the government directly related to national security and the United States Armed Forces."
11
+ org_ids: List[str] = [
12
+ "USDDD-ARIN",
13
+ ]
14
+ domains: List[str] = ["defense.gov", "war.gov", "mil"]
15
+
16
+ # https://en.wikipedia.org/wiki/List_of_assigned_/8_IPv4_address_blocks
17
+ cidrs: List[str] = [
18
+ "6.0.0.0/8", # Army Information Systems Center
19
+ "7.0.0.0/8", # DoD Network Information Center
20
+ "11.0.0.0/8", # DoD Intel Information Systems
21
+ "21.0.0.0/8", # DDN-RVN
22
+ "22.0.0.0/8", # Defense Information Systems Agency
23
+ "26.0.0.0/8", # Defense Information Systems Agency
24
+ "28.0.0.0/8", # DSI-North
25
+ "29.0.0.0/8", # Defense Information Systems Agency
26
+ "30.0.0.0/8", # Defense Information Systems Agency
27
+ "33.0.0.0/8", # DLA Systems Automation Center
28
+ "55.0.0.0/8", # DoD Network Information Center
29
+ "214.0.0.0/8", # DoD Network Information Center
30
+ "215.0.0.0/8", # DoD Network Information Center
31
+ ]
@@ -0,0 +1,24 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Fastly(BaseProvider):
6
+ v2fly_company: str = "fastly"
7
+ tags: List[str] = ["cdn"]
8
+ short_description: str = "Fastly"
9
+ long_description: str = "A content delivery network and edge cloud platform that provides edge computing, security, and performance services."
10
+ # {"org_id": "SKYCA-3-ARIN", "org_name": "Fastly, Inc.", "country": "US", "asns": [895,54113,394192]}
11
+ org_ids: List[str] = [
12
+ "SKYCA-3-ARIN",
13
+ ]
14
+
15
+ _ips_url = "https://api.fastly.com/public-ip-list"
16
+
17
+ def fetch_cidrs(self):
18
+ response = self.request(self._ips_url)
19
+ j = response.json()
20
+ if j and isinstance(j, dict):
21
+ addresses = j.get("addresses", [])
22
+ if addresses and isinstance(addresses, list):
23
+ return list(set(addresses))
24
+ return []
@@ -0,0 +1,18 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class FBI(BaseProvider):
6
+ """Federal Bureau of Investigation"""
7
+
8
+ tags: List[str] = ["gov"]
9
+ short_description: str = "Federal Bureau of Investigation"
10
+ long_description: str = "A U.S. government agency that serves as the domestic intelligence and security service, responsible for investigating federal crimes and protecting national security."
11
+ org_ids: List[str] = [
12
+ "FCJIS-ARIN", # Federal Criminal Justice Information Services
13
+ ]
14
+ domains: List[str] = [
15
+ "fbi.gov",
16
+ "fbijobs.gov",
17
+ "ic3.gov",
18
+ ]
@@ -0,0 +1,12 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Gabia(BaseProvider):
6
+ tags: List[str] = ["cloud"]
7
+ short_description: str = "Gabia (가비아)"
8
+ long_description: str = "A Korean cloud hosting and infrastructure provider."
9
+ # {"org_id": "@aut-17589-APNIC", "org_name": null, "country": null, "asns": [17589]}
10
+ org_ids: List[str] = [
11
+ "@aut-17589-APNIC",
12
+ ]
@@ -0,0 +1,27 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Gcore(BaseProvider):
6
+ tags: List[str] = ["cdn"]
7
+ short_description: str = "G-Core Labs"
8
+ long_description: str = "A content delivery network and cloud infrastructure provider offering CDN, cloud computing, and edge services."
9
+ # {"org_id": "ORG-GLS1-AP-APNIC", "org_name": "G-Core Labs S.A", "country": "LU", "asns": [59245]}
10
+ # {"org_id": "ORG-WIG6-RIPE", "org_name": "G-Core Labs S.A.", "country": "LU", "asns": [199524,202422,210559]}
11
+ org_ids: List[str] = [
12
+ "ORG-GLS1-AP-APNIC",
13
+ "ORG-WIG6-RIPE",
14
+ ]
15
+
16
+ _ips_url = "https://api.gcore.com/cdn/public-ip-list"
17
+
18
+ def fetch_cidrs(self):
19
+ response = self.request(self._ips_url)
20
+ ranges = set()
21
+ if getattr(response, "status_code", 0) == 200:
22
+ response_json = response.json()
23
+ if isinstance(response_json, dict):
24
+ for key in "addresses", "addresses_v6":
25
+ for ip_range in response_json.get(key, []):
26
+ ranges.add(ip_range)
27
+ return list(ranges)