chifflier / nfqueue-go

Go bindings for NFQueue
GNU General Public License v2.0
51 stars 21 forks source link

BUG: Raw Sockets And NFQUEUE in The Same Process Block Each Other #11

Closed ilyaigpetrov closed 6 years ago

ilyaigpetrov commented 6 years ago

With lines commented ReadMsgIP works, uncommenting those lines make it block.

on.bash

#sudo iptables -t nat -D OUTPUT -p tcp -m tcp --dport 80 -j NFQUEUE --queue-num 13 -m owner ! --gid-owner proxyclient
sudo iptables -t nat -D OUTPUT -p tcp -m tcp --dport 80 -j REDIRECT
#sudo iptables -t nat -A OUTPUT -p tcp -m tcp --dport 80 -j NFQUEUE --queue-num 13 -m owner ! --gid-owner proxyclient
sudo iptables -t nat -A OUTPUT -p tcp -m tcp --dport 80 -j REDIRECT

test.go

package main

import (
  "github.com/chifflier/nfqueue-go/nfqueue"
  "syscall"
  "net"
  "fmt"
  "log"
  "math"
)

func handleQueue(payload *nfqueue.Payload) int {

  payload.SetVerdict(nfqueue.NF_ACCEPT)
  return nfqueue.NF_ACCEPT // Must return verdict

}

func createInputQueue() {

  q := new(nfqueue.Queue)

  q.SetCallback(handleQueue)

  q.Init()

  q.Unbind(syscall.AF_INET)
  q.Bind(syscall.AF_INET)

  q.CreateQueue(13)

  q.Loop()
  q.DestroyQueue()
  q.Close()

}

func main() {

  ipConn, err := net.ListenIP("ip:tcp", &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)})
  if err != nil {
    fmt.Println("Try running under root rights.")
    log.Fatal(err)
  }
  log.Println("Listening!")

  maxIPPacketSize := math.MaxUint16
  fmt.Println("BEFORE LOOP")
  go func(){
    for {
      ipBuf := make([]byte, maxIPPacketSize)
      oob := make([]byte, maxIPPacketSize)
      fmt.Println("Blocking on read MSG")
      /*n*/_, _, _, _, err := ipConn.ReadMsgIP(ipBuf, oob)
      if err != nil {
        log.Println(err)
        continue
      }
      fmt.Println("UNBLOCKED")
      // packetData := ipBuf[:n]
    }
  }()

  createInputQueue()

}

off.bash

source <(head -2 on.bash)

start.bash

sudo groupadd proxyclient
sudo -g proxyclient ./test

Instructions

  1. go build test.go, start it with sudo ./start.bash
  2. ./on.bash
  3. Check that UNBLOCKED is printed to output while loading http://time.com
  4. ./off.bash
  5. Restart test.go
  6. ./on.bash
  7. See UNBLOCKED is never printed no matter if you load http://time.com or not
  8. ./off.bash

Why

Maybe because NF_ACCEPT verdict presumes all next rules in the chain are skipped?

ilyaigpetrov commented 6 years ago

Not a bug, well defined behavior.