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()
}
In case you are interested in the solution, code can be found here: https://github.com/kung-foo/freki
Related
I developed an example that uses udp multicast to send and receive data,it work at linux but not wort at window10.
I try to developed another udp multicast application by Java, it works in the same environment!
Where is the problem?
Golang code:
package main
import (
"flag"
"fmt"
"net"
"strings"
)
var (
bind = flag.String("bind", "239.255.0.0", "bind")
port = flag.Int("port", 2222, "port")
cmd = flag.String("cmd", "server", "Command")
)
func main() {
flag.Parse()
addr, err := net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%d", *bind, *port))
if err != nil {
panic(err)
}
switch *cmd {
case "server":
{
startServer(addr)
}
case "client":
{
startClient(addr, strings.Join(flag.Args(), ""))
}
}
}
func startServer(addr *net.UDPAddr) {
conn, err := net.ListenMulticastUDP("udp4", nil, addr)
if err != nil {
panic(err)
} else {
fmt.Println("Server was started")
}
var buff = make([]byte, 1600)
for {
l, remoteAddr, err := conn.ReadFromUDP(buff)
if err != nil {
panic(err)
}
fmt.Printf("read data from %v, data: %s\n", remoteAddr, string(buff[0:l]))
}
}
func startClient(addr *net.UDPAddr, msg string) {
conn, err := net.DialUDP("udp4", nil, addr)
if err != nil {
panic(err)
}
l, err := conn.Write([]byte(msg))
if err != nil {
panic(err)
} else {
fmt.Printf("Wrote byte length %d\n", l)
}
conn.Close()
}
Eureka!
The problem was caused by "The Winsock version of the IP_MULTICAST_LOOP option is semantically different than the UNIX version of the IP_MULTICAST_LOOP option":
In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path.
https://learn.microsoft.com/en-us/windows/win32/winsock/ip-multicast-2
How to set IP_MULTICAST_LOOP on multicast UDPConn in Golang
so I am hosting a TCP server through GoLang and then I want to connect to my TCP server using multiple TCP clients and measure the RTT every time a new client is connected. I haven't found anything that allows me to measure RTT to connect to this server in Golang (like do I connect to localhost, it doesn't work) Below is my code for the TCP server.
package main
import (
"bufio"
"fmt"
"log"
"math/rand"
"net"
"os"
"strconv"
"strings"
"time"
)
var counter int
const MIN = 1
const MAX = 100
func random() int {
return rand.Intn(MAX-MIN) + MIN
}
func verifyPortNo(portNo string) bool {
conn, err := net.Listen("tcp", portNo)
if err != nil {
log.Println("Connection error: ", err)
log.Println("Cannot verify port")
return false
}
log.Println("Available")
conn.Close()
return true
}
func handleConnection(con net.Conn, counter int) {
fmt.Printf("Client %d: %s\n", counter, con.LocalAddr().String())
defer con.Close()
for {
clientRequest, err := bufio.NewReader(con).ReadString('\n')
if err != nil {
fmt.Println(err)
return
}
stop := strings.TrimSpace(clientRequest)
if stop == "STOP" {
break
}
result := strconv.Itoa(random()) + "\n"
con.Write([]byte(string(result)))
}
}
func main() {
arguments := os.Args //first element of the argument array is the program name
if len(arguments) == 1 {
fmt.Println("Please provide a port number")
return
}
PortNo := "localhost:" + arguments[1]
fmt.Println(PortNo)
if !verifyPortNo(PortNo) {
return
}
n, err := net.Listen("tcp", PortNo)
if err != nil {
fmt.Println(err)
return
}
//close the listener when the application closes
defer n.Close()
rand.Seed(time.Now().Unix())
for {
//while loop for TCP server to accept connections
conn, err := n.Accept()
if err != nil {
fmt.Println(err)
return
}
counter++
go handleConnection(conn, counter)
}
}
Below is my code for the TCP clients.
package main
import (
"bufio"
"log"
"net"
"os"
"strings"
"time"
)
var counter int
func main() {
for {
go createTCPClient()
time.Sleep(1 * time.Second)
}
// log.Println("Available")
//netstat -anp TCP | grep 9999
}
func createTCPClient() {
PortNo := "localhost:" + os.Args[1]
conn, err := net.Dial("tcp", PortNo)
if err != nil {
log.Println("Connection error: ", err)
log.Println("Cannot verify port")
return
}
defer conn.Close()
serverReader := bufio.NewReader(conn)
for {
reply, err := serverReader.ReadString('\n')
if err != nil {
println("Write to server failed:", err.Error())
os.Exit(1)
}
println("reply from server=", strings.TrimSpace(reply))
}
}
The code works (see figure below) but I cannot wrap my head around measuring the RTT for each TCP client and displaying it.
enter image description here
The only portable solution is using/designing an application protocol that lets you determine the RTT. Eg, time the difference between a request/response.
Alternatively, OS kernels often record the TCP connection latency. However:
there isn't a portable way to retrieve TCP RTT
TCP RTT isn't available on all platforms.
This cut-down example demonstrates reading the TCPInfo containing the TCP RTT under Linux:
//go:build linux
package main
import (
"fmt"
"net"
"time"
"golang.org/x/sys/unix"
)
func main() {
listener, err := net.Listen("tcp", ":0")
check(err)
fmt.Println("Listening on", listener.Addr())
for {
conn, err := listener.Accept()
check(err)
go func(conn *net.TCPConn) {
defer conn.Close()
info, err := tcpInfo(conn)
check(err)
rtt := time.Duration(info.Rtt) * time.Microsecond
fmt.Println(rtt)
}(conn.(*net.TCPConn))
}
}
func tcpInfo(conn *net.TCPConn) (*unix.TCPInfo, error) {
raw, err := conn.SyscallConn()
if err != nil {
return nil, err
}
var info *unix.TCPInfo
ctrlErr := raw.Control(func(fd uintptr) {
info, err = unix.GetsockoptTCPInfo(int(fd), unix.IPPROTO_TCP, unix.TCP_INFO)
})
switch {
case ctrlErr != nil:
return nil, ctrlErr
case err != nil:
return nil, err
}
return info, nil
}
func check(err error) {
if err != nil {
panic(err)
}
}
Example output for connections over localhost:
$ ./tcpinfo
Listening on [::]:34761
97µs
69µs
103µs
60µs
92µs
As a beginner in go and programming in general, I've been coding a port scanner in go with gopacket library and most of the code is done, but I've been running into a problem of spawning too many goroutines and getting 'read ip4 0.0.0.0: i/o timeout' I've done some research and it seems I need to implement a worker pool I've been trying to implement this example 'https://gobyexample.com/worker-pools' as I'm still learning goroutines and channels I've been at it a few days now and can't seem to figure out how to implement the above example correctly in my program can you guys give me some pointers or preferably a code fix example.
package main
import (
"fmt"
"log"
"net"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
// Get preferred outbound ip and port of this machine
func GetOutboundIPPort() (net.IP, int) {
conn, err := net.Dial("udp", "1.1.1.1:80")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP, localAddr.Port
}
func ipv4_gen(out chan net.IP) {
ip, ipnet, err := net.ParseCIDR("192.168.0.0/24")
if err != nil {
log.Fatal(err)
}
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
time.Sleep(300 * time.Millisecond)
dstaddrs, err := net.LookupIP(ip.String())
if err != nil {
log.Fatal(err)
}
dstip := dstaddrs[0].To4()
out <- dstip
}
close(out)
}
func inc(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
func port_scanner(dstip net.IP) {
dstport := layers.TCPPort(80)
srcip, port := GetOutboundIPPort()
srcport := layers.TCPPort(port)
ip := &layers.IPv4{
SrcIP: srcip,
DstIP: dstip,
Protocol: layers.IPProtocolTCP,
}
tcp := &layers.TCP{
SrcPort: srcport,
DstPort: dstport,
Seq: 1105024978,
SYN: true,
Window: 14600,
}
tcp.SetNetworkLayerForChecksum(ip)
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
if err := gopacket.SerializeLayers(buf, opts, tcp); err != nil {
log.Fatal(err)
}
conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if _, err := conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}); err != nil {
log.Fatal(err)
}
// Set deadline so we don't wait forever.
if err := conn.SetDeadline(time.Now().Add(10 * time.Second)); err != nil {
log.Fatal(err)
}
for {
b := make([]byte, 4096)
n, addr, err := conn.ReadFrom(b)
if err != nil {
log.Println("error reading packet: ", err)
return
} else if addr.String() == dstip.String() {
// Decode a packet
packet := gopacket.NewPacket(b[:n], layers.LayerTypeTCP, gopacket.Default)
// Get the TCP layer from this packet
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.TCP)
if tcp.DstPort == srcport {
if tcp.SYN && tcp.ACK {
fmt.Printf("Discovered open port %d/tcp on %s\n", dstport, dstip)
}
return
}
}
}
}
}
func worker(id int, ips <-chan net.IP) {
for ip := range ips {
go port_scanner(ip)
}
}
func main() {
ips := make(chan net.IP)
go ipv4_gen(ips)
for w := 1; w <= 10; w++ {
go worker(w, ips)
}
}
You are starting a new goroutine for each piece of work inside the worker so it defeats its purpose.
You need to run the work instead of starting a goroutine inside the worker.
On the client, I want to set the UDP source port when sending a udp packet.
On the server, I want to know what the UDP source port was received on.
Client:
package main
import (
"net"
)
func main() {
s, err := net.ResolveUDPAddr("udp4", "127.0.0.1:1234")
c, err := net.DialUDP("udp4", nil, s)
if err != nil {
fmt.Println(err)
return
}
}
Server:
package main
import (
"net"
"time"
)
func main() {
s, err := net.ResolveUDPAddr("udp4", "127.0.0.1:1234")
if err != nil {
fmt.Println(err)
return
}
connection, err := net.ListenUDP("udp4", s)
if err != nil {
fmt.Println(err)
return
}
}
In the above client code, is there a way for me to set the source port?
In the above server code, is there a way for me to know the source port used?
https://golang.org/pkg/net/#DialUDP
func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error)
Both laddr and raddr use UDPAddr struct, but you're not setting laddr.
laddr, err := net.ResolveUDPAddr("udp", "<source_int>:50000")
raddr := net.UDPAddr{IP: net.ParseIP("<dest>"), Port: 50000}
conn, err := net.DialUDP("udp", laddr, &raddr)
I'm trying to realize how works a following code made by kdar:
package main
import (
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"log"
"net"
"os"
"strconv"
"time"
)
// get the local ip and port based on our destination ip
func localIPPort(dstip net.IP) (net.IP, int) {
serverAddr, err := net.ResolveUDPAddr("udp", dstip.String()+":12345")
if err != nil {
log.Fatal(err)
}
// We don't actually connect to anything, but we can determine
// based on our destination ip what source ip we should use.
if con, err := net.DialUDP("udp", nil, serverAddr); err == nil {
if udpaddr, ok := con.LocalAddr().(*net.UDPAddr); ok {
return udpaddr.IP, udpaddr.Port
}
}
log.Fatal("could not get local ip: " + err.Error())
return nil, -1
}
func main() {
if len(os.Args) != 3 {
log.Printf("Usage: %s <host/ip> <port>\n", os.Args[0])
os.Exit(-1)
}
log.Println("starting")
dstaddrs, err := net.LookupIP(os.Args[1])
if err != nil {
log.Fatal(err)
}
// parse the destination host and port from the command line os.Args
dstip := dstaddrs[0].To4()
var dstport layers.TCPPort
if d, err := strconv.ParseInt(os.Args[2], 10, 16); err != nil {
log.Fatal(err)
} else {
dstport = layers.TCPPort(d)
}
srcip, sport := localIPPort(dstip)
srcport := layers.TCPPort(sport)
log.Printf("using srcip: %v", srcip.String())
// Our IP header... not used, but necessary for TCP checksumming.
ip := &layers.IPv4{
SrcIP: srcip,
DstIP: dstip,
Protocol: layers.IPProtocolTCP,
}
// Our TCP header
tcp := &layers.TCP{
SrcPort: srcport,
DstPort: dstport,
Seq: 1105024978,
SYN: true,
Window: 14600,
}
tcp.SetNetworkLayerForChecksum(ip)
// Serialize. Note: we only serialize the TCP layer, because the
// socket we get with net.ListenPacket wraps our data in IPv4 packets
// already. We do still need the IP layer to compute checksums
// correctly, though.
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
if err := gopacket.SerializeLayers(buf, opts, tcp); err != nil {
log.Fatal(err)
}
conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
log.Fatal(err)
}
log.Println("writing request")
if _, err := conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}); err != nil {
log.Fatal(err)
}
// Set deadline so we don't wait forever.
if err := conn.SetDeadline(time.Now().Add(10 * time.Second)); err != nil {
log.Fatal(err)
}
for {
b := make([]byte, 4096)
log.Println("reading from conn")
n, addr, err := conn.ReadFrom(b)
if err != nil {
log.Println("error reading packet: ", err)
return
} else if addr.String() == dstip.String() {
// Decode a packet
packet := gopacket.NewPacket(b[:n], layers.LayerTypeTCP, gopacket.Default)
// Get the TCP layer from this packet
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.TCP)
if tcp.DstPort == srcport {
if tcp.SYN && tcp.ACK {
log.Printf("Port %d is OPEN\n", dstport)
} else {
log.Printf("Port %d is CLOSED\n", dstport)
}
return
}
}
} else {
log.Printf("Got packet not matching addr")
}
}
}
If i understand right, that code sends a raw TCP packet with SYN-flag to a server and waits for response. Using wireshark I found out that after receiving a response (SYN-ACK) from a server, the client sends a packet with RST flag. I can't understand, which piece of code is responsible for sending a TCP packet with RST-flag.