commit d787bce15937e2b9f91c46bcd63956c1604563d8 Author: juneflbjpz Date: Fri Sep 13 23:27:03 2024 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ab68bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +lagran +.idea +.DS_Store +*.DS_Store diff --git a/InitParams.go b/InitParams.go new file mode 100644 index 0000000..149cde2 --- /dev/null +++ b/InitParams.go @@ -0,0 +1,49 @@ +package main + +import ( + "flag" +) + +var Port string +var SaEnable bool +var WindowSa uint16 +var AEnable bool +var WindowA uint16 +var PaEnable bool +var WindowPa uint16 +var FaEnable bool +var WindowFa uint16 +var Debug bool +var Daemon bool +var Forever bool + +func InitParams() (string, bool, uint16, bool, uint16, bool, uint16, bool, uint16, bool, bool, bool) { + flag.StringVar(&Port, "p", "443", "The port of geneva, multi ports should be like \"80,443\"") + + flag.BoolVar(&SaEnable, "sa", true, "Enable to handle the packet when TCP flag SYN and ACK are 1.") + var wsa int + flag.IntVar(&wsa, "wsa", 4, "The window size of packet when TCP flag SYN and ACK are 1, available only when param -sa is true") + + flag.BoolVar(&AEnable, "a", true, "Enable to handle the packet when TCP flag ACK is 1") + var wa int + flag.IntVar(&wa, "wa", 4, "The window size of packet when TCP flag ACK is 1, available only when param -a is true") + + flag.BoolVar(&PaEnable, "pa", true, "Enable to handle the packet when TCP flag PSH and ACK are 1.") + var wpa int + flag.IntVar(&wpa, "wpa", 4, "The window size of packet when TCP flag PSH and ACK are 1, available only when param -pa is true") + + flag.BoolVar(&FaEnable, "fa", true, "Enable to handle the packet when TCP flag FIN and ACK are 1.") + var wfa int + flag.IntVar(&wfa, "wfa", 4, "The window size of packet when TCP flag FIN and ACK are 1, available only when param -fa is true") + + flag.BoolVar(&Debug, "debug", false, "Debug mode.") + flag.BoolVar(&Daemon, "daemon", false, "Run in daemon") + flag.BoolVar(&Forever, "forever", false, "Run forever") + + flag.Parse() + WindowSa = uint16(wsa) + WindowA = uint16(wa) + WindowPa = uint16(wpa) + WindowFa = uint16(wfa) + return Port, SaEnable, WindowSa, AEnable, WindowA, PaEnable, WindowPa, FaEnable, WindowFa, Debug, Daemon, Forever +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..f15cb88 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +- 本小程序主要用来实现Geneva的以下四条规则,还可以自定义端口、需要修改的window size的值。 +``` +"[TCP:flags:SA]-tamper{TCP:window:replace:0}-|" +"[TCP:flags:A]-tamper{TCP:window:replace:0}-|" +"[TCP:flags:PA]-tamper{TCP:window:replace:0}-|" +"[TCP:flags:FA]-tamper{TCP:window:replace:0}-|" +``` +- 默认四条规则全部开启,具体使用方法参考`./lagran -h`。 +- 例如:开启第一条规则并设置window为2,同时关闭2、3、4条规则 +```./lagran -debug -p 80 -sa=true -wsa 2 -a=false -pa=false -fa=false``` +- 注意:本小程序依赖libpcap-dev、libnetfilter-queue-dev、iptables等使用之前请先安装。 \ No newline at end of file diff --git a/common.go b/common.go new file mode 100644 index 0000000..7c9c8cc --- /dev/null +++ b/common.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "strconv" +) + +func getProcessOwner() string { + stdout, err := exec.Command("ps", "-o", "user=", "-p", strconv.Itoa(os.Getpid())).Output() + if err != nil { + log.Fatalln(err) + } + return string(stdout) +} + +func StripSlice(slice []string, element string) []string { + for i := 0; i < len(slice); { + if slice[i] == element && i != len(slice)-1 { + slice = append(slice[:i], slice[i+1:]...) + } else if slice[i] == element && i == len(slice)-1 { + slice = slice[:i] + } else { + i++ + } + } + return slice +} + +func SubProcess(args []string) *exec.Cmd { + cmd := exec.Command(args[0], args[1:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Start() + if err != nil { + fmt.Fprintf(os.Stderr, "[-] Error: %s\n", err) + } + return cmd +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..aa2da59 --- /dev/null +++ b/go.mod @@ -0,0 +1,21 @@ +module lagran + +go 1.18 + +require ( + github.com/coreos/go-iptables v0.6.0 + github.com/florianl/go-nfqueue v1.3.1 + github.com/google/gopacket v1.1.19 + github.com/panjf2000/ants/v2 v2.5.0 +) + +require ( + github.com/google/go-cmp v0.5.7 // indirect + github.com/josharian/native v1.0.0 // indirect + github.com/mdlayher/netlink v1.6.0 // indirect + github.com/mdlayher/socket v0.1.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7bc05e2 --- /dev/null +++ b/go.sum @@ -0,0 +1,55 @@ +github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= +github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/florianl/go-nfqueue v1.3.1 h1:khQ9fYCrjbu5CF8dZF55G2RTIEIQRI0Aj5k3msJR6Gw= +github.com/florianl/go-nfqueue v1.3.1/go.mod h1:aHWbgkhryJxF5XxYvJ3oRZpdD4JP74Zu/hP1zuhja+M= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= +github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0= +github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= +github.com/mdlayher/socket v0.1.1 h1:q3uOGirUPfAV2MUoaC7BavjQ154J7+JOkTWyiV+intI= +github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= +github.com/panjf2000/ants/v2 v2.5.0 h1:1rWGWSnxCsQBga+nQbA4/iY6VMeNoOIAM0ZWh9u3q2Q= +github.com/panjf2000/ants/v2 v2.5.0/go.mod h1:cU93usDlihJZ5CfRGNDYsiBYvoilLvBF5Qp/BT2GNRE= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= diff --git a/iptables.go b/iptables.go new file mode 100644 index 0000000..1fad47a --- /dev/null +++ b/iptables.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "github.com/coreos/go-iptables/iptables" + "os" +) + +func SetIptable(sport string) { + ipt, err := iptables.New() + if err != nil { + fmt.Printf("Iptabels new error:%v", err) + os.Exit(1) + } + _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "SYN,ACK", "-j", "NFQUEUE", "--queue-balance", "1000:1127") + _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "ACK", "-j", "NFQUEUE", "--queue-balance", "2000:2127") + _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "PSH,ACK", "-j", "NFQUEUE", "--queue-balance", "3000:3127") + _ = ipt.AppendUnique("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "FIN,ACK", "-j", "NFQUEUE", "--queue-balance", "4000:4127") +} +func UnsetIptable(sport string) { + ipt, err := iptables.New() + if err != nil { + fmt.Printf("Iptabels new error:%v", err) + os.Exit(1) + } + _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "SYN,ACK", "-j", "NFQUEUE", "--queue-balance", "1000:1127") + _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "ACK", "-j", "NFQUEUE", "--queue-balance", "2000:2127") + _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "PSH,ACK", "-j", "NFQUEUE", "--queue-balance", "3000:3127") + _ = ipt.Delete("filter", "OUTPUT", "-p", "tcp", "-m", "multiport", "--sport", sport, "--tcp-flags", "SYN,RST,ACK,FIN,PSH", "FIN,ACK", "-j", "NFQUEUE", "--queue-balance", "4000:4127") +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..b5de4b3 --- /dev/null +++ b/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "fmt" + "github.com/panjf2000/ants/v2" + "io/ioutil" + "log" + "os" + "sync" +) + +const ( + DAEMON = "daemon" + FOREVER = "forever" +) + +func init() { + if getProcessOwner() != "root\n" { + log.Fatalln("Please run this program with root.") + } +} + +func main() { + InitParams() + if !Debug { + log.SetOutput(ioutil.Discard) + } + if Daemon { + SubProcess(StripSlice(os.Args, "-"+DAEMON)) + fmt.Printf("[*] Daemon running in PID: %d PPID: %d\n", os.Getpid(), os.Getppid()) + os.Exit(0) + } else if Forever { + for { + cmd := SubProcess(StripSlice(os.Args, "-"+FOREVER)) + fmt.Printf("[*] Forever running in PID: %d PPID: %d\n", os.Getpid(), os.Getppid()) + cmd.Wait() + } + os.Exit(0) + } else { + UnsetIptable(Port) + SetIptable(Port) + var wg sync.WaitGroup + p1, _ := ants.NewPoolWithFunc(512, func(i interface{}) { + packetHandle(i.(int)) + wg.Done() + }) + defer p1.Release() + // Submit tasks one by one. + log.Println("Starting Task p1") + for i := 1000; i < 1512; i++ { + wg.Add(1) + _ = p1.Invoke(int(i)) + } + p2, _ := ants.NewPoolWithFunc(1512, func(i interface{}) { + packetHandle(i.(int)) + wg.Done() + }) + defer p2.Release() + // Submit tasks one by one. + log.Println("Starting Task p2") + for i := 2000; i < 2512; i++ { + wg.Add(1) + _ = p2.Invoke(int(i)) + } + p3, _ := ants.NewPoolWithFunc(512, func(i interface{}) { + packetHandle(i.(int)) + wg.Done() + }) + defer p3.Release() + // Submit tasks one by one. + log.Println("Starting Task p3") + for i := 3000; i < 3512; i++ { + wg.Add(1) + _ = p3.Invoke(int(i)) + } + p4, _ := ants.NewPoolWithFunc(512, func(i interface{}) { + packetHandle(i.(int)) + wg.Done() + }) + defer p4.Release() + // Submit tasks one by one. + log.Println("Starting Task p4") + for i := 4000; i < 4512; i++ { + wg.Add(1) + _ = p4.Invoke(int(i)) + } + wg.Wait() + } +} diff --git a/packet.go b/packet.go new file mode 100644 index 0000000..d85d124 --- /dev/null +++ b/packet.go @@ -0,0 +1,140 @@ +package main + +import ( + "context" + "fmt" + "github.com/florianl/go-nfqueue" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "log" + "net" + "regexp" + "strings" + "time" +) + +func packetHandle(queueNum int) { + config := nfqueue.Config{ + NfQueue: uint16(queueNum), + MaxPacketLen: 0xFFFF, + MaxQueueLen: 0xFF, + Copymode: nfqueue.NfQnlCopyPacket, + WriteTimeout: 200 * time.Millisecond, + } + + nf, err := nfqueue.Open(&config) + if err != nil { + fmt.Println("could not open nfqueue socket:", err) + return + } + + defer nf.Close() + + ctx, cancelFunc := context.WithCancel(context.Background()) + defer cancelFunc() + + fn := func(a nfqueue.Attribute) int { + id := *a.PacketID + var srcIP net.IP + var dstIP net.IP + log.Printf("PKT[%03d]\t\n", id) + + packet := gopacket.NewPacket(*a.Payload, layers.LayerTypeIPv4, gopacket.Default) + + // Get the IP layer from this packet + if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer != nil { + // Get actual IP data from this layer + ip, _ := ipLayer.(*layers.IPv4) + srcIP = ip.SrcIP + dstIP = ip.DstIP + log.Printf("%15s > %-15s \n", srcIP, dstIP) + } + if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil { + tcp, _ := tcpLayer.(*layers.TCP) + ports := strings.Split(Port, ",") + reg := regexp.MustCompile(`\d+`) + sport := reg.FindString(tcp.SrcPort.String()) + var matchedPort bool = false + + for _, port := range ports { + if port == sport { + matchedPort = true + break + } + } + if matchedPort { + var ok1 bool = SaEnable && tcp.SYN && tcp.ACK + var ok2 bool = AEnable && tcp.ACK && !tcp.PSH && !tcp.FIN && !tcp.SYN && !tcp.RST + var ok3 bool = PaEnable && tcp.PSH && tcp.ACK + var ok4 bool = FaEnable && tcp.FIN && tcp.ACK + var windowSize uint16 + if ok1 || ok2 || ok3 || ok4 { + if ok1 { + windowSize = WindowSa + log.Println("Handle SYN=1 and ACK=1") + } + if ok2 { + windowSize = WindowA + log.Println("Handle ACK=1") + } + if ok3 { + windowSize = WindowPa + log.Println("Handle PSH=1 and ACK=1") + } + if ok4 { + windowSize = WindowFa + log.Println("Handle FIN=1 and ACK=1") + } + packet.TransportLayer().(*layers.TCP).Window = windowSize + err := packet.TransportLayer().(*layers.TCP).SetNetworkLayerForChecksum(packet.NetworkLayer()) + if err != nil { + log.Fatalf("SetNetworkLayerForChecksum error: %v", err) + } + buffer := gopacket.NewSerializeBuffer() + options := gopacket.SerializeOptions{ + ComputeChecksums: true, + FixLengths: true, + } + if err := gopacket.SerializePacket(buffer, options, packet); err != nil { + log.Fatalf("SerializePacket error: %v", err) + } + packetBytes := buffer.Bytes() + log.Printf("Set TCP window size to %d", windowSize) + err = nf.SetVerdictModPacket(id, nfqueue.NfAccept, packetBytes) + if err != nil { + log.Fatalf("SetVerdictModified error: %v", err) + } + return 0 + } + err := nf.SetVerdict(id, nfqueue.NfAccept) + if err != nil { + log.Fatalf("SetVerdictModified error: %v", err) + } + return 0 + } + err := nf.SetVerdict(id, nfqueue.NfAccept) + if err != nil { + log.Fatalf("SetVerdictModified error: %v", err) + } + return 0 + } + err := nf.SetVerdict(id, nfqueue.NfAccept) + if err != nil { + log.Fatalf("SetVerdictModified error: %v", err) + } + return 0 + } + + // Register your function to listen on nflqueue queue 100 + err = nf.RegisterWithErrorFunc(ctx, fn, func(e error) int { + if e != nil { + log.Fatalln("RegisterWithErrorFunc Error:", e) + } + return 0 + }) + if err != nil { + fmt.Println(err) + return + } + <-ctx.Done() +}