cloudcheck 8.4.2__cp314-cp314-manylinux_2_38_x86_64.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.
@@ -0,0 +1,269 @@
1
+ import ipaddress
2
+ import os
3
+ import traceback
4
+ import subprocess
5
+ import time
6
+ from pathlib import Path
7
+ from typing import Dict, List, Union
8
+ from pydantic import BaseModel, field_validator, computed_field
9
+
10
+ from ..helpers import defrag_cidrs, parse_v2fly_domain_file, request
11
+
12
+
13
+ v2fly_repo_pulled = False
14
+
15
+
16
+ class BaseProvider(BaseModel):
17
+ """
18
+ Base class for all cloud providers.
19
+
20
+ Each provider inherits from this class and overrides any of the default values.
21
+ They can also override the update_cidrs() method to fetch cidrs from a different source.
22
+ """
23
+
24
+ # these values are static and always loaded from the class definition
25
+ regexes: Dict[str, List[str]] = {}
26
+ tags: List[str] = [] # Tags for the provider (e.g. "cdn", "waf", etc.)
27
+ org_ids: List[str] = [] # ASN Organization IDs (e.g. GOGL-ARIN)
28
+ v2fly_company: str = "" # Company name for v2fly domain fetching
29
+
30
+ # these values are dynamic and set by the update() method
31
+ last_updated: float = time.time()
32
+
33
+ # these we allow static values but they are later merged with dynamic values
34
+ asns: List[int] = []
35
+ cidrs: List[str] = []
36
+ domains: List[str] = []
37
+
38
+ @field_validator("cidrs")
39
+ @classmethod
40
+ def validate_cidrs(cls, value):
41
+ ips = []
42
+ for v in value:
43
+ try:
44
+ ips.append(ipaddress.ip_network(v, strict=False))
45
+ except ValueError:
46
+ print(f"Invalid CIDR: from {cls.__name__}: {v}")
47
+ continue
48
+ ips = [str(ip) for ip in defrag_cidrs(ips)]
49
+ return sorted(ips)
50
+
51
+ @field_validator("domains")
52
+ @classmethod
53
+ def validate_domains(cls, value):
54
+ return sorted(list(set([d.lower().strip(".") for d in value])))
55
+
56
+ @computed_field(return_type=str)
57
+ @property
58
+ def name(self):
59
+ return self.__class__.__name__
60
+
61
+ def __init__(self, **data):
62
+ super().__init__(**data)
63
+ print(f"Initializing {self.name}")
64
+ self._cidrs = []
65
+ self._cache_dir = Path.home() / ".cache" / "cloudcheck"
66
+ self._repo_url = "https://github.com/v2fly/domain-list-community.git"
67
+ self._asndb_url = os.getenv("ASNDB_URL", "https://asndb.api.bbot.io/v1")
68
+ self._bbot_io_api_key = os.getenv("BBOT_IO_API_KEY")
69
+
70
+ def update(self):
71
+ print(f"Updating {self.name}")
72
+ errors = []
73
+ errors.extend(self.update_domains())
74
+ errors.extend(self.update_cidrs())
75
+ return errors
76
+
77
+ def update_domains(self):
78
+ # update dynamic domains
79
+ errors = []
80
+ if self.v2fly_company:
81
+ domains, errors = self.fetch_v2fly_domains()
82
+ if domains:
83
+ self.domains = sorted(list(set(self.domains + domains)))
84
+ else:
85
+ errors.append(
86
+ f"No v2fly domains were found for {self.name} (company name: {self.v2fly_company})"
87
+ )
88
+ return errors
89
+
90
+ def update_cidrs(self):
91
+ cidrs = set()
92
+ errors = []
93
+
94
+ # query by direct ASNs
95
+ if self.asns:
96
+ _cidrs, _errors = self.fetch_asns()
97
+ print(f"Got {len(_cidrs)} ASN cidrs for {self.name}'s ASNs {self.asns}")
98
+ if not _cidrs:
99
+ errors.append(
100
+ f"No ASN cidrs were found for {self.name}'s ASNs {self.asns}"
101
+ )
102
+ errors.extend(_errors)
103
+ cidrs.update(_cidrs)
104
+
105
+ # query by org IDs
106
+ if self.org_ids:
107
+ _cidrs, _asns, _errors = self.fetch_org_ids()
108
+ _asns = _asns.copy()
109
+ _asns.update(self.asns)
110
+ self.asns = list(sorted(_asns))
111
+ print(
112
+ f"Got {len(_cidrs)} org id cidrs for {self.name}'s org ids {self.org_ids}"
113
+ )
114
+ if not _cidrs:
115
+ errors.append(
116
+ f"No cidrs were found for {self.name}'s org ids {self.org_ids}"
117
+ )
118
+ errors.extend(_errors)
119
+ cidrs.update(_cidrs)
120
+
121
+ # fetch any dynamically-updated lists of CIDRs
122
+ try:
123
+ dynamic_cidrs = self.fetch_cidrs()
124
+ print(f"Got {len(dynamic_cidrs)} dynamic cidrs for {self.name}")
125
+ cidrs.update(dynamic_cidrs)
126
+ except Exception as e:
127
+ errors.append(
128
+ f"Failed to fetch dynamic cidrs for {self.name}: {e}:\n{traceback.format_exc()}"
129
+ )
130
+
131
+ # finally, put in any manually-specified CIDRs
132
+ print(f"Adding {len(self.cidrs)} manually-specified cidrs for {self.name}")
133
+ if self.cidrs:
134
+ cidrs.update(self.cidrs)
135
+
136
+ print(f"Total {len(cidrs)} cidrs for {self.name}")
137
+
138
+ try:
139
+ self.cidrs = self.validate_cidrs(cidrs)
140
+ except Exception as e:
141
+ errors.append(
142
+ f"Error validating ASN cidrs for {self.name}: {e}:\n{traceback.format_exc()}"
143
+ )
144
+
145
+ self.last_updated = time.time()
146
+
147
+ return errors
148
+
149
+ def fetch_org_ids(
150
+ self,
151
+ ) -> List[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
152
+ """Takes org_ids and populates the .asns and .cidrs attributes."""
153
+ errors = []
154
+ cidrs = set()
155
+ print(f"Fetching {len(self.org_ids)} org ids for {self.name}")
156
+ asns = set()
157
+ for org_id in self.org_ids:
158
+ print(f"Fetching cidrs for {org_id} from asndb")
159
+ try:
160
+ url = f"{self._asndb_url}/org/{org_id}"
161
+ print(f"Fetching {url}")
162
+ res = self.request(url, include_api_key=True)
163
+ print(f"{url} -> {res}: {res.text}")
164
+ j = res.json()
165
+ except Exception as e:
166
+ errors.append(
167
+ f"Failed to fetch cidrs for {org_id} from asndb: {e}:\n{traceback.format_exc()}"
168
+ )
169
+ continue
170
+ _asns = j.get("asns", [])
171
+ for asn in _asns:
172
+ asns.add(asn)
173
+ asn_cidrs, _errors = self.fetch_asn(asn)
174
+ errors.extend(_errors)
175
+ cidrs.update(asn_cidrs)
176
+ return cidrs, asns, errors
177
+
178
+ def fetch_asns(self) -> List[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
179
+ """Fetch CIDRs for a given list of ASNs from ASNDB."""
180
+ cidrs = []
181
+ errors = []
182
+ print(f"Fetching {len(self.asns)} ASNs for {self.name}")
183
+ for asn in self.asns:
184
+ asn_cidrs, _errors = self.fetch_asn(asn)
185
+ errors.extend(_errors)
186
+ cidrs.update(asn_cidrs)
187
+ return cidrs, errors
188
+
189
+ def fetch_asn(
190
+ self, asn: int
191
+ ) -> List[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
192
+ """Fetch CIDRs for a given ASN from ASNDB."""
193
+ cidrs = []
194
+ errors = []
195
+ url = f"{self._asndb_url}/asn/{asn}"
196
+ print(f"Fetching {url}")
197
+ try:
198
+ res = self.request(url, include_api_key=True)
199
+ print(f"{url} -> {res.text}")
200
+ j = res.json()
201
+ cidrs = j.get("subnets", [])
202
+ except Exception as e:
203
+ errors.append(
204
+ f"Failed to fetch cidrs for {asn} from asndb: {e}:\n{traceback.format_exc()}"
205
+ )
206
+ print(f"Got {len(cidrs)} cidrs for {asn}")
207
+ return cidrs, errors
208
+
209
+ def fetch_v2fly_domains(self) -> List[str]:
210
+ """Fetch domains from the v2fly community repository."""
211
+ if not self.v2fly_company:
212
+ return [], []
213
+
214
+ errors = []
215
+ repo_path, _success = self._ensure_v2fly_repo_cached()
216
+ company_file = repo_path / "data" / self.v2fly_company
217
+ try:
218
+ domains = parse_v2fly_domain_file(company_file)
219
+ except Exception as e:
220
+ errors.append(
221
+ f"Failed to parse {self.v2fly_company} domains: {e}:\n{traceback.format_exc()}"
222
+ )
223
+ return sorted(list(domains)), errors
224
+
225
+ def fetch_cidrs(self) -> List[str]:
226
+ """Fetch CIDRs from a custom source."""
227
+ return []
228
+
229
+ def fetch_domains(self) -> List[str]:
230
+ """Fetch domains from a custom source."""
231
+ return []
232
+
233
+ def _ensure_v2fly_repo_cached(self) -> Path:
234
+ """Ensure the community repo is cloned and up-to-date."""
235
+ global v2fly_repo_pulled
236
+ errors = []
237
+ repo_dir = self._cache_dir / "domain-list-community"
238
+ if not repo_dir.exists():
239
+ self._cache_dir.mkdir(parents=True, exist_ok=True)
240
+ try:
241
+ subprocess.run(
242
+ ["git", "clone", "--depth", "1", self._repo_url, str(repo_dir)],
243
+ check=True,
244
+ capture_output=True,
245
+ )
246
+ v2fly_repo_pulled = True
247
+ except subprocess.CalledProcessError as e:
248
+ errors.append(
249
+ f"Failed to clone v2fly repo: {e}:\n{traceback.format_exc()}"
250
+ )
251
+ elif not v2fly_repo_pulled:
252
+ try:
253
+ subprocess.run(
254
+ ["git", "pull"], cwd=repo_dir, check=True, capture_output=True
255
+ )
256
+ except subprocess.CalledProcessError as e:
257
+ errors.append(
258
+ f"Failed to pull v2fly repo: {e}:\n{traceback.format_exc()}"
259
+ )
260
+ return repo_dir, errors
261
+
262
+ def request(self, *args, **kwargs):
263
+ return request(*args, **kwargs)
264
+
265
+ def __str__(self):
266
+ return self.name
267
+
268
+ def __repr__(self):
269
+ return f"{self.__class__.__name__}(name='{self.name}')"
@@ -0,0 +1,39 @@
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
+ # {"org_id": "CISCO-25-ARIN", "org_name": "Cisco Systems Inc.", "country": "US", "asns": [25949]}
9
+ # {"org_id": "CISCO-32-ARIN", "org_name": "Cisco Systems, Inc.", "country": "US", "asns": [63096]}
10
+ # {"org_id": "CISCOR-ARIN", "org_name": "CIS Corporation", "country": "US", "asns": [3792]}
11
+ # {"org_id": "CISL-7-ARIN", "org_name": "Cisco Systems Ironport Division", "country": "US", "asns": [16417,30214,30215,30238,40427]}
12
+ # {"org_id": "CS-2787-ARIN", "org_name": "Cisco Systems Inc", "country": "US", "asns": [398699]}
13
+ # {"org_id": "CS-2821-ARIN", "org_name": "Cisco IoT", "country": "US", "asns": [36180,393544]}
14
+ # {"org_id": "CS-2825-ARIN", "org_name": "Cisco Systems, Inc.", "country": "US", "asns": [396922]}
15
+ # {"org_id": "CS-2831-ARIN", "org_name": "CISCO SYSTEMS, INC.", "country": "US", "asns": [109,2051,3943,22183,23460,26092,36519,40590,54140,399780]}
16
+ # {"org_id": "CS-691-ARIN", "org_name": "Cisco Systems Cloud Division", "country": "US", "asns": [1343,32644]}
17
+ # {"org_id": "CS-985-ARIN", "org_name": "Cisco Systems, Inc.", "country": "US", "asns": [55219]}
18
+ # {"org_id": "OPEND-2-ARIN", "org_name": "Cisco OpenDNS, LLC", "country": "US", "asns": [25605,30607,36692]}
19
+ # {"org_id": "ORG-CIL21-RIPE", "org_name": "Cisco International Limited", "country": "GB", "asns": [201799]}
20
+ # {"org_id": "ORG-CL586-RIPE", "org_name": "CISCOM Ltd", "country": "RU", "asns": [61035]}
21
+ # {"org_id": "ORG-CSNA1-RIPE", "org_name": "Cisco Systems Norway AS", "country": "NO", "asns": [58298]}
22
+ # {"org_id": "WEX-ARIN", "org_name": "Cisco Webex LLC", "country": "US", "asns": [6577,13445,16472,26152,53258,399937]}
23
+ org_ids: List[str] = [
24
+ "CISCO-25-ARIN",
25
+ "CISCO-32-ARIN",
26
+ "CISCOR-ARIN",
27
+ "CISL-7-ARIN",
28
+ "CS-2787-ARIN",
29
+ "CS-2821-ARIN",
30
+ "CS-2825-ARIN",
31
+ "CS-2831-ARIN",
32
+ "CS-691-ARIN",
33
+ "CS-985-ARIN",
34
+ "OPEND-2-ARIN",
35
+ "ORG-CIL21-RIPE",
36
+ "ORG-CL586-RIPE",
37
+ "ORG-CSNA1-RIPE",
38
+ "WEX-ARIN",
39
+ ]
@@ -0,0 +1,40 @@
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
+ # {"org_id": "CLOUD14-ARIN", "org_name": "Cloudflare, Inc.", "country": "US", "asns": [13335,14789,394536,395747,400095]}
9
+ # {"org_id": "ORG-CHKL1-AP-APNIC", "org_name": "Cloudflare Hong Kong, LLC", "country": "US", "asns": [133877]}
10
+ # {"org_id": "ORG-CI4-AP-APNIC", "org_name": "Cloudflare, Inc.", "country": "US", "asns": [132892]}
11
+ # {"org_id": "ORG-CI40-RIPE", "org_name": "Cloudflare Inc", "country": "US", "asns": [202623,203898]}
12
+ # {"org_id": "ORG-CLL6-RIPE", "org_name": "Cloudflare London, LLC", "country": "US", "asns": [209242]}
13
+ # {"org_id": "ORG-CSL5-AP-APNIC", "org_name": "Cloudflare Sydney, LLC", "country": "US", "asns": [139242]}
14
+ org_ids: List[str] = [
15
+ "CLOUD14-ARIN",
16
+ "ORG-CHKL1-AP-APNIC",
17
+ "ORG-CI4-AP-APNIC",
18
+ "ORG-CI40-RIPE",
19
+ "ORG-CLL6-RIPE",
20
+ "ORG-CSL5-AP-APNIC",
21
+ ]
22
+ _bucket_name_regex = r"[a-z0-9_][a-z0-9-\.]{1,61}[a-z0-9]"
23
+ regexes: Dict[str, List[str]] = {
24
+ "STORAGE_BUCKET_NAME": [_bucket_name_regex],
25
+ "STORAGE_BUCKET_HOSTNAME": [
26
+ r"(" + _bucket_name_regex + r")\.(r2\.dev)",
27
+ r"(" + _bucket_name_regex + r")\.(r2\.cloudflarestorage\.com)",
28
+ ],
29
+ }
30
+
31
+ _ips_url = "https://api.cloudflare.com/client/v4/ips"
32
+
33
+ def fetch_cidrs(self):
34
+ response = self.request(self._ips_url)
35
+ ranges = set()
36
+ response_json = response.json()
37
+ for ip_type in ("ipv4_cidrs", "ipv6_cidrs"):
38
+ for ip_range in response_json.get("result", {}).get(ip_type, []):
39
+ ranges.add(ip_range)
40
+ return list(ranges)
@@ -0,0 +1,18 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Cloudfront(BaseProvider):
6
+ tags: List[str] = ["cdn"]
7
+
8
+ _ips_url = "https://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips"
9
+
10
+ def fetch_cidrs(self):
11
+ response = self.request(self._ips_url)
12
+ ranges = set()
13
+ response_json = response.json()
14
+ if not isinstance(response_json, dict):
15
+ raise ValueError(f"Invalid response format: {type(response_json)}")
16
+ for r in response_json.values():
17
+ ranges.update(r)
18
+ return list(ranges)
@@ -0,0 +1,11 @@
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
+ # {"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]}
9
+ org_ids: List[str] = [
10
+ "DCC-25-ARIN",
11
+ ]
@@ -0,0 +1,30 @@
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
+ # {"org_id": "DO-13-ARIN", "org_name": "DigitalOcean, LLC", "country": "US", "asns": [14061,46652,62567,393406,394362]}
10
+ org_ids: List[str] = [
11
+ "DO-13-ARIN",
12
+ ]
13
+ _bucket_name_regex = r"[a-z0-9][a-z0-9-]{2,62}"
14
+ regexes: Dict[str, List[str]] = {
15
+ "STORAGE_BUCKET_NAME": [_bucket_name_regex],
16
+ "STORAGE_BUCKET_HOSTNAME": [
17
+ r"(" + _bucket_name_regex + r")\.([a-z]{3}[\d]{1}\.digitaloceanspaces\.com)"
18
+ ],
19
+ }
20
+
21
+ _ips_url = "https://www.digitalocean.com/geo/google.csv"
22
+
23
+ def fetch_cidrs(self):
24
+ response = self.request(self._ips_url)
25
+ do_ips = csv.DictReader(
26
+ response.content.decode("utf-8").splitlines(),
27
+ fieldnames=["range", "country", "region", "city", "postcode"],
28
+ )
29
+ ranges = set(i["range"] for i in do_ips)
30
+ return list(ranges)
@@ -0,0 +1,22 @@
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
+ # {"org_id": "SKYCA-3-ARIN", "org_name": "Fastly, Inc.", "country": "US", "asns": [895,54113,394192]}
9
+ org_ids: List[str] = [
10
+ "SKYCA-3-ARIN",
11
+ ]
12
+
13
+ _ips_url = "https://api.fastly.com/public-ip-list"
14
+
15
+ def fetch_cidrs(self):
16
+ response = self.request(self._ips_url)
17
+ j = response.json()
18
+ if j and isinstance(j, dict):
19
+ addresses = j.get("addresses", [])
20
+ if addresses and isinstance(addresses, list):
21
+ return list(set(addresses))
22
+ return []
@@ -0,0 +1,28 @@
1
+ import ipaddress
2
+ from cloudcheck.providers.base import BaseProvider
3
+ from typing import List
4
+
5
+
6
+ class GitHub(BaseProvider):
7
+ v2fly_company: str = "github"
8
+ tags: List[str] = ["cdn"]
9
+ # {"org_id": "GITHU-ARIN", "org_name": "GitHub, Inc.", "country": "US", "asns": [36459]}
10
+ org_ids: List[str] = [
11
+ "GITHU-ARIN",
12
+ ]
13
+
14
+ _ips_url = "https://api.github.com/meta"
15
+
16
+ def fetch_cidrs(self):
17
+ response = self.request(self._ips_url)
18
+ ranges = set()
19
+ response_json = response.json()
20
+ for k, v in response_json.items():
21
+ if isinstance(v, list):
22
+ for n in v:
23
+ try:
24
+ ipaddress.ip_network(n)
25
+ ranges.add(n)
26
+ except ValueError:
27
+ pass
28
+ return list(ranges)
@@ -0,0 +1,61 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List, Dict
3
+
4
+
5
+ class Google(BaseProvider):
6
+ v2fly_company: str = "google"
7
+ # domains = ["googleapis.cn", "googleapis.com", "cloud.google.com", "gcp.gvt2.com", "appspot.com", "firebaseio.com", "google"]
8
+ tags: List[str] = ["cloud"]
9
+ # {"org_id": "GAL-53-ARIN", "org_name": "Google Access LLC", "country": "US", "asns": [32381]}
10
+ # {"org_id": "GF-ARIN", "org_name": "Google Fiber Inc.", "country": "US", "asns": [6432,16591,19448]}
11
+ # {"org_id": "GL-946-ARIN", "org_name": "Google LLC", "country": "US", "asns": [33715]}
12
+ # {"org_id": "GOGL-ARIN", "org_name": "Google LLC", "country": "US", "asns": [13949,15169,19425,22577,22859,26684,36039,36040,40873]}
13
+ # {"org_id": "GOOGL-1-ARIN", "org_name": "Google LLC", "country": "US", "asns": [36383,36384,36385,36411,36520]}
14
+ # {"org_id": "GOOGL-2-ARIN", "org_name": "Google LLC", "country": "US", "asns": [16550,19527,26910,36561,55023,394089,395973,396178,396982]}
15
+ # {"org_id": "GOOGL-5-ARIN", "org_name": "Google LLC", "country": "US", "asns": [394639]}
16
+ # {"org_id": "GOOGL-9-ARIN", "org_name": "Google LLC", "country": "US", "asns": [394507]}
17
+ # {"org_id": "GOOGL-ARIN", "org_name": "Google, LLC", "country": "US", "asns": [36492]}
18
+ # {"org_id": "ORG-GAPP2-AP-APNIC", "org_name": "Google Asia Pacific Pte. Ltd.", "country": "SG", "asns": [139070,139190]}
19
+ # {"org_id": "ORG-GCEL1-RIPE", "org_name": "Google Cloud EMEA Ltd", "country": "IE", "asns": [209504,209519,209539,214609,214611]}
20
+ # {"org_id": "ORG-GIL4-RIPE", "org_name": "Google Ireland Limited", "country": "IE", "asns": [43515]}
21
+ # {"org_id": "ORG-GKL1-AFRINIC", "org_name": "Google Kenya Limited", "country": "KE", "asns": [36987]}
22
+ # {"org_id": "ORG-GSG10-RIPE", "org_name": "Google Switzerland GmbH", "country": "CH", "asns": [41264]}
23
+ # {"org_id": "ORG-GSPL5-AP-APNIC", "org_name": "Google Singapore Pte. Ltd.", "country": "SG", "asns": [45566]}
24
+ org_ids: List[str] = [
25
+ "GAL-53-ARIN",
26
+ "GF-ARIN",
27
+ "GL-946-ARIN",
28
+ "GOGL-ARIN",
29
+ "GOOGL-1-ARIN",
30
+ "GOOGL-2-ARIN",
31
+ "GOOGL-5-ARIN",
32
+ "GOOGL-9-ARIN",
33
+ "GOOGL-ARIN",
34
+ "ORG-GAPP2-AP-APNIC",
35
+ "ORG-GCEL1-RIPE",
36
+ "ORG-GIL4-RIPE",
37
+ "ORG-GKL1-AFRINIC",
38
+ "ORG-GSG10-RIPE",
39
+ "ORG-GSPL5-AP-APNIC",
40
+ ]
41
+ _bucket_name_regex = r"[a-z0-9][a-z0-9-_\.]{1,61}[a-z0-9]"
42
+ _firebase_bucket_name_regex = r"[a-z0-9][a-z0-9-\.]{1,61}[a-z0-9]"
43
+ regexes: Dict[str, List[str]] = {
44
+ "STORAGE_BUCKET_NAME": [_bucket_name_regex, _firebase_bucket_name_regex],
45
+ "STORAGE_BUCKET_HOSTNAME": [
46
+ r"(" + _firebase_bucket_name_regex + r")\.(firebaseio\.com)",
47
+ r"(" + _bucket_name_regex + r")\.(storage\.googleapis\.com)",
48
+ ],
49
+ }
50
+
51
+ _ips_url = "https://www.gstatic.com/ipranges/cloud.json"
52
+
53
+ def fetch_cidrs(self):
54
+ response = self.request(self._ips_url)
55
+ ranges = set()
56
+ for p in response.json()["prefixes"]:
57
+ try:
58
+ ranges.add(p["ipv4Prefix"])
59
+ except KeyError:
60
+ ranges.add(p["ipv6Prefix"])
61
+ return list(ranges)
@@ -0,0 +1,7 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Heroku(BaseProvider):
6
+ v2fly_company: str = "heroku"
7
+ tags: List[str] = ["cloud"]
@@ -0,0 +1,18 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List, Dict
3
+
4
+
5
+ class Hetzner(BaseProvider):
6
+ v2fly_company: str = "hetzner"
7
+ tags: List[str] = ["cloud"]
8
+ # {"org_id": "ORG-HOA1-RIPE", "org_name": "Hetzner Online GmbH", "country": "DE", "asns": [24940,212317,213230,215859]}
9
+ org_ids: List[str] = [
10
+ "ORG-HOA1-RIPE",
11
+ ]
12
+ _bucket_name_regex = r"[a-z0-9][a-z0-9-_\.]{1,61}[a-z0-9]"
13
+ regexes: Dict[str, List[str]] = {
14
+ "STORAGE_BUCKET_NAME": [_bucket_name_regex],
15
+ "STORAGE_BUCKET_HOSTNAME": [
16
+ r"(" + _bucket_name_regex + r")\.(your-objectstorage\.com)"
17
+ ],
18
+ }
@@ -0,0 +1,12 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class HPE(BaseProvider):
6
+ # Hewlett Packard Enterprise Development, L.P.
7
+ v2fly_company: str = "hpe"
8
+ tags: List[str] = ["cloud"]
9
+ # {"org_id": "HPE-15-ARIN", "org_name": "HEWLETT PACKARD ENTERPRISE COMPANY", "country": "US", "asns": [157,1033,1034,13481,20096,22149,25867,27510,40617,395714,395992,396063,397363,397957,398199,399185,399610,400054,400624,400737,400763]}
10
+ org_ids: List[str] = [
11
+ "HPE-15-ARIN",
12
+ ]
@@ -0,0 +1,17 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class Huawei(BaseProvider):
6
+ v2fly_company: str = "huawei"
7
+ tags: List[str] = ["cloud"]
8
+ # {"org_id": "ORG-HIPL2-AP-APNIC", "org_name": "HUAWEI INTERNATIONAL PTE. LTD.", "country": "SG", "asns": [131444,136907,141180,149167,151610]}
9
+ # {"org_id": "ORG-HT57-RIPE", "org_name": "HUAWEI TECHNOLOGIES(UK)CO.,LTD", "country": "GB", "asns": [206798]}
10
+ # {"org_id": "ORG-HT61-RIPE", "org_name": "Huawei Tech(UAE)FZ-LLC", "country": "AE", "asns": [206204]}
11
+ # {"org_id": "ORG-HTB10-RIPE", "org_name": "Huawei Technologies (Netherlands) B.V.", "country": "NL", "asns": [200756]
12
+ org_ids: List[str] = [
13
+ "ORG-HIPL2-AP-APNIC",
14
+ "ORG-HT57-RIPE",
15
+ "ORG-HT61-RIPE",
16
+ "ORG-HTB10-RIPE",
17
+ ]
@@ -0,0 +1,57 @@
1
+ from cloudcheck.providers.base import BaseProvider
2
+ from typing import List
3
+
4
+
5
+ class IBM(BaseProvider):
6
+ v2fly_company: str = "ibm"
7
+ tags: List[str] = ["cloud"]
8
+ # {"org_id": "AWDIC-ARIN", "org_name": "Advanced Workstations Division, IBM Corporation", "country": "US", "asns": [706]}
9
+ # {"org_id": "IAD-7-ARIN", "org_name": "IBM AS/400 Division", "country": "US", "asns": [10337]}
10
+ # {"org_id": "IBM-1-ARIN", "org_name": "IBM", "country": "US", "asns": [763,10676,12237,15293,17390,18703,19152,19604,19898,22722,23145,23257,26543,27477,27530,29834,393850,395473]}
11
+ # {"org_id": "IBM-1-Z-ARIN", "org_name": "IBM", "country": "US", "asns": [163,547,1747,1786,1956,1997,2538,3082,3383]}
12
+ # {"org_id": "IBM-43-ARIN", "org_name": "IBM", "country": "US", "asns": [2560]}
13
+ # {"org_id": "IBMC-14-ARIN", "org_name": "IBM Corporation", "country": "US", "asns": [19765]}
14
+ # {"org_id": "IBMC-24-ARIN", "org_name": "IBM Cloud", "country": "US", "asns": [13749,13884,21844,30315,36351,36420,46702,46703,46704]}
15
+ # {"org_id": "IBML-1-ARIN", "org_name": "ibml", "country": "US", "asns": [40847]}
16
+ # {"org_id": "ICNS-4-ARIN", "org_name": "IBM Canada Network Services Company", "country": "CA", "asns": [3059]}
17
+ # {"org_id": "ORG-ACL6-AP-APNIC", "org_name": "FIBMESH IN LIMITED", "country": "IN", "asns": [133082,149779]}
18
+ # {"org_id": "ORG-CIF2-RIPE", "org_name": "COMPAGNIE IBM FRANCE SAS", "country": "FR", "asns": [202213]}
19
+ # {"org_id": "ORG-IBBC1-RIPE", "org_name": "IBM BTO Business Consulting Services Sp. z o.o.", "country": "PL", "asns": [200138]}
20
+ # {"org_id": "ORG-IBMC1-RIPE", "org_name": "INTERNATIONAL BUSINESS MACHINES CORPORATION", "country": "US", "asns": [204764,209394]}
21
+ # {"org_id": "ORG-IBMO1-RIPE", "org_name": "International Business Machines of Belgium Ltd", "country": "BE", "asns": [15776]}
22
+ # {"org_id": "ORG-IBSI1-AP-APNIC", "org_name": "IBM Business Services, Inc", "country": "PH", "asns": [133377]}
23
+ # {"org_id": "ORG-IDG12-RIPE", "org_name": "IBM Deutschland GmbH", "country": "DE", "asns": [214585]}
24
+ # {"org_id": "ORG-IIAT1-RIPE", "org_name": "IBM Israel-Science and technology Ltd.", "country": "IL", "asns": [50995]}
25
+ # {"org_id": "ORG-INZL1-AP-APNIC", "org_name": "IBM New Zealand Limited", "country": "NZ", "asns": [24189]}
26
+ # {"org_id": "ORG-IR9-RIPE", "org_name": "IBM Romania SRL", "country": "RO", "asns": [61179]}
27
+ # {"org_id": "ORG-IRS1-RIPE", "org_name": "IBM Romania S.R.L.", "country": "RO", "asns": [43283]}
28
+ # {"org_id": "ORG-ISPL9-AP-APNIC", "org_name": "IBM Singapore Pte Ltd", "country": "SG", "asns": [10120,134667,135291,136468,138450]}
29
+ # {"org_id": "ORG-IUL5-RIPE", "org_name": "IBM United Kingdom Limited", "country": "GB", "asns": [203652]}
30
+ # {"org_id": "ORG-LS306-RIPE", "org_name": "LTD SibMediaFon", "country": "RU", "asns": [48507]}
31
+ # {"org_id": "ORG-SCG6-RIPE", "org_name": "IBM Deutschland GmbH", "country": "DE", "asns": [50524]}
32
+ org_ids: List[str] = [
33
+ "AWDIC-ARIN",
34
+ "IAD-7-ARIN",
35
+ "IBM-1-ARIN",
36
+ "IBM-1-Z-ARIN",
37
+ "IBM-43-ARIN",
38
+ "IBMC-14-ARIN",
39
+ "IBMC-24-ARIN",
40
+ "IBML-1-ARIN",
41
+ "ICNS-4-ARIN",
42
+ "ORG-ACL6-AP-APNIC",
43
+ "ORG-CIF2-RIPE",
44
+ "ORG-IBBC1-RIPE",
45
+ "ORG-IBMC1-RIPE",
46
+ "ORG-IBMO1-RIPE",
47
+ "ORG-IBSI1-AP-APNIC",
48
+ "ORG-IDG12-RIPE",
49
+ "ORG-IIAT1-RIPE",
50
+ "ORG-INZL1-AP-APNIC",
51
+ "ORG-IR9-RIPE",
52
+ "ORG-IRS1-RIPE",
53
+ "ORG-ISPL9-AP-APNIC",
54
+ "ORG-IUL5-RIPE",
55
+ "ORG-LS306-RIPE",
56
+ "ORG-SCG6-RIPE",
57
+ ]