package main

import (
	"container/list"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	Daemon = flag.Bool("d", false, "守护进程模式")
	child  = flag.Bool("child", false, "子进程模式")
)

var (
	listInterfaces bool
	interfaceName  *string
	outputFile     *string
	filter         *string

	SIG      int
	MAX_SIG  = 10
	SIG_NAME *string

	// 存储 IPv4 地址的链表
	ipList  = list.New()
	ipMutex sync.Mutex // 用于保护 ipList 的互斥锁
)

// 启动子进程
func startChildProcess() (*exec.Cmd, error) {
	cmd := exec.Command(os.Args[0], "-child=true", "-i", *interfaceName)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("启动子进程失败: %w", err)
	}
	fmt.Printf("子进程已启动, PID: %d\n", cmd.Process.Pid)
	return cmd, nil
}

// 停止子进程
func stopChildProcess(cmd *exec.Cmd) error {
	if cmd == nil || cmd.Process == nil {
		return fmt.Errorf("子进程无效")
	}

	// 尝试优雅地停止子进程
	if err := cmd.Process.Signal(syscall.SIGTERM); err != nil {
		return fmt.Errorf("停止子进程失败: %w", err)
	}

	// 等待一段时间让子进程退出
	done := make(chan error, 1)
	go func() {
		done <- cmd.Wait()
	}()

	select {
	case err := <-done:
		if err != nil {
			return fmt.Errorf("等待子进程退出时出错: %w", err)
		}
	case <-time.After(5 * time.Second):
		fmt.Println("子进程未在规定时间内退出，强制终止...")
		if err := cmd.Process.Kill(); err != nil {
			return fmt.Errorf("强制终止子进程失败: %w", err)
		}
	}

	fmt.Printf("子进程已停止, PID: %d\n", cmd.Process.Pid)
	return nil
}

// 等待信号并优雅退出
func waitForSignalAndCleanUp(cmd *exec.Cmd) {
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

	<-sigChan
	fmt.Println("主进程收到终止信号，准备清理子进程...")
	if err := stopChildProcess(cmd); err != nil {
		log.Fatalf("清理子进程时遇到错误: %v", err)
	}
	fmt.Println("主进程退出")
}

// 守护进程模式（简化版）
func startDaemon() {
	// 注意：此方法不会创建真正的守护进程，它只是以分离的方式启动一个新的进程。
	// 对于创建真正的守护进程，你应该使用 systemd 或其他服务管理器。
	cmd := exec.Command(os.Args[0], "-d=false", "-child=false", "-i", *interfaceName)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	if err != nil {
		log.Fatalf("无法启动新实例: %v", err)
	}
	fmt.Println("新实例已启动，当前进程将退出")
	os.Exit(0)
}

func runChildProcess() { // 子进程逻辑
	//fmt.Println("子进程启动中...")
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

	ticker := time.NewTicker(3 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-sigChan:
			fmt.Println("子进程收到终止信号，退出中...")
			return
		case <-ticker.C:
			//fmt.Println("子进程!!!")
		}
	}
}

