侧边栏壁纸
博主头像
一叶舟的秘密花园 博主等级

行动起来,活在当下

  • 累计撰写 35 篇文章
  • 累计创建 14 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

抓包出入流量IP端口shell脚本-cneots7

Li
Li
2025-10-29 / 0 评论 / 1 点赞 / 55 阅读 / 0 字
温馨提示:
本文最后更新于2025-11-06,若内容或图片失效,请留言反馈。 八月长江万里晴,千帆一道带风轻

脚本(需要配yum)

#!/bin/bash
# 抓包监控脚本 - 捕获所有流量版(进出流量分离)

# 配置项
CAPTURE_DIR="/var/pcap"          # 抓包存储目录
UPDATE_INTERVAL=60               # 抓包间隔(秒)
DISK_THRESHOLD=80                # 磁盘使用率阈值(%)
INTERFACE="$(ip -o link show | awk -F': ' '{if ($2 != "lo") print $2}' | head -n 1)"  # 监听的网卡
IN_STATS_FILE="$CAPTURE_DIR/access_stats_in.txt"   # 入方向统计文件
OUT_STATS_FILE="$CAPTURE_DIR/access_stats_out.txt" # 出方向统计文件
LOG_FILE="$CAPTURE_DIR/zhuabao.log"         # 运行日志文件
MAX_LOG_SIZE=100                 # 日志文件最大大小(MB)
LOG_RETENTION=7                  # 日志保留天数

# 获取本机IP地址
LOCAL_IP=$(ip -o -4 addr list $INTERFACE | awk '{print $4}' | cut -d/ -f1)
if [ -z "$LOCAL_IP" ]; then
    echo "无法获取本机IP地址,请检查网卡配置"
    exit 1
fi

# 识别系统类型并安装依赖
install_dependencies() {
    local distro=""
    local pkg_manager=""
    local install_cmd=""
    
    # 检测系统类型
    if [ -f /etc/os-release ]; then
        source /etc/os-release
        distro=$ID
    elif type lsb_release >/dev/null 2>&1; then
        distro=$(lsb_release -si | tr '[:upper:]' '[:lower:]')
    else
        log "WARN: 无法确定Linux发行版,将尝试通用安装方法"
        distro="unknown"
    fi

    # 根据系统类型设置包管理器和安装命令
    case $distro in
        ubuntu|debian)
            pkg_manager="apt-get"
            install_cmd="sudo $pkg_manager install -y"
            ;;
        centos|rhel|fedora|rocky|almalinux)
            pkg_manager="yum"
            [ "$distro" = "fedora" ] && pkg_manager="dnf"
            install_cmd="sudo $pkg_manager install -y"
            ;;
        opensuse*|sles)
            pkg_manager="zypper"
            install_cmd="sudo $pkg_manager install -y"
            ;;
        arch)
            pkg_manager="pacman"
            install_cmd="sudo $pkg_manager -S --noconfirm"
            ;;
        *)
            log "ERROR: 不支持的Linux发行版: $distro"
            return 1
            ;;
    esac

    log "INFO: 检测到系统: $distro, 使用包管理器: $pkg_manager"

    # 检查并安装必要软件包
    local required_pkgs=("tcpdump" "tshark" "wireshark-common" "coreutils")
    local missing_pkgs=()

    # 检查哪些包未安装
    for pkg in "${required_pkgs[@]}"; do
        if ! command -v $pkg >/dev/null 2>&1; then
            missing_pkgs+=("$pkg")
        fi
    done

    # 如果有缺失的包则安装
    if [ ${#missing_pkgs[@]} -gt 0 ]; then
        log "INFO: 正在安装缺失的软件包: ${missing_pkgs[*]}"
        
        # 更新包索引
        case $distro in
            ubuntu|debian)
                sudo $pkg_manager update
                ;;
            centos|rhel|fedora|rocky|almalinux)
                sudo $pkg_manager makecache
                ;;
        esac

        # 特殊处理不同系统的包名差异
        local install_pkgs=()
        for pkg in "${missing_pkgs[@]}"; do
            case $pkg in
                tshark)
                    case $distro in
                        ubuntu|debian)
                            install_pkgs+=("wireshark")
                            ;;
                        centos|rhel|fedora|rocky|almalinux)
                            install_pkgs+=("wireshark")
                            ;;
                        *)
                            install_pkgs+=("$pkg")
                            ;;
                    esac
                    ;;
                *)
                    install_pkgs+=("$pkg")
                    ;;
            esac
        done

        # 执行安装
        if ! $install_cmd "${install_pkgs[@]}"; then
            log "ERROR: 软件包安装失败"
            return 1
        fi
        
        log "INFO: 软件包安装完成"
    else
        log "INFO: 所有依赖已安装"
    fi

    return 0
}

