commit 4ed683462b540b3f249ca3642984b32768390c22 Author: sajadMRjl Date: Tue Mar 10 15:03:43 2026 +0000 Add bash.sh diff --git a/bash.sh b/bash.sh new file mode 100644 index 0000000..a96430f --- /dev/null +++ b/bash.sh @@ -0,0 +1,936 @@ +#!/bin/bash - +#=============================================================================== +# +# FILE: cfScanner.sh +# +# USAGE: ./cfScanner.sh [Argumets] +# +# DESCRIPTION: Scan all 1.5 Mil CloudFlare IP addresses +# +# OPTIONS: -h, --help +# REQUIREMENTS: getopt, jq, git, tput, bc, curl, parallel (version > 20220515), shuf +# AUTHOR: Morteza Bashsiz (mb), morteza.bashsiz@gmail.com +# ORGANIZATION: Linux +# CREATED: 01/24/2023 07:36:57 PM +# REVISION: nomadzzz, armgham, beh-rouz, amini8, mahdibahramih, armineslami, miytiy, F4RAN +#=============================================================================== + +export TOP_PID=$$ + +# Function fncLongIntToStr +# converts IP in long integer format to a string +fncLongIntToStr() { + local IFS=. num quad ip e + num=$1 + for e in 3 2 1 + do + (( quad = 256 ** e)) + (( ip[3-e] = num / quad )) + (( num = num % quad )) + done + ip[3]=$num + echo "${ip[*]}" +} +# End of Function fncLongIntToStr + +# Function fncIpToLongInt +# converts IP to long integer +fncIpToLongInt() { + local IFS=. ip num e + # shellcheck disable=SC2206 + ip=($1) + for e in 3 2 1 + do + (( num += ip[3-e] * 256 ** e )) + done + (( num += ip[3] )) + echo $num +} +# End of Function fncIpToLongInt + +# Function fncSubnetToIP +# converts subnet to IP list +fncSubnetToIP() { + # shellcheck disable=SC2206 + local network=(${1//\// }) + # shellcheck disable=SC2206 + local iparr=(${network[0]//./ }) + local mask=32 + [[ $((${#network[@]})) -gt 1 ]] && mask=${network[1]} + + local maskarr + # shellcheck disable=SC2206 + if [[ ${mask} = '\.' ]]; then # already mask format like 255.255.255.0 + maskarr=(${mask//./ }) + else # assume CIDR like /24, convert to mask + if [[ $((mask)) -lt 8 ]]; then + maskarr=($((256-2**(8-mask))) 0 0 0) + elif [[ $((mask)) -lt 16 ]]; then + maskarr=(255 $((256-2**(16-mask))) 0 0) + elif [[ $((mask)) -lt 24 ]]; then + maskarr=(255 255 $((256-2**(24-mask))) 0) + elif [[ $((mask)) -lt 32 ]]; then + maskarr=(255 255 255 $((256-2**(32-mask)))) + elif [[ ${mask} == 32 ]]; then + maskarr=(255 255 255 255) + fi + fi + + # correct wrong subnet masks (e.g. 240.192.255.0 to 255.255.255.0) + [[ ${maskarr[2]} == 255 ]] && maskarr[1]=255 + [[ ${maskarr[1]} == 255 ]] && maskarr[0]=255 + + # generate list of ip addresses + if [[ "$randomNumber" != "NULL" ]] + then + local bytes=(0 0 0 0) + for i in $(seq 0 $((255-maskarr[0]))); do + bytes[0]="$(( i+(iparr[0] & maskarr[0]) ))" + for j in $(seq 0 $((255-maskarr[1]))); do + bytes[1]="$(( j+(iparr[1] & maskarr[1]) ))" + for k in $(seq 0 $((255-maskarr[2]))); do + bytes[2]="$(( k+(iparr[2] & maskarr[2]) ))" + for l in $(seq 1 $((255-maskarr[3]))); do + bytes[3]="$(( l+(iparr[3] & maskarr[3]) ))" + ipList+=("$(printf "%d.%d.%d.%d" "${bytes[@]}")") + done + done + done + done + # Choose random IP addresses from generated IP list + if [[ "$osVersion" == "Linux" ]] + then + mapfile -t ipList < <(shuf -e "${ipList[@]}") + mapfile -t ipList < <(shuf -e "${ipList[@]:0:$randomNumber}") + elif [[ "$osVersion" == "Mac" ]] + then + # shellcheck disable=SC2207 + ipList=($(printf '%s\n' "${ipList[@]}" | shuf)) + # shellcheck disable=SC2207 + ipList=($(printf '%s\n' "${ipList[@]:0:$randomNumber}" | shuf)) + else + echo "OS not supported only Linux or Mac" + exit 1 + fi + for i in "${ipList[@]}"; do + echo "$i" + done + elif [[ "$randomNumber" == "NULL" ]] + then + local bytes=(0 0 0 0) + for i in $(seq 0 $((255-maskarr[0]))); do + bytes[0]="$(( i+(iparr[0] & maskarr[0]) ))" + for j in $(seq 0 $((255-maskarr[1]))); do + bytes[1]="$(( j+(iparr[1] & maskarr[1]) ))" + for k in $(seq 0 $((255-maskarr[2]))); do + bytes[2]="$(( k+(iparr[2] & maskarr[2]) ))" + for l in $(seq 1 $((255-maskarr[3]))); do + bytes[3]="$(( l+(iparr[3] & maskarr[3]) ))" + printf "%d.%d.%d.%d\n" "${bytes[@]}" + done + done + done + done + fi +} +# End of Function fncSubnetToIP + +# Function fncShowProgress +# Progress bar maker function (based on https://www.baeldung.com/linux/command-line-progress-bar) +function fncShowProgress { + barCharDone="=" + barCharTodo=" " + barSplitter='>' + barPercentageScale=2 + current="$1" + total="$2" + + barSize="$(($(tput cols)-70))" # 70 cols for description characters + + # calculate the progress in percentage + percent=$(bc <<< "scale=$barPercentageScale; 100 * $current / $total" ) + # The number of done and todo characters + done=$(bc <<< "scale=0; $barSize * $percent / 100" ) + todo=$(bc <<< "scale=0; $barSize - $done") + # build the done and todo sub-bars + doneSubBar=$(printf "%${done}s" | tr " " "${barCharDone}") + todoSubBar=$(printf "%${todo}s" | tr " " "${barCharTodo} - 1") # 1 for barSplitter + spacesSubBar=$(printf "%${todo}s" | tr " " " ") + + # output the bar + progressBar="| Progress bar of main IPs: [${doneSubBar}${barSplitter}${todoSubBar}] ${percent}%${spacesSubBar}" # Some end space for pretty formatting +} +# End of Function showProgress + +# Function fncCheckIPList +# Check Subnet +function fncCheckIPList { + local ipList scriptDir resultFile timeoutCommand domainFronting downOK upOK + ipList="${1}" + resultFile="${3}" + scriptDir="${4}" + configId="${5}" + configHost="${6}" + configPort="${7}" + configPath="${8}" + fileSize="${9}" + osVersion="${10}" + clientCommand="${11}" + tryCount="${12}" + downThreshold="${13}" + upThreshold="${14}" + downloadOrUpload="${15}" + vpnOrNot="${16}" + quickOrNot="${17}" + binDir="$scriptDir/../bin" + tempConfigDir="$scriptDir/tempConfig" + uploadFile="$tempConfigDir/upload_file" + configPath=$(echo "$configPath" | sed 's/\//\\\//g') + # set proper command for linux + if command -v timeout >/dev/null 2>&1; + then + timeoutCommand="timeout" + else + # set proper command for mac + if command -v gtimeout >/dev/null 2>&1; + then + timeoutCommand="gtimeout" + else + echo >&2 "I require 'timeout' command but it's not installed. Please install 'timeout' or an alternative command like 'gtimeout' and try again." + exit 1 + fi + fi + if [[ "$vpnOrNot" == "YES" ]] + then + for ip in ${ipList} + do + if [[ "$downloadOrUpload" == "BOTH" ]] + then + downOK="NO" + upOK="NO" + elif [[ "$downloadOrUpload" == "UP" ]] + then + downOK="YES" + upOK="NO" + elif [[ "$downloadOrUpload" == "DOWN" ]] + then + downOK="NO" + upOK="YES" + fi + if $timeoutCommand 1 bash -c " /dev/null 2>&1; + then + if [[ "$quickOrNot" == "NO" ]] + then + domainFronting=$($timeoutCommand 1 curl -k -s --tlsv1.2 -H "Host: speed.cloudflare.com" --resolve "speed.cloudflare.com:443:$ip" "https://speed.cloudflare.com/__down?bytes=10") + elif [[ "$quickOrNot" == "YES" ]] + then + domainFronting="0000000000" + fi + if [[ "$domainFronting" == "0000000000" ]] + then + mainDomain=$(echo "$configHost" | awk -F '.' '{ print $2"."$3}') + if [[ "$osVersion" == "Linux" ]] + then + randomUUID=$(cat /proc/sys/kernel/random/uuid) + elif [[ "$osVersion" == "Mac" ]] + then + randomUUID=$(uuidgen | tr '[:upper:]' '[:lower:]') + else + echo "OS not supported only Linux or Mac" + exit 1 + fi + configServerName="$randomUUID.$mainDomain" + ipConfigFile="$tempConfigDir/config.json.$ip".json + cp "$scriptDir"/config.json.temp "$ipConfigFile" + ipO1=$(echo "$ip" | awk -F '.' '{print $1}') + ipO2=$(echo "$ip" | awk -F '.' '{print $2}') + ipO3=$(echo "$ip" | awk -F '.' '{print $3}') + ipO4=$(echo "$ip" | awk -F '.' '{print $4}') + port=$((ipO1 + ipO2 + ipO3 + ipO4)) + if [[ "$osVersion" == "Mac" ]] + then + sed -i "" "s/IP.IP.IP.IP/$ip/g" "$ipConfigFile" + sed -i "" "s/PORTPORT/3$port/g" "$ipConfigFile" + sed -i "" "s/IDID/$configId/g" "$ipConfigFile" + sed -i "" "s/HOSTHOST/$configHost/g" "$ipConfigFile" + sed -i "" "s/CFPORTCFPORT/$configPort/g" "$ipConfigFile" + sed -i "" "s/ENDPOINTENDPOINT/$configPath/g" "$ipConfigFile" + sed -i "" "s/RANDOMHOST/$configServerName/g" "$ipConfigFile" + elif [[ "$osVersion" == "Linux" ]] + then + sed -i "s/IP.IP.IP.IP/$ip/g" "$ipConfigFile" + sed -i "s/PORTPORT/3$port/g" "$ipConfigFile" + sed -i "s/IDID/$configId/g" "$ipConfigFile" + sed -i "s/HOSTHOST/$configHost/g" "$ipConfigFile" + sed -i "s/CFPORTCFPORT/$configPort/g" "$ipConfigFile" + sed -i "s/ENDPOINTENDPOINT/$configPath/g" "$ipConfigFile" + sed -i "s/RANDOMHOST/$configServerName/g" "$ipConfigFile" + fi + # shellcheck disable=SC2009 + pid=$(ps aux | grep config.json."$ip" | grep -v grep | awk '{ print $2 }') + if [[ "$pid" ]] + then + kill -9 "$pid" > /dev/null 2>&1 + fi + downTotalTime=0 + upTotalTime=0 + downAvgStr="" + upAvgStr="" + downSuccessedCount=0 + upSuccessedCount=0 + nohup "$binDir"/"$clientCommand" -c "$ipConfigFile" > /dev/null & + sleep 2 + for i in $(seq 1 "$tryCount"); + do + downTimeMil=0 + upTimeMil=0 + if [[ "$downloadOrUpload" == "DOWN" ]] || [[ "$downloadOrUpload" == "BOTH" ]] + then + downTimeMil=$($timeoutCommand 2 curl -x "socks5://127.0.0.1:3$port" -s -w "TIME: %{time_total}\n" --resolve "speed.cloudflare.com:443:$ip" "https://speed.cloudflare.com/__down?bytes=$fileSize" --output /dev/null | grep "TIME" | tail -n 1 | awk '{print $2}' | xargs -I {} echo "{} * 1000 /1" | bc ) + if [[ $downTimeMil -gt 100 ]] + then + downSuccessedCount=$(( downSuccessedCount+1 )) + else + downTimeMil=0 + fi + fi + if [[ "$downloadOrUpload" == "UP" ]] || [[ "$downloadOrUpload" == "BOTH" ]] + then + result=$($timeoutCommand 2 curl -x "socks5://127.0.0.1:3$port" -s -w "\nTIME: %{time_total}\n" --resolve "speed.cloudflare.com:443:$ip" --data "@$uploadFile" https://speed.cloudflare.com/__up | grep "TIME" | tail -n 1 | awk '{print $2}' | xargs -I {} echo "{} * 1000 /1" | bc) + if [[ "$result" ]] + then + upTimeMil="$result" + if [[ $upTimeMil -gt 100 ]] + then + upSuccessedCount=$(( upSuccessedCount+1 )) + else + upTimeMil=0 + fi + fi + fi + downTotalTime=$(( downTotalTime+downTimeMil )) + upTotalTime=$(( upTotalTime+upTimeMil )) + downAvgStr="$downAvgStr $downTimeMil" + upAvgStr="$upAvgStr $upTimeMil" + done + if [[ $downSuccessedCount -ge $downThreshold ]] && [[ "$downloadOrUpload" != "UP" ]] + then + downOK="YES" + downRealTime=$(( downTotalTime/downSuccessedCount )) + else + downRealTime=0 + fi + if [[ $upSuccessedCount -ge $upThreshold ]] && [[ "$downloadOrUpload" != "DOWN" ]] + then + upOK="YES" + upRealTime=$(( upTotalTime/upSuccessedCount )) + else + upRealTime=0 + fi + # shellcheck disable=SC2009 + pid=$(ps aux | grep config.json."$ip" | grep -v grep | awk '{ print $2 }') + if [[ "$pid" ]] + then + kill -9 "$pid" > /dev/null 2>&1 + fi + if [[ "$downOK" == "YES" ]] && [[ "$upOK" == "YES" ]] + then + if [[ "$downRealTime" && $downRealTime -gt 100 ]] || [[ "$upRealTime" && $upRealTime -gt 100 ]] + then + echo -e "${GREEN}OK${NC} $ip ${BLUE}DOWN: Avg $downRealTime $downAvgStr ${ORANGE}UP: Avg $upRealTime, $upAvgStr${NC}" + if [[ "$downRealTime" && $downRealTime -gt 100 ]] + then + #echo "${GREEN}OK${NC} $ip ${BLUE}DOWN: Avg $downRealTime $downAvgStr${NC}" + echo "$downRealTime, $downAvgStr DOWN FOR IP $ip" >> "$resultFile" + fi + if [[ "$upRealTime" && $upRealTime -gt 100 ]] + then + #echo "${GREEN}OK${NC} $ip ${BLUE}UP: $upRealTime, $upAvgStr${NC}" + echo "$upRealTime, $upAvgStr UP FOR IP $ip" >> "$resultFile" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + done + elif [[ "$vpnOrNot" == "NO" ]] + then + for ip in ${ipList} + do + if [[ "$downloadOrUpload" == "BOTH" ]] + then + downOK="NO" + upOK="NO" + elif [[ "$downloadOrUpload" == "UP" ]] + then + downOK="YES" + upOK="NO" + elif [[ "$downloadOrUpload" == "DOWN" ]] + then + downOK="NO" + upOK="YES" + fi + if $timeoutCommand 1 bash -c " /dev/null 2>&1; + then + if [[ "$quickOrNot" == "NO" ]] + then + domainFronting=$($timeoutCommand 1 curl -k -s --tlsv1.2 -H "Host: speed.cloudflare.com" --resolve "speed.cloudflare.com:443:$ip" "https://speed.cloudflare.com/__down?bytes=10") + elif [[ "$quickOrNot" == "YES" ]] + then + domainFronting="0000000000" + fi + if [[ "$domainFronting" == "0000000000" ]] + then + downTotalTime=0 + upTotalTime=0 + downAvgStr="" + upAvgStr="" + downSuccessedCount=0 + upSuccessedCount=0 + for i in $(seq 1 "$tryCount"); + do + downTimeMil=0 + upTimeMil=0 + if [[ "$downloadOrUpload" == "DOWN" ]] || [[ "$downloadOrUpload" == "BOTH" ]] + then + downTimeMil=$($timeoutCommand 2 curl -s -w "TIME: %{time_total}\n" -H "Host: speed.cloudflare.com" --resolve "speed.cloudflare.com:443:$ip" "https://speed.cloudflare.com/__down?bytes=$fileSize" --output /dev/null | grep "TIME" | tail -n 1 | awk '{print $2}' | xargs -I {} echo "{} * 1000 /1" | bc ) + if [[ $downTimeMil -gt 100 ]] + then + downSuccessedCount=$(( downSuccessedCount+1 )) + else + downTimeMil=0 + fi + fi + if [[ "$downloadOrUpload" == "UP" ]] || [[ "$downloadOrUpload" == "BOTH" ]] + then + result=$($timeoutCommand 2 curl -s -w "\nTIME: %{time_total}\n" -H "Host: speed.cloudflare.com" --resolve "speed.cloudflare.com:443:$ip" --data "@$uploadFile" https://speed.cloudflare.com/__up | grep "TIME" | tail -n 1 | awk '{print $2}' | xargs -I {} echo "{} * 1000 /1" | bc) + if [[ "$result" ]] + then + upTimeMil="$result" + if [[ $upTimeMil -gt 100 ]] + then + upSuccessedCount=$(( upSuccessedCount+1 )) + else + upTimeMil=0 + fi + fi + fi + downTotalTime=$(( downTotalTime+downTimeMil )) + upTotalTime=$(( upTotalTime+upTimeMil )) + downAvgStr="$downAvgStr $downTimeMil" + upAvgStr="$upAvgStr $upTimeMil" + done + if [[ $downSuccessedCount -ge $downThreshold ]] && [[ "$downloadOrUpload" != "UP" ]] + then + downOK="YES" + downRealTime=$(( downTotalTime/downSuccessedCount )) + else + downRealTime=0 + fi + if [[ $upSuccessedCount -ge $upThreshold ]] && [[ "$downloadOrUpload" != "DOWN" ]] + then + upOK="YES" + upRealTime=$(( upTotalTime/upSuccessedCount )) + else + upRealTime=0 + fi + if [[ "$downOK" == "YES" ]] && [[ "$upOK" == "YES" ]] + then + if [[ "$downRealTime" && $downRealTime -gt 100 ]] || [[ "$upRealTime" && $upRealTime -gt 100 ]] + then + echo -e "${GREEN}OK${NC} $ip ${BLUE}DOWN: Avg $downRealTime $downAvgStr ${ORANGE}UP: Avg $upRealTime, $upAvgStr${NC}" + if [[ "$downRealTime" && $downRealTime -gt 100 ]] + then + #echo -e "${GREEN}OK${NC} $ip ${BLUE}DOWN: Avg $downRealTime $downAvgStr${NC}" + echo "$downRealTime, $downAvgStr DOWN FOR IP $ip" >> "$resultFile" + fi + if [[ "$upRealTime" && $upRealTime -gt 100 ]] + then + #echo -e "${GREEN}OK${NC} $ip ${BLUE}UP: $upRealTime, $upAvgStr${NC}" + echo "$upRealTime, $upAvgStr UP FOR IP $ip" >> "$resultFile" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + else + echo -e "${RED}FAILED${NC} $ip" + fi + done + fi +} +# End of Function fncCheckIPList +export -f fncCheckIPList + +# Function fncCheckDpnd +# Check for dipendencies +function fncCheckDpnd { + osVersion="NULL" + if [[ "$(uname)" == "Linux" ]]; then + command -v jq >/dev/null 2>&1 || { echo >&2 "I require 'jq' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + command -v parallel >/dev/null 2>&1 || { echo >&2 "I require 'parallel' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + command -v bc >/dev/null 2>&1 || { echo >&2 "I require 'bc' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + command -v timeout >/dev/null 2>&1 || { echo >&2 "I require 'timeout' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + osVersion="Linux" + elif [[ "$(uname)" == "Darwin" ]];then + command -v jq >/dev/null 2>&1 || { echo >&2 "I require 'jq' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + command -v parallel >/dev/null 2>&1 || { echo >&2 "I require 'parallel' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + command -v bc >/dev/null 2>&1 || { echo >&2 "I require 'bc' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + command -v gtimeout >/dev/null 2>&1 || { echo >&2 "I require 'gtimeout' but it's not installed. Please install it and try again."; kill -s 1 "$TOP_PID"; } + osVersion="Mac" + fi + echo "$osVersion" +} +# End of Function fncCheckDpnd + +# Function fncValidateConfig +# Install packages on destination host +function fncValidateConfig { + local config + config="$1" + if [[ -f "$config" ]] + then + echo "reading config ..." + configId=$(jq --raw-output .id "$config") + configHost=$(jq --raw-output .host "$config") + configPort=$(jq --raw-output .port "$config") + configPath=$(jq --raw-output .path "$config") + if ! [[ "$configId" ]] || ! [[ $configHost ]] || ! [[ $configPort ]] || ! [[ $configPath ]] + then + echo "config is not correct" + exit 1 + fi + else + echo "config file does not exist $config" + exit 1 + fi +} +# End of Function fncValidateConfig + +# Function fncCreateDir +# creates needed directory +function fncCreateDir { + local dirPath + dirPath="${1}" + if [ ! -d "$dirPath" ]; then + mkdir -p "$dirPath" + fi +} +# End of Function fncCreateDir + +# Function fncMainCFFindSubnet +# main Function for Subnet +function fncMainCFFindSubnet { + local threads progressBar resultFile scriptDir configId configHost configPort configPath fileSize osVersion parallelVersion subnetsFile breakedSubnets network netmask downloadOrUpload tryCount downThreshold upThreshold vpnOrNot quickOrNot + threads="${1}" + progressBar="${2}" + resultFile="${3}" + scriptDir="${4}" + configId="${5}" + configHost="${6}" + configPort="${7}" + configPath="${8}" + fileSize="${9}" + osVersion="${10}" + subnetsFile="${11}" + tryCount="${12}" + downThreshold="${13}" + upThreshold="${14}" + downloadOrUpload="${15}" + vpnOrNot="${16}" + quickOrNot="${17}" + + if [[ "$osVersion" == "Linux" ]] + then + if [[ "$clientCore" == "XRAY" ]] + then + clientCommand="xray" + else + clientCommand="v2ray" + fi + elif [[ "$osVersion" == "Mac" ]] + then + clientCommand="v2ray-mac" + else + echo "OS not supported only Linux or Mac" + exit 1 + fi + + parallelVersion=$(parallel --version | head -n1 | grep -Ewo '[0-9]{8}') + defaultSubnetsFileUrl="https://raw.githubusercontent.com/MortezaBashsiz/CFScanner/main/config/cf.local.iplist" + + if [[ "$subnetsFile" == "NULL" ]] + then + defaultSubnetsFileUrlResult=$(curl -I -L -s "$defaultSubnetsFileUrl" | grep "^HTTP" | grep 200 | awk '{ print $2 }') + if [[ "$defaultSubnetsFileUrlResult" == "200" ]] + then + defaultSubnetsFile=$(curl -s "$defaultSubnetsFileUrl") + echo "Reading subnets from $defaultSubnetsFileUrl" + cfSubnetList="$defaultSubnetsFile" + else + echo "URL $defaultSubnetsFileUrl is not available. This URL contains the latest subnet file" + echo "Reading subnets from file $scriptDir/../config/cf.local.iplist" + cfSubnetList=$(cat "$scriptDir/../config/cf.local.iplist") + fi + else + echo "Reading subnets from file $subnetsFile" + cfSubnetList=$(cat "$subnetsFile") + fi + + ipListLength="0" + for subNet in ${cfSubnetList} + do + breakedSubnets= + maxSubnet=24 + network=${subNet%/*} + netmask=${subNet#*/} + if [[ ${netmask} -ge ${maxSubnet} ]] + then + breakedSubnets="${breakedSubnets} ${network}/${netmask}" + else + for i in $(seq 0 $(( $(( 2 ** (maxSubnet - netmask) )) - 1 )) ) + do + breakedSubnets="${breakedSubnets} $( fncLongIntToStr $(( $( fncIpToLongInt "${network}" ) + $(( 2 ** ( 32 - maxSubnet ) * i )) )) )/${maxSubnet}" + done + fi + breakedSubnets=$(echo "${breakedSubnets}"|tr ' ' '\n') + for breakedSubnet in ${breakedSubnets} + do + ipListLength=$(( ipListLength+1 )) + done + done + + passedIpsCount=0 + for subNet in ${cfSubnetList} + do + breakedSubnets= + maxSubnet=24 + network=${subNet%/*} + netmask=${subNet#*/} + if [[ ${netmask} -ge ${maxSubnet} ]] + then + breakedSubnets="${breakedSubnets} ${network}/${netmask}" + else + for i in $(seq 0 $(( $(( 2 ** (maxSubnet - netmask) )) - 1 )) ) + do + breakedSubnets="${breakedSubnets} $( fncLongIntToStr $(( $( fncIpToLongInt "${network}" ) + $(( 2 ** ( 32 - maxSubnet ) * i )) )) )/${maxSubnet}" + done + fi + breakedSubnets=$(echo "${breakedSubnets}"|tr ' ' '\n') + for breakedSubnet in ${breakedSubnets} + do + fncShowProgress "$passedIpsCount" "$ipListLength" + killall v2ray > /dev/null 2>&1 + ipList=$(fncSubnetToIP "$breakedSubnet") + tput cuu1; tput ed # rewrites Parallel's bar + if [[ $parallelVersion -gt 20220515 ]]; + then + parallel --ll --bar -j "$threads" fncCheckIPList ::: "$ipList" ::: "$progressBar" ::: "$resultFile" ::: "$scriptDir" ::: "$configId" ::: "$configHost" ::: "$configPort" ::: "$configPath" ::: "$fileSize" ::: "$osVersion" ::: "$clientCommand" ::: "$tryCount" ::: "$downThreshold" ::: "$upThreshold" ::: "$downloadOrUpload" ::: "$vpnOrNot" ::: "$quickOrNot" + else + echo -e "${RED}$progressBar${NC}" + parallel -j "$threads" fncCheckIPList ::: "$ipList" ::: "$progressBar" ::: "$resultFile" ::: "$scriptDir" ::: "$configId" ::: "$configHost" ::: "$configPort" ::: "$configPath" ::: "$fileSize" ::: "$osVersion" ::: "$clientCommand" ::: "$tryCount" ::: "$downThreshold" ::: "$upThreshold" ::: "$downloadOrUpload" ::: "$vpnOrNot" ::: "$quickOrNot" + fi + killall v2ray > /dev/null 2>&1 + passedIpsCount=$(( passedIpsCount+1 )) + done + done + sort -n -k1 -t, "$resultFile" -o "$resultFile" +} +# End of Function fncMainCFFindSubnet + +# Function fncMainCFFindIP +# main Function for IP +function fncMainCFFindIP { + local threads progressBar resultFile scriptDir configId configHost configPort configPath fileSize osVersion parallelVersion IPFile downloadOrUpload downThreshold upThreshold vpnOrNot quickOrNot + threads="${1}" + progressBar="${2}" + resultFile="${3}" + scriptDir="${4}" + configId="${5}" + configHost="${6}" + configPort="${7}" + configPath="${8}" + fileSize="${9}" + osVersion="${10}" + IPFile="${11}" + tryCount="${12}" + downThreshold="${13}" + upThreshold="${14}" + downloadOrUpload="${15}" + vpnOrNot="${16}" + quickOrNot="${17}" + + if [[ "$osVersion" == "Linux" ]] + then + if [[ "$clientCore" == "XRAY" ]] + then + clientCommand="xray" + else + clientCommand="v2ray" + fi + elif [[ "$osVersion" == "Mac" ]] + then + clientCommand="v2ray-mac" + else + echo "OS not supported only Linux or Mac" + exit 1 + fi + + parallelVersion=$(parallel --version | head -n1 | grep -Ewo '[0-9]{8}') + + cfIPList=$(cat "$IPFile") + killall v2ray > /dev/null 2>&1 + tput cuu1; tput ed # rewrites Parallel's bar + if [[ $parallelVersion -gt 20220515 ]]; + then + parallel --ll --bar -j "$threads" fncCheckIPList ::: "$cfIPList" ::: "$progressBar" ::: "$resultFile" ::: "$scriptDir" ::: "$configId" ::: "$configHost" ::: "$configPort" ::: "$configPath" ::: "$fileSize" ::: "$osVersion" ::: "$clientCommand" ::: "$tryCount" ::: "$downThreshold" ::: "$upThreshold" ::: "$downloadOrUpload" ::: "$vpnOrNot" ::: "$quickOrNot" + else + echo -e "${RED}$progressBar${NC}" + parallel -j "$threads" fncCheckIPList ::: "$cfIPList" ::: "$progressBar" ::: "$resultFile" ::: "$scriptDir" ::: "$configId" ::: "$configHost" ::: "$configPort" ::: "$configPath" ::: "$fileSize" ::: "$osVersion" ::: "$clientCommand" ::: "$tryCount" ::: "$downThreshold" ::: "$upThreshold" ::: "$downloadOrUpload" ::: "$vpnOrNot" ::: "$quickOrNot" + fi + killall v2ray > /dev/null 2>&1 + sort -n -k1 -t, "$resultFile" -o "$resultFile" +} +# End of Function fncMainCFFindIP + +clientConfigFile="https://raw.githubusercontent.com/MortezaBashsiz/CFScanner/main/config/ClientConfig.json" +subnetIPFile="NULL" + +# Function fncUsage +# usage function +function fncUsage { + if [[ "$osVersion" == "Mac" ]] + then + echo -e "Usage: cfScanner [ -v YES/NO ] + [ -m SUBNET/IP ] + [ -t DOWN/UP/BOTH ] + [ -p ] threads + [ -n ] trycount + [ -c ] + [ -s ] speed + [ -r ] randomness + [ -d ] download threshold + [ -u ] upload threshold + [ -f (if you chose IP mode)] + [ -q YES/NO] + [ -h ] help\n" + exit 2 + elif [[ "$osVersion" == "Linux" ]] + then + echo -e "Usage: cfScanner [ -x|--core V2RAY/XRAY ] + [ -v|--vpn-mode YES/NO ] + [ -m|--mode SUBNET/IP ] + [ -t|--test-type DOWN/UP/BOTH ] + [ -p|--thread ] + [ -n|--tryCount ] + [ -c|--config ] + [ -s|--speed ] + [ -r|--random ] + [ -d|--down-threshold ] + [ -u|--up-threshold ] + [ -f|--file (if you chose IP mode)] + [ -q|--quick YES/NO] + [ -h|--help ]\n" + exit 2 + fi +} +# End of Function fncUsage + +clientCore="XRAY" +randomNumber="NULL" +downThreshold="1" +upThreshold="1" +osVersion="$(fncCheckDpnd)" +vpnOrNot="NO" +subnetOrIP="SUBNET" +downloadOrUpload="BOTH" +threads="4" +tryCount="1" +config="NULL" +speed="100" +quickOrNot="NO" + +if [[ "$osVersion" == "Mac" ]] +then + parsedArguments=$(getopt v:m:t:p:n:c:s:r:d:u:f:q:h "$@") +elif [[ "$osVersion" == "Linux" ]] +then + parsedArguments=$(getopt -a -n cfScanner -o x:v:m:t:p:n:c:s:r:d:u:f:q:h --long core:,vpn-mode:,mode:,test-type:,thread:,tryCount:,config:,speed:,random:,down-threshold:,up-threshold:,file:,quick:,help -- "$@") +fi + +eval set -- "$parsedArguments" +if [[ "$osVersion" == "Mac" ]] +then + while : + do + case "$1" in + -v) vpnOrNot="$2" ; shift 2 ;; + -m) subnetOrIP="$2" ; shift 2 ;; + -t) downloadOrUpload="$2" ; shift 2 ;; + -p) threads="$2" ; shift 2 ;; + -n) tryCount="$2" ; shift 2 ;; + -c) config="$2" ; shift 2 ;; + -s) speed="$2" ; shift 2 ;; + -r) randomNumber="$2" ; shift 2 ;; + -d) downThreshold="$2" ; shift 2 ;; + -u) upThreshold="$2" ; shift 2 ;; + -f) subnetIPFile="$2" ; shift 2 ;; + -q) quickOrNot="$2" ; shift 2 ;; + -h) fncUsage ;; + --) shift; break ;; + *) echo "Unexpected option: $1 is not acceptable" + fncUsage ;; + esac + done +elif [[ "$osVersion" == "Linux" ]] +then + while : + do + case "$1" in + -x|--core) clientCore="$2" ; shift 2 ;; + -v|--vpn-mode) vpnOrNot="$2" ; shift 2 ;; + -m|--mode) subnetOrIP="$2" ; shift 2 ;; + -t|--test-type) downloadOrUpload="$2" ; shift 2 ;; + -p|--thread) threads="$2" ; shift 2 ;; + -n|--tryCount) tryCount="$2" ; shift 2 ;; + -c|--config) config="$2" ; shift 2 ;; + -s|--speed) speed="$2" ; shift 2 ;; + -r|--random) randomNumber="$2" ; shift 2 ;; + -d|--down-threshold) downThreshold="$2" ; shift 2 ;; + -u|--up-threshold) upThreshold="$2" ; shift 2 ;; + -f|--file) subnetIPFile="$2" ; shift 2 ;; + -q|--quick) quickOrNot="$2" ; shift 2 ;; + -h|--help) fncUsage ;; + --) shift; break ;; + *) echo "Unexpected option: $1 is not acceptable" + fncUsage ;; + esac + done +fi + +validArguments=$? +if [ "$validArguments" != "0" ]; then + echo "error validate" + exit 2 +fi + +if [[ "$clientCore" != "XRAY" && "$clientCore" != "V2RAY" ]] +then + echo "Wrong value: $clientCore Must be XRAY or V2RAY" + exit 2 +fi +if [[ "$vpnOrNot" != "YES" && "$vpnOrNot" != "NO" ]] +then + echo "Wrong value: $vpnOrNot Must be YES or NO" + exit 2 +fi +if [[ "$subnetOrIP" != "SUBNET" && "$subnetOrIP" != "IP" ]] +then + echo "Wrong value: $subnetOrIP Must be SUBNET or IP" + exit 2 +fi +if [[ "$downloadOrUpload" != "DOWN" && "$downloadOrUpload" != "UP" && "$downloadOrUpload" != "BOTH" ]] +then + echo "Wrong value: $downloadOrUpload Must be DOWN or UP or BOTH" + exit 2 +fi + +if [[ "$subnetIPFile" != "NULL" ]] +then + if ! [[ -f "$subnetIPFile" ]] + then + echo "file does not exists: $subnetIPFile" + exit 1 + fi +fi + +now=$(date +"%Y%m%d-%H%M%S") +scriptDir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +resultDir="$scriptDir/result" +resultFile="$resultDir/$now-result.cf" +tempConfigDir="$scriptDir/tempConfig" +filesDir="$tempConfigDir" + +uploadFile="$filesDir/upload_file" + +configId="NULL" +configHost="NULL" +configPort="NULL" +configPath="NULL" + +progressBar="" + +export GREEN='\033[0;32m' +export BLUE='\033[0;34m' +export RED='\033[0;31m' +export ORANGE='\033[0;33m' +export YELLOW='\033[1;33m' +export NC='\033[0m' + +fncCreateDir "${resultDir}" +fncCreateDir "${tempConfigDir}" +echo "" > "$resultFile" + +if [[ "$config" == "NULL" ]] +then + echo "updating config" + configRealUrlResult=$(curl -I -L -s "$clientConfigFile" | grep "^HTTP" | grep 200 | awk '{ print $2 }') + if [[ "$configRealUrlResult" == "200" ]] + then + curl -s "$clientConfigFile" -o "$scriptDir"/config.default + echo "config.default updated with $clientConfigFile" + echo "" + config="$scriptDir/config.default" + cat "$config" + else + echo "" + echo "config file is not available $clientConfigFile" + echo "use your own" + echo "" + exit 1 + fi +else + echo "" + echo "using your own config $config" + cat "$config" + echo "" +fi + +fileSize="$(( 2*speed*1024 ))" +if [[ "$downloadOrUpload" == "DOWN" || "$downloadOrUpload" == "BOTH" ]] +then + echo "You are testing download" +fi +if [[ "$downloadOrUpload" == "UP" || "$downloadOrUpload" == "BOTH" ]] +then + echo "You are testing upload" + echo "making upload file by size $fileSize Bytes in $uploadFile" + ddSize="$(( 2*speed ))" + dd if=/dev/random of="$uploadFile" bs=1024 count="$ddSize" > /dev/null 2>&1 +fi + +fncValidateConfig "$config" + +if [[ "$subnetOrIP" == "SUBNET" ]] +then + fncMainCFFindSubnet "$threads" "$progressBar" "$resultFile" "$scriptDir" "$configId" "$configHost" "$configPort" "$configPath" "$fileSize" "$osVersion" "$subnetIPFile" "$tryCount" "$downThreshold" "$upThreshold" "$downloadOrUpload" "$vpnOrNot" "$quickOrNot" +elif [[ "$subnetOrIP" == "IP" ]] +then + fncMainCFFindIP "$threads" "$progressBar" "$resultFile" "$scriptDir" "$configId" "$configHost" "$configPort" "$configPath" "$fileSize" "$osVersion" "$subnetIPFile" "$tryCount" "$downThreshold" "$upThreshold" "$downloadOrUpload" "$vpnOrNot" "$quickOrNot" +else + echo "$subnetOrIP is not correct choose one SUBNET or IP" + exit 1 +fi \ No newline at end of file