Compare commits
2 Commits
2588ee8d5a
...
34fd31e33d
Author | SHA1 | Date | |
---|---|---|---|
34fd31e33d | |||
ca121e248b |
@ -5,9 +5,9 @@ The [ICANN Centralized Zone Data Service](https://czds.icann.org) *(CZDS)* allow
|
|||||||
## Zone Information
|
## Zone Information
|
||||||
Zone files are updated once every 24 hours, specifically from 00:00 UTC to 06:00 UTC. Access to these zones is granted in increments, and the total time for approval across all zones may extend to a month or longer. It is typical for more than 90% of requested zones to receive approval. Access to certain zone files may require additional application forms with the TLD organization. Please be aware that access to certain zones is time-bound, expiring at the beginning of the following year, or up to a decade after the initial approval has been confirmed.
|
Zone files are updated once every 24 hours, specifically from 00:00 UTC to 06:00 UTC. Access to these zones is granted in increments, and the total time for approval across all zones may extend to a month or longer. It is typical for more than 90% of requested zones to receive approval. Access to certain zone files may require additional application forms with the TLD organization. Please be aware that access to certain zones is time-bound, expiring at the beginning of the following year, or up to a decade after the initial approval has been confirmed.
|
||||||
|
|
||||||
At the time of writing this repository, the CZDS offers access to 1,150 zones in total.
|
At the time of writing this repository, the CZDS offers access to 1,151 zones in total.
|
||||||
|
|
||||||
1,079 have been approved, 55 are still pending *(after 3 months)*, 10 have been revoked because the TLDs are longer active, and 6 have been denied. Zones that have expired automatically had the expiration extended for me without doing anything, aside from 13 zones that remained expired.
|
1,079 have been approved, 55 are still pending *(after 3 months)*, 10 have been revoked because the TLDs are longer active, and 6 have been denied. Zones that have expired automatically had the expiration extended for me without doing anything, aside from 13 zones that remained expired. I have included a recent [stats file](./stats_2024-01-31.csv) directly from my ICANN account.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
### Authentication
|
### Authentication
|
||||||
@ -29,7 +29,7 @@ python czds.py [--username <username> --password <password>] [--concurrency <int
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Respects
|
## Respects
|
||||||
While ICANN does have an official [czds-api-client-python](https://github.com/icann/czds-api-client-python) repository, I rewrote it from scratch to be more streamline & included a POSIX version for portability. Either way, big props to ICANN for allowing me to use the CZDS for research purposes!
|
While ICANN does have an official [czds-api-client-python](https://github.com/icann/czds-api-client-python) repository, I rewrote it from scratch to be more streamline & included a POSIX version for portability. There is some [official documentation](https://raw.githubusercontent.com/icann/czds-api-client-java/master/docs/ICANN_CZDS_api.pdf) that was referenced in the creation of the POSIX version. Either way, big props to ICANN for allowing me to use the CZDS for research purposes!
|
||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
|
22
czds
22
czds
@ -1,8 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ICANN API for the Centralized Zones Data Service - developed by acidvegas (https://git.acid.vegas/czds)
|
# ICANN API for the Centralized Zones Data Service - developed by acidvegas (https://git.acid.vegas/czds)
|
||||||
|
# Reference: https://czds.icann.org
|
||||||
# https://czds.icann.org
|
|
||||||
# https://czds.icann.org/sites/default/files/czds-api-documentation.pdf
|
|
||||||
|
|
||||||
# Function to authenticate and get access token
|
# Function to authenticate and get access token
|
||||||
authenticate() {
|
authenticate() {
|
||||||
@ -22,17 +20,13 @@ authenticate() {
|
|||||||
download_zone() {
|
download_zone() {
|
||||||
url="$1"
|
url="$1"
|
||||||
token="$2"
|
token="$2"
|
||||||
filename=$(basename "$url")
|
tld=$(basename "$url" .zone)
|
||||||
tld=$(echo "$filename" | cut -d '.' -f 1)
|
|
||||||
filepath="zonefiles/$tld.txt.gz"
|
|
||||||
|
|
||||||
|
|
||||||
# Create output directory if it does not exist
|
|
||||||
mkdir -p zonefiles
|
|
||||||
|
|
||||||
# Make the GET request and save the response to a file
|
# Make the GET request and save the response to a file
|
||||||
curl --progress-bar -o "$filepath" -H "Authorization: Bearer $token" "$url"
|
echo "Downloading $url..."
|
||||||
echo "Downloaded zone file to $filepath"
|
curl --progress-bar -o zonefiles/$tld.txt.gz -H "Authorization: Bearer $token" "$url"
|
||||||
|
echo "Downloaded zone file to zonefiles/$tld.txt.gz"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main program starts here
|
# Main program starts here
|
||||||
@ -56,12 +50,12 @@ echo "Fetching zone file links..."
|
|||||||
# Fetch zone links with inline URL and download zone files
|
# Fetch zone links with inline URL and download zone files
|
||||||
zone_links=$(curl -s -H "Authorization: Bearer $token" "https://czds-api.icann.org/czds/downloads/links" | grep -o 'https://[^"]*')
|
zone_links=$(curl -s -H "Authorization: Bearer $token" "https://czds-api.icann.org/czds/downloads/links" | grep -o 'https://[^"]*')
|
||||||
|
|
||||||
|
# Create output directory if it does not exist
|
||||||
|
mkdir -p zonefiles
|
||||||
|
|
||||||
# Download zone files
|
# Download zone files
|
||||||
for url in $zone_links; do
|
for url in $zone_links; do
|
||||||
if [ ! -f $filepath ]; then
|
|
||||||
echo "Downloading $url..."
|
|
||||||
download_zone "$url" "$token"
|
download_zone "$url" "$token"
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "All zone files downloaded."
|
echo "All zone files downloaded."
|
||||||
|
20
czds.py
20
czds.py
@ -1,11 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# ICANN API for the Centralized Zones Data Service - developed by acidvegas (https://git.acid.vegas/czds)
|
# ICANN API for the Centralized Zones Data Service - developed by acidvegas (https://git.acid.vegas/czds)
|
||||||
|
# Reference: https://czds.icann.org
|
||||||
'''
|
|
||||||
References:
|
|
||||||
- https://czds.icann.org
|
|
||||||
- https://czds.icann.org/sites/default/files/czds-api-documentation.pdf
|
|
||||||
'''
|
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import concurrent.futures
|
import concurrent.futures
|
||||||
@ -13,7 +8,6 @@ import getpass
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import requests
|
import requests
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -31,8 +25,10 @@ def authenticate(username: str, password: str) -> str:
|
|||||||
:param username: ICANN Username
|
:param username: ICANN Username
|
||||||
:param password: ICANN Password
|
:param password: ICANN Password
|
||||||
'''
|
'''
|
||||||
|
|
||||||
response = requests.post('https://account-api.icann.org/api/authenticate', json={'username': username, 'password': password})
|
response = requests.post('https://account-api.icann.org/api/authenticate', json={'username': username, 'password': password})
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
return response.json()['accessToken']
|
return response.json()['accessToken']
|
||||||
|
|
||||||
|
|
||||||
@ -44,11 +40,13 @@ def download_zone(url: str, token: str, output_directory: str):
|
|||||||
:param token: ICANN access token
|
:param token: ICANN access token
|
||||||
:param output_directory: Directory to save the zone file
|
:param output_directory: Directory to save the zone file
|
||||||
'''
|
'''
|
||||||
|
|
||||||
headers = {'Authorization': f'Bearer {token}'}
|
headers = {'Authorization': f'Bearer {token}'}
|
||||||
response = requests.get(url, headers=headers)
|
response = requests.get(url, headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
filename = response.headers.get('Content-Disposition').split('filename=')[-1].strip('"')
|
filename = response.headers.get('Content-Disposition').split('filename=')[-1].strip('"')
|
||||||
filepath = os.path.join(output_directory, filename)
|
filepath = os.path.join(output_directory, filename)
|
||||||
|
|
||||||
with open(filepath, 'wb') as file:
|
with open(filepath, 'wb') as file:
|
||||||
for chunk in response.iter_content(chunk_size=1024):
|
for chunk in response.iter_content(chunk_size=1024):
|
||||||
file.write(chunk)
|
file.write(chunk)
|
||||||
@ -63,19 +61,24 @@ def main(username: str, password: str, concurrency: int):
|
|||||||
:param password: ICANN Password
|
:param password: ICANN Password
|
||||||
:param concurrency: Number of concurrent downloads
|
:param concurrency: Number of concurrent downloads
|
||||||
'''
|
'''
|
||||||
|
|
||||||
token = authenticate(username, password)
|
token = authenticate(username, password)
|
||||||
headers = {'Authorization': f'Bearer {token}'}
|
headers = {'Authorization': f'Bearer {token}'}
|
||||||
|
|
||||||
response = requests.get('https://czds-api.icann.org/czds/downloads/links', headers=headers)
|
response = requests.get('https://czds-api.icann.org/czds/downloads/links', headers=headers)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
zone_links = response.json()
|
zone_links = response.json()
|
||||||
output_directory = 'zonefiles'
|
output_directory = 'zonefiles'
|
||||||
|
|
||||||
os.makedirs(output_directory, exist_ok=True)
|
os.makedirs(output_directory, exist_ok=True)
|
||||||
|
|
||||||
with concurrent.futures.ThreadPoolExecutor(max_workers=concurrency) as executor:
|
with concurrent.futures.ThreadPoolExecutor(max_workers=concurrency) as executor:
|
||||||
|
|
||||||
future_to_url = {executor.submit(download_zone, url, token, output_directory): url for url in zone_links}
|
future_to_url = {executor.submit(download_zone, url, token, output_directory): url for url in zone_links}
|
||||||
|
|
||||||
for future in concurrent.futures.as_completed(future_to_url):
|
for future in concurrent.futures.as_completed(future_to_url):
|
||||||
|
|
||||||
url = future_to_url[future]
|
url = future_to_url[future]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
filepath = future.result()
|
filepath = future.result()
|
||||||
logging.info(f'Completed downloading {url} to file {filepath}')
|
logging.info(f'Completed downloading {url} to file {filepath}')
|
||||||
@ -96,6 +99,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
if not username:
|
if not username:
|
||||||
username = input('ICANN Username: ')
|
username = input('ICANN Username: ')
|
||||||
|
|
||||||
if not password:
|
if not password:
|
||||||
password = getpass.getpass('ICANN Password: ')
|
password = getpass.getpass('ICANN Password: ')
|
||||||
|
|
||||||
|
1151
stats_2024-01-31.csv
Normal file
1151
stats_2024-01-31.csv
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user