Initial commit

This commit is contained in:
Dionysus 2023-11-03 02:12:13 -04:00
commit 7e9597efb4
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
4 changed files with 208 additions and 0 deletions

15
LICENSE Normal file
View File

@ -0,0 +1,15 @@
ISC License
Copyright (c) 2023, acidvegas <acid.vegas@acid.vegas>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

30
README.md Normal file
View File

@ -0,0 +1,30 @@
# ICANN CZDS
The [ICANN Centralized Zone Data Service](https://czds.icann.org) *(CZDS)* allows *approved* users to request and download DNS zone files in bulk, provided they represent a legitimate company or academic institution and their intended use is legal and ethical. Once ICANN approves the request, this tool streamlines the retrieval of extensive domain name system data, facilitating research and security analysis in the realm of internet infrastructure.
## 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. 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.
## Usage
### Authentication
Credentials may be provided interactively upon execution or via the `CZDS_USER` & `CZDS_PASS` environment variables:
```bash
export CZDS_USER='your_username'
export CZDS_PASS='your_password'
```
### Python version
```bash
python czds.py [--username <username> --password <password>] [--concurrency <int>]
```
### POSIX version
```bash
./czds
```
___
###### Mirrors
[acid.vegas](https://git.acid.vegas/czds) • [GitHub](https://github.com/acidvegas/czds) • [GitLab](https://gitlab.com/acidvegas/czds) • [SuperNETs](https://git.supernets.org/acidvegas/czds)

62
czds Executable file
View File

@ -0,0 +1,62 @@
#!/bin/sh
# ICANN API for the Centralized Zones Data Service - developed by acidvegas (https://git.acid.vegas/czds)
# https://czds.icann.org
# https://czds.icann.org/sites/default/files/czds-api-documentation.pdf
# Function to authenticate and get access token
authenticate() {
username="$1"
password="$2"
# Make an authentication request and inline the URL
response=$(curl -s -X POST "https://account-api.icann.org/api/authenticate" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d "{\"username\":\"$username\",\"password\":\"$password\"}")
# Extract and return the access token
echo "$response" | grep -o '"accessToken":"[^"]*' | cut -d '"' -f 4
}
# Function to download a zone file
download_zone() {
url="$1"
token="$2"
filename=$(basename "$url")
filepath="zonefiles/$filename"
# Create output directory if it does not exist
mkdir -p "zonefiles"
# Make the GET request and save the response to a file
curl -s -o "$filepath" -H "Authorization: Bearer $token" "$url"
echo "Downloaded zone file to $filepath"
}
# Main program starts here
echo "ICANN Zone Data Service Script"
# Get username and password
username=${CZDS_USER:-$(read -p "ICANN Username: " user && echo "$user")}
password=${CZDS_PASS:-$(read -sp "ICANN Password: " pass && echo "$pass" && echo)}
# Authenticate and get token
echo "Authenticating..."
token=$(authenticate "$username" "$password")
# Check if authentication was successful
if [ -z "$token" ]; then
echo "Authentication failed."
exit 1
fi
echo "Fetching zone file links..."
# 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://[^"]*')
# Download zone files
for url in $zone_links; do
echo "Downloading $url..."
download_zone "$url" "$token"
done
echo "All zone files downloaded."

101
czdz.py Normal file
View File

@ -0,0 +1,101 @@
#!/usr/bin/env python
# ICANN API for the Centralized Zones Data Service - developed by acidvegas (https://git.acid.vegas/czds)
'''
References:
- https://czds.icann.org
- https://czds.icann.org/sites/default/files/czds-api-documentation.pdf
'''
import argparse
import concurrent.futures
import getpass
import os
try:
import requests
except ImportError:
raise ImportError('Missing dependency: requests (pip install requests)')
def authenticate(username: str, password: str) -> str:
'''
Authenticate with ICANN's API and return the access token.
:param username: ICANN Username
:param password: ICANN Password
'''
response = requests.post('https://account-api.icann.org/api/authenticate', json={'username': username, 'password': password})
response.raise_for_status()
return response.json()['accessToken']
def download_zone(url: str, token: str, output_directory: str):
'''
Download a single zone file.
:param url: URL to download
:param token: ICANN access token
:param output_directory: Directory to save the zone file
'''
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(url, headers=headers)
response.raise_for_status()
filename = response.headers.get('Content-Disposition').split('filename=')[-1].strip('"')
filepath = os.path.join(output_directory, filename)
with open(filepath, 'wb') as file:
for chunk in response.iter_content(chunk_size=1024):
file.write(chunk)
return filepath
def main(username: str, password: str, concurrency: int):
'''
Main function to download all zone files.
:param username: ICANN Username
:param password: ICANN Password
:param concurrency: Number of concurrent downloads
'''
token = authenticate(username, password)
headers = {'Authorization': f'Bearer {token}'}
response = requests.get('https://czds-api.icann.org/czds/downloads/links', headers=headers)
response.raise_for_status()
zone_links = response.json()
output_directory = 'zonefiles'
os.makedirs(output_directory, exist_ok=True)
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}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
filepath = future.result()
print(f'Completed downloading {url} to file {filepath}')
except Exception as e:
print(f'{url} generated an exception: {e}')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="ICANN Zone Files Downloader")
parser.add_argument('-u', '--username', help='ICANN Username')
parser.add_argument('-p', '--password', help='ICANN Password')
parser.add_argument('-c', '--concurrency', type=int, default=5, help='Number of concurrent downloads')
args = parser.parse_args()
username = args.username or os.getenv('CZDS_USER')
password = args.password or os.getenv('CZDS_PASS')
if not username:
username = input('ICANN Username: ')
if not password:
password = getpass.getpass('ICANN Password: ')
try:
main(username, password, args.concurrency)
except requests.HTTPError as e:
print(f'HTTP error occurred: {e.response.status_code} - {e.response.reason}')
except Exception as e:
print(f'An error occurred: {e}')