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