#!/usr/bin/env bash
# Turn one rotating ISP Proxy line into static lines, each with its own fixed IP,
# or check that saved static lines still exit through their IPs.
usage() {
cat >&2 <<'EOF'
Usage:
isp-static.sh [-p socks5|http] LINE [COUNT] make COUNT static lines (default 10), save to static.txt
isp-static.sh check [-p socks5|http] [FILE] check lines from FILE (default static.txt)
LINE is HOST:PORT:LOGIN:PASSWORD, optionally with a socks5:// or http:// prefix.
A prefix in the line wins over -p; without both the script uses SOCKS5.
EOF
exit 1
}
ECHO_URL=http://ifconfig.me/ip
MODE=make
[ "$1" = check ] && { MODE=check; shift; }
OPT_PROTO=
while getopts "p:" opt; do
case $opt in
p) OPT_PROTO=$OPTARG ;;
*) usage ;;
esac
done
shift $((OPTIND - 1))
case $OPT_PROTO in ''|socks5|http) ;; *) usage ;; esac
parse() {
local l=$1
PREFIX=
case $l in
http://*) PREFIX=http:// ;;
socks5://*) PREFIX=socks5:// ;;
socks5h://*) PREFIX=socks5h:// ;;
esac
l=${l#"$PREFIX"}
if [ -n "$PREFIX" ]; then PROTO=${PREFIX%://}; else PROTO=${OPT_PROTO:-socks5}; fi
[ "$PROTO" = http ] && PROXY="http://" || PROXY="socks5h://"
IFS=: read -r HOST PORT LOGIN PASS <<< "$l"
PROXY="$PROXY$HOST:$PORT"
}
ip_of() { curl -s -m 15 -x "$PROXY" -U "$1:$PASS" "$ECHO_URL" < /dev/null; }
bar() {
[ -t 2 ] || return 0
local done=$1 total=$2 width=30
local fill; fill=$(printf '%*s' $((done * width / total)) '' | tr ' ' '=')
[ "$done" -lt "$total" ] && fill="$fill>"
printf '\r%3d%%[%-*s] %d/%d' $((done * 100 / total)) "$width" "$fill" "$done" "$total" >&2
}
say() {
[ -t 2 ] && printf '\r\033[K' >&2
echo "$1"
}
make_lines() {
[ -n "$1" ] || usage
parse "$1"
local count=${2:-10} found=0 tries=0 answered=0 seen=" " ip
: > static.txt
bar 0 "$count"
while [ "$found" -lt "$count" ] && [ "$tries" -lt $((count * 3)) ]; do
tries=$((tries + 1))
ip=$(ip_of "$LOGIN")
if ! [[ $ip =~ ^[0-9.]+$ ]]; then
if [ "$answered" -eq 0 ] && [ "$tries" -ge 3 ]; then
say "No answer through $PROXY: check the line, the port and the protocol (-p)" >&2
exit 1
fi
continue
fi
answered=1
case $seen in *" $ip "*) continue ;; esac
seen="$seen$ip "
[ "$(ip_of "$LOGIN-ip-$ip")" = "$ip" ] || continue
found=$((found + 1))
echo "$PREFIX$HOST:$PORT:$LOGIN-ip-$ip:$PASS" >> static.txt
bar "$found" "$count"
done
[ -t 2 ] && echo >&2
echo "Static lines: $found of $count, saved to static.txt"
}
check_lines() {
local file=${1:-static.txt} total n=0 ok=0 line want got
[ -r "$file" ] || { echo "Cannot read $file" >&2; exit 1; }
total=$(grep -c . "$file")
[ "$total" -gt 0 ] || { echo "No lines in $file" >&2; exit 1; }
bar 0 "$total"
while IFS= read -r line; do
line=${line%$'\r'}
[ -n "$line" ] || continue
parse "$line"
want=${LOGIN##*-ip-}
[ "$want" = "$LOGIN" ] && want="(no -ip- in login)"
got=$(ip_of "$LOGIN")
n=$((n + 1))
if [ "$got" = "$want" ]; then
ok=$((ok + 1))
say "$(printf '%-15s -> %-15s OK' "$want" "$got")"
else
say "$(printf '%-15s -> %-15s FAIL' "$want" "${got:-no answer}")"
fi
bar "$n" "$total"
done < "$file"
[ -t 2 ] && echo >&2
echo "Checked $n: $ok OK, $((n - ok)) failed"
}
if [ "$MODE" = check ]; then check_lines "$1"; else make_lines "$1" "$2"; fi
Setzen Sie statt LOGIN und PASSWORD den Login und das Passwort aus der Zeile im Kundenbereich ein. Das Protokoll bestimmt das Präfix in der Zeile (socks5:// oder http://) oder der Schalter -p; ohne beides nutzt das Skript SOCKS5.