# 日志管理
manage_logs() {
    # 检查日志大小
    if [ -f "$LOG_FILE" ]; then
        log_size=$(du -m "$LOG_FILE" | cut -f1)
        if [ "$log_size" -gt "$MAX_LOG_SIZE" ]; then
            mv "$LOG_FILE" "${LOG_FILE}.old"
            touch "$LOG_FILE"
        fi
    fi

    # 清理旧日志
    find "$CAPTURE_DIR" -name "zhuabao.log.old" -mtime +$LOG_RETENTION -delete
}

# 初始化目录和标题
init_files() {
    sudo mkdir -p "$CAPTURE_DIR" || {
        log "ERROR: 无法创建目录 $CAPTURE_DIR"
        exit 1
    }
    
    sudo touch "$LOG_FILE" || {
        log "ERROR: 无法创建日志文件"
        exit 1
    }

    # 初始化入方向统计文件(如果不存在)
    if [ ! -f "$IN_STATS_FILE" ]; then
        echo "# 入方向流量统计" | sudo tee "$IN_STATS_FILE" >/dev/null
        echo "# 源IP            目的IP          目的端口  访问次数" | sudo tee -a "$IN_STATS_FILE" >/dev/null
        echo "# ===============================================" | sudo tee -a "$IN_STATS_FILE" >/dev/null
    fi

    # 初始化出方向统计文件(如果不存在)
    if [ ! -f "$OUT_STATS_FILE" ]; then
        echo "# 出方向流量统计" | sudo tee "$OUT_STATS_FILE" >/dev/null
        echo "# 源IP            目的IP          目的端口  访问次数" | sudo tee -a "$OUT_STATS_FILE" >/dev/null
        echo "# ===============================================" | sudo tee -a "$OUT_STATS_FILE" >/dev/null
    fi
}

# 智能日志记录
log() {
    manage_logs  # 先检查日志状态
    echo "[$(date +'%F %T')] $1" | sudo tee -a "$LOG_FILE"
}

# 检查网卡是否存在
check_interface() {
    if ! ip link show "$INTERFACE" &>/dev/null; then
        log "ERROR: 网卡 $INTERFACE 不存在! 可用网卡:"
        ip -o link show | awk -F': ' '{print $2}' | sudo tee -a "$LOG_FILE"
        return 1
    fi
    return 0
}