func runMainProcess() { // 主进程逻辑

	fmt.Println("主进程启动...")

	cmd, err := startChildProcess()
	if err != nil {
		log.Fatalf("子进程启动失败: %v", err)
	}

	SIG = 0
	SIG_NAME := fmt.Sprintf("root%d", SIG)
	if return_value := IsIpset(SIG_NAME); return_value == 1 {
		createIPSet(SIG_NAME)
	}

	// 启动抓包
	go startPacketCapture()

	// 启动IP地域判断，管理
	go func() {
		for {
			ipMutex.Lock()        // 锁定互斥锁
			if ipList.Len() > 0 { // 链表不为空
				e1 := ipList.Front() // 获取链表第一个元素
				//fmt.Println(e1.Value) // 输出第一个元素

				region, _ := ip2region(e1.Value.(net.IP).String())

				log.Printf("当前 Ipset 链 %s %d\n", SIG_NAME, func() int {
					_len, _err := NumIPSet(SIG_NAME)
					if _err == nil {
						return _len
					}
					return 0
				}())

				if !strings.Contains(region, "中国") && !strings.Contains(region, "内网") {
					if position, err := curl_(e1.Value.(net.IP).String()); err != nil { //判断地域
						log.Printf("获取Ip地域出错: %v", err)
					} else {
						log.Printf("curl_ %s 位置 %s\n", e1.Value.(net.IP).String(), position) // 打印地域
						AddIPSet(SIG_NAME, e1.Value.(net.IP).String())                       // 添加 Ip 到 ipset 集合

						ipList.Remove(e1) // 移除第一个元素
					}
				} else { // 这时是国内地址
					ipList.Remove(e1)
				}

				log.Printf("Ip 链表长度:%d\n", ipList.Len()) // 链表长度
				time.Sleep(3 * time.Second)
			}
			ipMutex.Unlock() // 链表解锁互斥锁

		}

	}()

	// 启动防火墙管理
	go func() {

		for {

			if ipset_len, _ := NumIPSet(SIG_NAME); ipset_len >= 65534 {
				log.Printf("ipset %s 列表已满 %dd\n", SIG_NAME, ipset_len)

				// 创建新的 ipset 集合
				SIG++

				if SIG >= MAX_SIG {
					log.Printf("已创建 %d 个集合!!!", MAX_SIG)
				}

				SIG_NAME = fmt.Sprintf("root%d", SIG)
				if return_value := IsIpset(SIG_NAME); return_value == 1 {
					createIPSet(SIG_NAME)
				}

			}

			time.Sleep(3 * time.Second)
		}
	}()

	// 等待信号并清理
	waitForSignalAndCleanUp(cmd)
}

func handleCmd() {
	// 定义命令行标志
	var instruction string
	var help bool
	interfaceName = flag.String("i", "", "指定要使用的网络接口")
	flag.BoolVar(&listInterfaces, "l", false, "列出可用的网络接口")
	filter = flag.String("f", "tcp", "指定 BPF 过滤器")
	outputFile = flag.String("o", "", "保存捕获数据的输出文件（可选）")
	flag.StringVar(&instruction, "s", "", "-s start 启动 Iptables 规则\n-s stop 停止 Iptables 规则")
	flag.BoolVar(&help, "h", false, "")
	flag.BoolVar(&help, "help", false, "帮助信息")
	flag.Parse()

	if help {
		fmt.Printf(
			"\t\tDenyip firewall\n" +
				"\tVersion 0.1\n" +
				"\tE-mail: aixiao@aixiao.me\n" +
				"\tDate: 20250102\n")

		flag.Usage()
		os.Exit(0)
	}

	if instruction != "" {
		switch instruction {
		case "start":
			fmt.Println("启动 Iptables 规则")
			for i := 0; i < MAX_SIG; i++ {
				_name := fmt.Sprintf("root%d", i)
				iptables_add(_name)
			}

			os.Exit(0)
		case "stop":
			fmt.Println("停止 Iptables 规则")
			for i := 0; i < MAX_SIG; i++ {
				_name := fmt.Sprintf("root%d", i)
				iptables_del(_name)
			}
			os.Exit(0)
		default:
			log.Fatalf("未知的操作: %s. 请使用 'start' 或 'stop'.", instruction)
		}
	}

	if listInterfaces {
		printAvailableInterfaces()
		os.Exit(0)
	}

	if *interfaceName == "" {
		log.Fatal("请使用 -i 标志指定网络接口，或者使用 -l 列出接口。")
	}
}

func main() {
	handleCmd()

	// 守护进程模式
	if *Daemon {
		startDaemon()
	}

	// 子进程逻辑
	if *child {
		runChildProcess()
		return
	}

	runMainProcess()

}
