9

I'm currently playing around with reading packages from nfqueue and modifying them.Unfortunately, I'm a bit stuck at changing the destination port of a package. See the code snippet below. Idea is to rewrite dest port 8888 to 8000. I do see the modified package going out from the queue, but if I want to connect to an HTTP server listening on port 8000 by connecting to port 8888, the connection times out. I assume something mal-formed in the package.

package main

import (
    "os"
    "os/signal"
    "syscall"

    "github.com/chifflier/nfqueue-go/nfqueue"
    "github.com/coreos/go-iptables/iptables"

    "github.com/google/gopacket"
    "github.com/google/gopacket/layers"
)

func sendNewPacket(payload *nfqueue.Payload, layers ...gopacket.SerializableLayer) {
    buffer := gopacket.NewSerializeBuffer()
    gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}, layers...)
    outgoingPacket := buffer.Bytes()
    payload.SetVerdictModified(nfqueue.NF_ACCEPT, outgoingPacket)
}

func realCallback(payload *nfqueue.Payload) int {
    packet := gopacket.NewPacket(payload.Data, layers.LayerTypeIPv4, gopacket.Default)
    ethLayer := packet.Layer(layers.LayerTypeEthernet)
    eth, _ := ethLayer.(*layers.Ethernet)
    if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer != nil {
        ip, _ := ipLayer.(*layers.IPv4)
        if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
            tcp, _ := tcpLayer.(*layers.TCP)
            if tcp.DstPort == 8888 {
                tcp.DstPort = 8000
                sendNewPacket(payload, eth, ip, tcp)
                return 0
            }
            if tcp.SrcPort == 8000 {
                tcp.SrcPort = 8888
                sendNewPacket(payload, eth, ip, tcp)
                return 0
            }
        }
    }
    payload.SetVerdict(nfqueue.NF_ACCEPT)
    return 0
}

func main() {
    ipt, err := iptables.New()
    if err != nil {
        panic(err)
    }
    ipt.Append("filter", "INPUT", "-p", "tcp", "-j", "NFQUEUE", "--queue-num", "0")
    ipt.Append("filter", "OUTPUT", "-p", "tcp", "-j", "NFQUEUE", "--queue-num", "0")
    q := new(nfqueue.Queue)
    q.SetCallback(realCallback)

    q.Init()
    defer q.Close()

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

    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)
    go func() {
        for sig := range c {
            _ = sig
            q.Close()
            err = ipt.ClearChain("filter", "INPUT")
            err = ipt.ClearChain("filter", "OUTPUT")
            if err != nil {
                panic(err)
            }
            os.Exit(0)
        }
    }()
    q.TryRun()
}
Srivishnu
  • 759
  • 1
  • 6
  • 15
Glaslos
  • 2,872
  • 1
  • 21
  • 31
  • If you see the modified packet going out again, what is your issue/question ? – nos Dec 16 '16 at 11:33
  • Sorry, I will clarify this in the question. I'm running a HTTP server on port 8000. If I connect from the browser to port 8888, the connection times out. – Glaslos Dec 16 '16 at 11:41
  • You have to rewrite the packets going in the other direction too. (Note that you don't need any code to really do this, you can do it with iptables as show e.g. [here](https://www.cyberciti.biz/faq/linux-port-redirection-with-iptables/) – nos Dec 16 '16 at 11:42
  • So changing the src port on the response from 8000 to 8888? – Glaslos Dec 16 '16 at 11:44
  • Yes. But not for INPUT packets, you need to somehow hook into the packets going out, and the source port on those. – nos Dec 16 '16 at 11:46
  • Sure, I can add an iptables rule to also queue messages going out. – Glaslos Dec 16 '16 at 11:49
  • Actually I never see the request arriving at the HTTP server. – Glaslos Dec 16 '16 at 11:52

1 Answers1

0

In case you are interested in the solution, code can be found here: https://github.com/kung-foo/freki

Glaslos
  • 2,872
  • 1
  • 21
  • 31