# 生成累计统计报告(分离进出流量)
generate_stats() {
    local current_pcap="$CAPTURE_DIR/current_capture.pcap"
    
    # 检查抓包文件是否有效
    if [ ! -f "$current_pcap" ] || [ ! -s "$current_pcap" ]; then
        log "WARN: 抓包文件不存在或为空"
        return 1
    fi

    log "INFO: 正在生成进出流量统计..."

    # 临时文件存储新解析的数据
    local new_in_data=$(mktemp)
    local new_out_data=$(mktemp)
    sudo chmod 644 "$new_in_data" "$new_out_data"

    # 捕获所有流量统计并分离进出流量
    sudo tshark -r "$current_pcap" -T fields -E separator=, \
        -e ip.src -e ip.dst -e tcp.dstport -e udp.dstport 2>/dev/null | \
        awk -F, -v local_ip="$LOCAL_IP" '
        {
            if ($1 && $2) {
                port = ($3 != "") ? $3 : ($4 != "") ? $4 : "N/A";
                
                # 判断流量方向
                if ($2 == local_ip) {
                    # 入方向流量:目的IP是本机
                    key = $1 "," $2 "," port;
                    in_count[key]++;
                } else if ($1 == local_ip) {
                    # 出方向流量:源IP是本机
                    key = $1 "," $2 "," port;
                    out_count[key]++;
                } else {
                    # 其他流量(经过流量)
                    key = $1 "," $2 "," port;
                    other_count[key]++;
                }
            }
        }
        END {
            # 输出入方向流量
            for (key in in_count) {
                split(key, parts, ",");
                printf "%-15s %-15s %-9s %d\n", parts[1], parts[2], parts[3], in_count[key];
            }
        }' > "$new_in_data"

    sudo tshark -r "$current_pcap" -T fields -E separator=, \
        -e ip.src -e ip.dst -e tcp.dstport -e udp.dstport 2>/dev/null | \
        awk -F, -v local_ip="$LOCAL_IP" '
        {
            if ($1 && $2) {
                port = ($3 != "") ? $3 : ($4 != "") ? $4 : "N/A";
                
                # 判断流量方向
                if ($1 == local_ip) {
                    # 出方向流量:源IP是本机
                    key = $1 "," $2 "," port;
                    out_count[key]++;
                }
            }
        }
        END {
            # 输出出方向流量
            for (key in out_count) {
                split(key, parts, ",");
                printf "%-15s %-15s %-9s %d\n", parts[1], parts[2], parts[3], out_count[key];
            }
        }' > "$new_out_data"

    # 合并入方向数据
    local merged_in_data=$(mktemp)
    if [ -s "$IN_STATS_FILE" ]; then
        awk '
        NR == FNR && FNR > 3 {  # 读取旧数据(跳过标题)
            key = $1 " " $2 " " $3;
            count[key] = $4;
            next;
        }
        FNR != NR {  # 读取新数据
            key = $1 " " $2 " " $3;
            count[key] += $4;
        }
        END {
            for (key in count) {
                split(key, parts, " ");
                printf "%-15s %-15s %-9s %d\n", parts[1], parts[2], parts[3], count[key];
            }
        }' "$IN_STATS_FILE" "$new_in_data" | sort -k4nr > "$merged_in_data"
    else
        sort -k4nr "$new_in_data" > "$merged_in_data"
    fi

    # 合并出方向数据
    local merged_out_data=$(mktemp)
    if [ -s "$OUT_STATS_FILE" ]; then
        awk '
        NR == FNR && FNR > 3 {  # 读取旧数据(跳过标题)
            key = $1 " " $2 " " $3;
            count[key] = $4;
            next;
        }
        FNR != NR {  # 读取新数据
            key = $1 " " $2 " " $3;
            count[key] += $4;
        }
        END {
            for (key in count) {
                split(key, parts, " ");
                printf "%-15s %-15s %-9s %d\n", parts[1], parts[2], parts[3], count[key];
            }
        }' "$OUT_STATS_FILE" "$new_out_data" | sort -k4nr > "$merged_out_data"
    else
        sort -k4nr "$new_out_data" > "$merged_out_data"
    fi

    # 生成最终入方向统计文件
    {
        echo "# 入方向流量统计"
        echo "# 源IP            目的IP          目的端口  访问次数"
        echo "# ==============================================="
        cat "$merged_in_data"
    } | sudo tee "$IN_STATS_FILE" > /dev/null

    # 生成最终出方向统计文件
    {
        echo "# 出方向流量统计"
        echo "# 源IP            目的IP          目的端口  访问次数"
        echo "# ==============================================="
        cat "$merged_out_data"
    } | sudo tee "$OUT_STATS_FILE" > /dev/null

    # 清理临时文件
    rm -f "$new_in_data" "$new_out_data" "$merged_in_data" "$merged_out_data" "$current_pcap"

    local in_count=$(($(wc -l < "$IN_STATS_FILE") - 3))
    local out_count=$(($(wc -l < "$OUT_STATS_FILE") - 3))
    
    log "INFO: 进出流量统计更新完成"
    log "INFO: 入方向记录: $in_count 条 | 出方向记录: $out_count 条"
    return 0
}

# 主循环
main() {
    # 先安装依赖
    if ! install_dependencies; then
        log "ERROR: 依赖安装失败,脚本终止"
        exit 1
    fi
    
    init_files
    
    log "INFO: ==== 启动监控 ===="
    log "INFO: 网卡: $INTERFACE | 本机IP: $LOCAL_IP | 间隔: ${UPDATE_INTERVAL}s | 存储: $CAPTURE_DIR"
    log "INFO: 入方向文件: $IN_STATS_FILE | 出方向文件: $OUT_STATS_FILE"

    while true; do
        # 磁盘检查
        disk_usage=$(df --output=pcent "$CAPTURE_DIR" | tail -n1 | tr -d ' %')
        if [ "$disk_usage" -ge "$DISK_THRESHOLD" ]; then
            log "WARN: 磁盘使用率 ${disk_usage}% ≥ $DISK_THRESHOLD% 阈值"
            break
        fi

        # 网卡检查
        if ! check_interface; then
            sleep 10
            continue
        fi

        # 执行抓包(捕获所有流量,不限制过滤条件)
        current_pcap="$CAPTURE_DIR/current_capture.pcap"
        log "INFO: 开始抓包(捕获所有流量) -> $current_pcap"
        
        if sudo tcpdump -i "$INTERFACE" -G $UPDATE_INTERVAL -W 1 -w "$current_pcap" -s0 -n 2>> "$LOG_FILE"; then
            if [ -s "$current_pcap" ]; then
                capture_size=$(du -h "$current_pcap" | awk '{print $1}')
                log "INFO: 抓包完成 大小: $capture_size"
                generate_stats
            else
                log "INFO: 无网络流量"
            fi
        else
            tcpdump_exit=$?
            [ $tcpdump_exit -eq 2 ] && log "WARN: 抓包被中断" || log "WARN: 抓包错误 (退出码: $tcpdump_exit)"
        fi

        sleep 1
    done

    log "INFO: ==== 监控停止 ===="
}

# 执行主函数
main

启动命令

chmod +x zhuabao.sh

sed -i 's/\r$//' zhuabao.sh

nohup ./zhuabao.sh > /dev/null 2>&1 &

1

评论区