#!/usr/bin/env bash
#
# gslb_watch.sh
#
# 지정한 도메인의 A레코드를 초당 N회(기본 100회) 반복 질의하면서,
# 특정 대역(기본 211.47.x.x)이 나오면 결과를 파일에 저장합니다.
#
# 사용 예:
#   ./gslb_watch.sh
#   DOMAIN=livecloud-shield.pstatic.net.live.gscdn.net RATE=50 STOP_ON_MATCH=0 ./gslb_watch.sh
#   RESOLVER=8.8.8.8 DURATION=600 ./gslb_watch.sh
#
# 옵션은 모두 환경변수로 제어합니다 (첫 번째 위치 인자로 DOMAIN도 지정 가능):
#   DOMAIN         질의할 도메인 (기본: livecloud-shield.pstatic.net.live.gscdn.net)
#   PATTERN        매치시킬 정규식 (기본: ^211\.47\.)
#   RESOLVER       특정 DNS 서버로 질의 (예: 8.8.8.8). 비우면 시스템 기본 리졸버 사용
#   RATE           초당 질의 수 (기본: 100)
#   DURATION       총 실행 시간(초). 0이면 STOP_ON_MATCH 조건 전까지 무제한 (기본: 0)
#   STOP_ON_MATCH  1이면 처음 매치되는 순간 종료, 0이면 계속 실행 (기본: 1)
#   OUT_FILE       매치된 레코드 저장 파일 (기본: ./matched_YYYYMMDD.tsv)
#   LOG_FILE       전체 질의 로그 파일 (기본: ./query_YYYYMMDD.log)
#
set -uo pipefail
 
DOMAIN="${1:-${DOMAIN:-livecloud-shield.pstatic.net.live.gscdn.net}}"
PATTERN="${PATTERN:-^211\.47\.}"
RESOLVER="${RESOLVER:-}"
RATE="${RATE:-100}"
DURATION="${DURATION:-0}"
STOP_ON_MATCH="${STOP_ON_MATCH:-1}"
OUT_FILE="${OUT_FILE:-./matched_$(date +%Y%m%d).tsv}"
LOG_FILE="${LOG_FILE:-./query_$(date +%Y%m%d).log}"
MATCH_FLAG="$(mktemp -u /tmp/.gslb_watch_matched.XXXXXX)"
 
if ! command -v dig >/dev/null 2>&1; then
    echo "오류: dig 명령이 없습니다. (Debian/Ubuntu: apt install dnsutils / RHEL: yum install bind-utils)" >&2
    exit 1
fi
 
DIG_ARGS=(+short +time=1 +tries=1 A "$DOMAIN")
[[ -n "$RESOLVER" ]] && DIG_ARGS=("@$RESOLVER" "${DIG_ARGS[@]}")
 
touch "$OUT_FILE" "$LOG_FILE"
rm -f "$MATCH_FLAG"
 
query_count=0
start_ts=$(date +%s)
 
cleanup() {
    echo ""
    echo "----------------------------------------"
    echo "종료합니다."
    echo "총 실행 시간   : $(( $(date +%s) - start_ts ))초"
    echo "전체 질의 로그 : ${LOG_FILE} ($(wc -l < "$LOG_FILE" 2>/dev/null || echo 0) 줄)"
    echo "매치 저장 파일 : ${OUT_FILE} ($(wc -l < "$OUT_FILE" 2>/dev/null || echo 0) 줄)"
    rm -f "$MATCH_FLAG"
    exit 0
}
trap cleanup INT TERM
 
do_query() {
    local ts ip
    ts="$(date '+%Y-%m-%d %H:%M:%S')"
    while read -r ip; do
        [[ -z "$ip" ]] && continue
        echo -e "${ts}\t${ip}" >> "$LOG_FILE"
        if [[ "$ip" =~ $PATTERN ]]; then
            echo -e "${ts}\t${DOMAIN}\t${ip}" >> "$OUT_FILE"
            echo "[MATCH] ${ts}  ${DOMAIN} -> ${ip}"
            touch "$MATCH_FLAG"
        fi
    done < <(dig "${DIG_ARGS[@]}" 2>/dev/null)
}
 
echo "대상 도메인   : ${DOMAIN}"
echo "매치 패턴     : ${PATTERN}"
echo "목표 질의율   : 초당 ${RATE}회 (실제 속도는 dig 응답 시간에 따라 다소 낮아질 수 있습니다)"
echo "매치 시 종료  : $([[ "$STOP_ON_MATCH" == "1" ]] && echo 예 || echo 아니오, 계속 기록)"
echo "매치 저장     : ${OUT_FILE}"
echo "전체 로그     : ${LOG_FILE}"
echo "(Ctrl+C로 언제든 종료 가능)"
echo "----------------------------------------"
 
while true; do
    batch_start=$(date +%s.%N)
 
    for ((i = 0; i < RATE; i++)); do
        do_query &
    done
    wait
    query_count=$(( query_count + RATE ))
 
    if [[ -f "$MATCH_FLAG" && "$STOP_ON_MATCH" == "1" ]]; then
        echo "매치를 찾았습니다. 종료합니다."
        break
    fi
 
    if [[ "$DURATION" -gt 0 ]]; then
        now=$(date +%s)
        if (( now - start_ts >= DURATION )); then
            echo "설정한 실행 시간(${DURATION}초)이 지나 종료합니다."
            break
        fi
    fi
 
    # 1초 주기를 맞추기 위해, 이번 배치에 걸린 시간만큼 뺀 나머지만 대기
    batch_end=$(date +%s.%N)
    elapsed=$(echo "$batch_end - $batch_start" | bc)
    remaining=$(echo "1 - $elapsed" | bc)
    if (( $(echo "$remaining > 0" | bc -l) )); then
        sleep "$remaining"
    fi
done
 
cleanup
 

