add source
This commit is contained in:
parent
cd63a55d33
commit
04ddae5b54
3 changed files with 271 additions and 0 deletions
232
asngecko
Normal file
232
asngecko
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# asngecko – Swiss-army script for fetching IPv4 / IPv6 prefixes for ASNs
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Author: <your-name>
|
||||||
|
# License: MIT
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# FEATURES
|
||||||
|
# • Accept single/multiple ASNs (-a) or a file (-l)
|
||||||
|
# • IPv4-only (-4), IPv6-only (-6) or both (default)
|
||||||
|
# • Custom WHOIS servers – global (-s) or per family (--server4 / --server6)
|
||||||
|
# • Output to console (default) or file(s):
|
||||||
|
# -o FILE → FILE.ipv4 / FILE.ipv6 (when both families)
|
||||||
|
# --output4 FILE → explicit IPv4 path
|
||||||
|
# --output6 FILE → explicit IPv6 path
|
||||||
|
# • Formats: CIDR (default), CSV, JSON
|
||||||
|
# • De-duplicate / sort (-u)
|
||||||
|
# • Throttle between WHOIS look-ups (-t SEC)
|
||||||
|
# • Quiet mode (-q) for cron/CI
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_NAME="${0##*/}"
|
||||||
|
VERSION="1.2.0"
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Defaults
|
||||||
|
WHOIS_SERVER_V4="whois.radb.net"
|
||||||
|
WHOIS_SERVER_V6="whois.ripe.net"
|
||||||
|
IP_VERSION="both" # 4 | 6 | both
|
||||||
|
OUTPUT_DEST="console" # console | file
|
||||||
|
OUTPUT_FILE_BASE="" # base name without family suffix
|
||||||
|
OUTPUT_FILE_V4="" # explicit IPv4 file path (optional)
|
||||||
|
OUTPUT_FILE_V6="" # explicit IPv6 file path (optional)
|
||||||
|
OUTPUT_FORMAT="cidr" # cidr | csv | json
|
||||||
|
UNIQ=false
|
||||||
|
QUIET=false
|
||||||
|
THROTTLE=0
|
||||||
|
ASN_INPUT=()
|
||||||
|
ASN_FILE=""
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
print_msg() { $QUIET || echo "$*" >&2; }
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat << EOF
|
||||||
|
$SCRIPT_NAME $VERSION – fetch IP ranges for Autonomous Systems
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
$SCRIPT_NAME -a AS15169 [options]
|
||||||
|
$SCRIPT_NAME -a "AS15169 AS16509" [options]
|
||||||
|
$SCRIPT_NAME -a AS15169 -q [more options] | your-special-command
|
||||||
|
$SCRIPT_NAME -l list.txt [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-a, --asn "AS… AS…" Space-separated ASNs (quote the list)
|
||||||
|
-l, --list FILE File with ASNs, one per line
|
||||||
|
-4 IPv4 only
|
||||||
|
-6 IPv6 only
|
||||||
|
-b, --both Both families (default)
|
||||||
|
-s, --server HOST WHOIS server for both families
|
||||||
|
--server4 HOST WHOIS server for IPv4 (default $WHOIS_SERVER_V4)
|
||||||
|
--server6 HOST WHOIS server for IPv6 (default $WHOIS_SERVER_V6)
|
||||||
|
|
||||||
|
-o, --output FILE Base file name (adds .ipv4 / .ipv6 if needed)
|
||||||
|
--output4 FILE Explicit IPv4 output path (overrides -o)
|
||||||
|
--output6 FILE Explicit IPv6 output path (overrides -o)
|
||||||
|
-c, --console Print to stdout (default when no -o/--outputX)
|
||||||
|
|
||||||
|
-f, --format FMT cidr|csv|json (default: cidr)
|
||||||
|
|
||||||
|
-u, --uniq De-duplicate & sort prefixes
|
||||||
|
-t, --throttle SEC Sleep SEC between ASN queries
|
||||||
|
-q, --quiet Suppress progress output
|
||||||
|
-h, --help Show this help & exit
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$SCRIPT_NAME -a AS1234 | grep 120.0.0.0/24
|
||||||
|
|
||||||
|
# Google IPv6 to file
|
||||||
|
$SCRIPT_NAME -a AS15169 -6 -o google_v6.txt
|
||||||
|
|
||||||
|
# Separate destinations in one call
|
||||||
|
$SCRIPT_NAME -a "AS15169 AS32934" -46 \\
|
||||||
|
--output4 /srv/v4/all.txt \\
|
||||||
|
--output6 /srv/v6/all.txt
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Parse options (GNU getopt for long opts)
|
||||||
|
PARSED=$(getopt \
|
||||||
|
-o "a:l:46bs:o:cf:uqht:" \
|
||||||
|
--long "asn:,list:,both,server:,server4:,server6:,output:,output4:,output6:,console,format:,uniq,quiet,help,throttle:" \
|
||||||
|
-- "$@") || { usage; exit 1; }
|
||||||
|
eval set -- "$PARSED"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
case "$1" in
|
||||||
|
-a|--asn) ASN_INPUT+=($2); shift 2 ;;
|
||||||
|
-l|--list) ASN_FILE="$2"; shift 2 ;;
|
||||||
|
-4) IP_VERSION="4"; shift ;;
|
||||||
|
-6) IP_VERSION="6"; shift ;;
|
||||||
|
-b|--both) IP_VERSION="both"; shift ;;
|
||||||
|
-s|--server) WHOIS_SERVER_V4="$2"; WHOIS_SERVER_V6="$2"; shift 2 ;;
|
||||||
|
--server4) WHOIS_SERVER_V4="$2"; shift 2 ;;
|
||||||
|
--server6) WHOIS_SERVER_V6="$2"; shift 2 ;;
|
||||||
|
|
||||||
|
-o|--output) OUTPUT_DEST="file"; OUTPUT_FILE_BASE="$2"; shift 2 ;;
|
||||||
|
--output4) OUTPUT_DEST="file"; OUTPUT_FILE_V4="$2"; shift 2 ;;
|
||||||
|
--output6) OUTPUT_DEST="file"; OUTPUT_FILE_V6="$2"; shift 2 ;;
|
||||||
|
-c|--console) OUTPUT_DEST="console"; shift ;;
|
||||||
|
|
||||||
|
-f|--format) OUTPUT_FORMAT="$2"; shift 2 ;;
|
||||||
|
|
||||||
|
-u|--uniq) UNIQ=true; shift ;;
|
||||||
|
-t|--throttle) THROTTLE="$2"; shift 2 ;;
|
||||||
|
-q|--quiet) QUIET=true; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
*) echo "Unknown option $1" >&2; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Collect ASNs
|
||||||
|
if [[ -n "$ASN_FILE" ]]; then
|
||||||
|
[[ -f "$ASN_FILE" ]] || { echo "File $ASN_FILE not found." >&2; exit 1; }
|
||||||
|
mapfile -t FILE_ASNS < <(grep -Eo 'AS?[0-9]+' "$ASN_FILE")
|
||||||
|
ASN_INPUT+=("${FILE_ASNS[@]}")
|
||||||
|
fi
|
||||||
|
[[ ${#ASN_INPUT[@]} -gt 0 ]] || { echo "No ASNs supplied." >&2; usage; exit 1; }
|
||||||
|
|
||||||
|
# Normalize
|
||||||
|
NORMALISED=()
|
||||||
|
for asn in "${ASN_INPUT[@]}"; do
|
||||||
|
[[ $asn =~ ^AS[0-9]+$ ]] && NORMALISED+=("$asn") || NORMALISED+=("AS${asn#AS}")
|
||||||
|
done
|
||||||
|
ASN_INPUT=("${NORMALISED[@]}")
|
||||||
|
|
||||||
|
print_msg "ASNs: ${ASN_INPUT[*]}"
|
||||||
|
print_msg "IP family: $IP_VERSION"
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Fetch helpers
|
||||||
|
fetch_prefixes() {
|
||||||
|
local asn="$1" fam="$2" server="$3"
|
||||||
|
if [[ $fam == 4 ]]; then
|
||||||
|
whois -h "$server" -- "-i origin $asn" |
|
||||||
|
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]+' || true
|
||||||
|
else
|
||||||
|
whois -h "$server" -- "-i origin $asn" |
|
||||||
|
awk '/route6:/ {print $2}' || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
RANGES_V4=()
|
||||||
|
RANGES_V6=()
|
||||||
|
for asn in "${ASN_INPUT[@]}"; do
|
||||||
|
if [[ $IP_VERSION == 4 || $IP_VERSION == both ]]; then
|
||||||
|
mapfile -t tmp < <(fetch_prefixes "$asn" 4 "$WHOIS_SERVER_V4")
|
||||||
|
RANGES_V4+=("${tmp[@]}")
|
||||||
|
fi
|
||||||
|
if [[ $IP_VERSION == 6 || $IP_VERSION == both ]]; then
|
||||||
|
mapfile -t tmp < <(fetch_prefixes "$asn" 6 "$WHOIS_SERVER_V6")
|
||||||
|
RANGES_V6+=("${tmp[@]}")
|
||||||
|
fi
|
||||||
|
(( THROTTLE > 0 )) && sleep "$THROTTLE"
|
||||||
|
done
|
||||||
|
|
||||||
|
# De-dup / sort
|
||||||
|
dedup_sort() { mapfile -t "$1" < <(printf '%s\n' "${!1}" | sort -u); }
|
||||||
|
$UNIQ && { dedup_sort RANGES_V4; dedup_sort RANGES_V6; }
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Formatters
|
||||||
|
format_cidr() { printf '%s\n' "$@"; }
|
||||||
|
|
||||||
|
format_csv() {
|
||||||
|
local fam="$1"; shift
|
||||||
|
for cidr in "$@"; do
|
||||||
|
printf '%s,%s\n' "$cidr" "$fam"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
format_json() {
|
||||||
|
jq -R -s -c 'split("\n")[:-1]' <<< "$(printf '%s\n' "$@")"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Decide where to write & actually write
|
||||||
|
write_output() {
|
||||||
|
local content="$1" fam="$2"
|
||||||
|
|
||||||
|
# Resolve file path when saving
|
||||||
|
local file=""
|
||||||
|
case "$fam" in
|
||||||
|
v4) file="$OUTPUT_FILE_V4" ;;
|
||||||
|
v6) file="$OUTPUT_FILE_V6" ;;
|
||||||
|
esac
|
||||||
|
if [[ -z $file && $OUTPUT_DEST == file ]]; then
|
||||||
|
file="$OUTPUT_FILE_BASE"
|
||||||
|
[[ $IP_VERSION == both ]] && file+=".$fam"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $OUTPUT_DEST == file || -n $file ]]; then
|
||||||
|
echo "$content" > "$file"
|
||||||
|
print_msg "Saved $fam → $file"
|
||||||
|
else
|
||||||
|
echo "$content"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ────────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Emit IPv4
|
||||||
|
if [[ $IP_VERSION == 4 || $IP_VERSION == both ]]; then
|
||||||
|
case $OUTPUT_FORMAT in
|
||||||
|
cidr) write_output "$(format_cidr "${RANGES_V4[@]}")" v4 ;;
|
||||||
|
csv) write_output "$(format_csv 4 "${RANGES_V4[@]}")" v4 ;;
|
||||||
|
json) write_output "$(format_json "${RANGES_V4[@]}")" v4 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Emit IPv6
|
||||||
|
if [[ $IP_VERSION == 6 || $IP_VERSION == both ]]; then
|
||||||
|
case $OUTPUT_FORMAT in
|
||||||
|
cidr) write_output "$(format_cidr "${RANGES_V6[@]}")" v6 ;;
|
||||||
|
csv) write_output "$(format_csv 6 "${RANGES_V6[@]}")" v6 ;;
|
||||||
|
json) write_output "$(format_json "${RANGES_V6[@]}")" v6 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
21
install.sh
Normal file
21
install.sh
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Copy asngecko to /usr/local/bin and make it executable.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SRC="${1:-./asngecko}"
|
||||||
|
DEST="/usr/local/bin/asngecko"
|
||||||
|
|
||||||
|
if [[ ! -f "$SRC" ]]; then
|
||||||
|
echo "Error: '$SRC' not found." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing asngecko to $DEST …"
|
||||||
|
install -Dm755 "$SRC" "$DEST" # -D: create dirs as needed, -m755: chmod +x
|
||||||
|
echo "Done. Type 'asngecko --help' to verify."
|
||||||
|
echo syncing file system
|
||||||
|
sudo sync
|
||||||
|
echo done.
|
||||||
18
uninstall.sh
Normal file
18
uninstall.sh
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Remove /usr/local/bin/asngecko
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DEST="/usr/local/bin/asngecko"
|
||||||
|
|
||||||
|
if [[ -f "$DEST" ]]; then
|
||||||
|
echo "Removing $DEST …"
|
||||||
|
rm -f "$DEST"
|
||||||
|
echo "Uninstalled."
|
||||||
|
echo syncing file system...
|
||||||
|
sudo sync
|
||||||
|
echo done
|
||||||
|
else
|
||||||
|
echo "Nothing to do – $DEST not found."
|
||||||
|
fi
|
||||||
Loading…
Add table
Add a link
Reference in a new issue