Encapsulating all traffic with a GRE header - go

Summary
I am attempting to GRE encapsulate all traffic from server1 to server2 and I am testing this by pinging the IP address 10.1.1.1 on server2. I have also set up tcpdump on server2 to verify that the traffic is indeed being encapsulated.
However, I am observing the same behavior(I'm able to ping) before and after running the binary, which it is that the traffic is not being encapsulated.
Diagram
Server1<-.3-------->172.16.241.0<---.2-->Server2
I'm running the go code in Server1 and I'm running a ping on server1
code:
package main
import (
"log"
"net"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
func main() {
// Open a network interface in promiscuous mode
handle, err := pcap.OpenLive("eth0", 65535, true, pcap.BlockForever)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
// Set a capture filter that drops all packets
err = handle.SetBPFFilter("ip")
if err != nil {
log.Fatal(err)
}
// Start capturing packets
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
// Check if the packet is an IPv4 packet
ipv4Layer := packet.Layer(layers.LayerTypeIPv4)
if ipv4Layer != nil {
ipv4 := ipv4Layer.(*layers.IPv4)
// Extract the Ethernet layer from the received packet
ethLayer := packet.Layer(layers.LayerTypeEthernet)
if ethLayer == nil {
log.Printf("Error extracting Ethernet layer")
continue
}
eth := ethLayer.(*layers.Ethernet)
greLayer := &layers.GRE{
Protocol: layers.EthernetTypeIPv4,
}
newIpv4 := &layers.IPv4{
Version: 4,
SrcIP: net.IP{192, 168, 1, 1},
DstIP: net.IP{192, 168, 1, 2},
Protocol: layers.IPProtocolGRE,
Flags: layers.IPv4DontFragment,
TTL: 64,
Id: 33852,
IHL: 5,
}
// Update the checksums
options := gopacket.SerializeOptions{
ComputeChecksums: true,
}
buf := gopacket.NewSerializeBuffer()
err := gopacket.SerializeLayers(buf, options,
eth,
greLayer,
newIpv4,
ipv4,
gopacket.Payload(ipv4.BaseLayer.LayerPayload()),
)
if err != nil {
log.Printf("Error serializing layers: %v", err)
}
// Send the modified packet
err = handle.WritePacketData(buf.Bytes())
if err != nil {
log.Printf("Error sending packet: %v", err)
}
}
}
}
It looks like the ping is not being captured.

Related

Getting bind: address already in use even after closing the connection in golang

I am building a master/slave type system in golang. When the slave(called racer) is up, it pings master telling that it is up and ready to receive data and then it starts listening on a port. The port used for pinging and listening are same but I make sure I am closing the connection after pinging. My use case is to use same port for pinging and listening but I get bind: address already in use error when I use the same port to listen. Sometimes it works sometimes it doesn't. What I am doing wrong?
Complete Code
main.go
package main
import (
"flag"
"log"
"strconv"
"time"
"github.com/goku321/line-racer/master"
"github.com/goku321/line-racer/model"
"github.com/goku321/line-racer/racer"
)
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
nodeType := flag.String("nodeType", "master", "type of node: master/racer")
masterIP := flag.String("masterIP", "127.0.0.1", "ip address of master process")
racers := flag.Int("racers", 2, "number of racers")
racerID := flag.Int("racerID", 0, "unique racer id (0 <= id < number of racers")
laps := flag.Int("laps", 10, "number of lap")
ip := flag.String("ip", "127.0.0.1", "ip address of the node")
port := flag.String("port", "3000", "port to use")
flag.Parse()
_, err := strconv.ParseInt(*port, 10, 64)
if err != nil {
log.Fatalf("error parsing port number: %s", *port)
}
if *nodeType == "master" {
m := master.New(*ip, *port, *racers, *laps)
m.GenerateLaps()
go m.Listen()
m.WaitForRacers()
m.StartRace()
m.PrintLaps()
} else {
r := racer.New(*racerID, *ip, *port, *masterIP)
r.SignalMaster(&model.Message{Source: r.IPAddr + ":" + r.Port})
time.Sleep(time.Second*60)
r.ListenForNewLap()
}
}
racer.go(slave)
package racer
import (
"encoding/json"
"log"
"net"
"os"
"strconv"
"time"
"github.com/goku321/line-racer/model"
)
// Racer represents a racer
type Racer struct {
ID int
IPAddr string
Port string
Master string
Laps [][]model.Point
Status string
}
// SignalMaster sends a signal to master process
// with its coordinates
func (r *Racer) SignalMaster(m *model.Message) {
laddr, err := net.ResolveTCPAddr("tcp", r.IPAddr+":"+r.Port)
if err != nil {
log.Fatalf("error resolving tcp address: %s, reason: %v", r.IPAddr+":"+r.Port, err)
}
raddr, err := net.ResolveTCPAddr("tcp", r.Master+":3000")
if err != nil {
log.Fatalf("error resolving tcp address: %v", err)
}
for {
conn, err := net.DialTCP("tcp", laddr, raddr)
if err != nil {
log.Printf("connecting to master, %v", err)
time.Sleep(time.Second * 5)
} else {
m.Type = "ready"
m.Source = strconv.Itoa(r.ID)
m.Dest = r.Master + ":3000"
err := json.NewEncoder(conn).Encode(&m)
if err != nil {
log.Fatalf("error communicating to master: %v", err)
}
if err = conn.Close(); err != nil {
log.Fatal("unable to close connection")
}
break
}
}
}
// ListenForNewLap waits for master to get new coordinates
func (r *Racer) ListenForNewLap() {
ln, err := net.Listen("tcp", ":"+r.Port)
if err != nil {
log.Fatalf("racer %d: %v - %v", r.ID, err, time.Now())
}
log.Printf("racer %d: listening on %s:%s", r.ID, r.IPAddr, r.Port)
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
go handleConnection(conn, r)
}
}
func handleConnection(conn net.Conn, r *Racer) {
log.Printf("racer %d: new lap from master", r.ID)
var msg model.Message
err := json.NewDecoder(conn).Decode(&msg)
if err != nil {
log.Printf("racer %d: %v", r.ID, err)
}
// close connection here as message has already been received
conn.Close()
if msg.Type == "race" {
r.Laps = append(r.Laps, msg.Coordinates)
r.race(msg.Coordinates)
} else if msg.Type == "kill" {
log.Printf("racer %d: kill signal received. racer will terminate", r.ID)
r.printLaps()
os.Exit(0)
}
}
Some details vary from one implementation to another, but in general, after closing a TCP connection, the underlying system (host OS, usually) has to keep it around for a little while in case of stray duplicate packets.
This connection, which is in TIME_WAIT state, can block further use of the port, making it impossible to create a new listener, unless you give the right underlying settings to the host OS. Since Go 1.5 or so, Go automatically does this on Linux: see issue 9929. What host OS are you using?
If you still get the error, try increasing the milliseconds:
// Sleep a little to avoid this error "bind: address already in use"
time.Sleep(time.Millisecond * 100)
log.Fatal(http.ListenAndServe(":7373", nil))
Thanks to #torek for the idea. I think it's just a notice, not really an error. Example:
2023/02/17 18:10:28 listen tcp :7373: bind: address already in use exit status 1
With go1.20 linux/amd64 and Kernel: Linux 5.13.19-2-MANJARO

Attempting to find a piece of code, responsible for sending TCP packet with RST-flag

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.

cannot receive time exceeded message

I'm doing some tests based on the idea of pwnat, it introduced a method for NAT traversal without 3rd party: the server sends ICMP echo request packets to the fixed address(for example, 3.3.3.3) where no echo replies won't be returned from, the client, pretending to be a hop on the Internet, sends an ICMP Time Exceeded packet to the server, expect the NAT in the front of the server to forward the ICMP time exceeded message to the server.
After I pinged to 3.3.3.3, then I run the code below in 192.168.1.100 to listen ICMP messages in Go:
package main
import (
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
func main() {
c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
fmt.Println("listen error", err)
}
rb := make([]byte, 1500)
for {
n, _, err := c.ReadFrom(rb)
if err != nil {
fmt.Printf("read err: %s\n", err)
}
reply, err := icmp.ParseMessage(1, rb[:n])
if err != nil {
fmt.Println("parse icmp err:", err)
return
}
switch reply.Type {
case ipv4.ICMPTypeTimeExceeded:
if _, ok := reply.Body.(*icmp.TimeExceeded); ok {
// internet header(20 bytes) plus the first 64 bits of the original datagram's data
//fmt.Println("recv id ", binary.BigEndian.Uint16(timeExceed.Data[22:24]))
fmt.Printf("ttl exceeded\n")
}
default:
}
}
}
and a program which runs in 192.168.2.100 to send forged time exceeded message to 192.168.1.100:
package main
import (
"errors"
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"net"
"os"
)
func sendTtle(host string) error {
conn, err := net.Dial("ip4:icmp", host)
if err != nil {
return err
}
// original IP header
h := ipv4.Header{
Version: 4,
Len: 20,
TotalLen: 20 + 8,
TTL: 64,
Protocol: 1,
}
h.Src = net.ParseIP(host)
h.Dst = net.ParseIP("3.3.3.3")
iph, err := h.Marshal()
if err != nil {
fmt.Println("ip header error", err)
return err
}
// 8 bytes of original datagram's data
echo := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: 3456, Seq: 1,
}}
oriReq, err := echo.Marshal(nil)
if err != nil {
return errors.New("Marshal error")
}
data := append(iph, oriReq...)
te := icmp.Message{
Type: ipv4.ICMPTypeTimeExceeded,
Code: 0,
Body: &icmp.TimeExceeded{
Data: data,
}}
if buf, err := te.Marshal(nil); err == nil {
fmt.Println("sent")
if _, err := conn.Write(buf); err != nil {
return errors.New("write error")
}
} else {
return errors.New("Marshal error")
}
return nil
}
func main() {
argc := len(os.Args)
if argc < 2 {
fmt.Println("usage: prpgram + host")
return
}
if err := sendTtle(os.Args[1]); err != nil {
fmt.Println("failed to send TTL exceeded message: ", err)
}
}
the problem is 192.168.1.100 cannot receive the message. What're the possible reasons?
Your code has no problem. If you run your code in the same network(I mean no NAT/router involvement), the program will receive time exceeded message as expected. The reason is the theory pwnat uses doesn't work nowadays.
First, you didn't get the identifier of the echo request sent by
192.168.2.100 to 3.3.3.3, the identifier will be uniquely
mapped to an external query ID by NAPT(if any) so that it can route
future ICMP Echo Replies with the same query ID to the sender. According to rfc 3022 ICMP error packet modifications section,
In a NAPT setup, if the IP message embedded within ICMP happens to be
a TCP, UDP or ICMP Query packet, you will also need to modify the
appropriate TU port number within the TCP/UDP header or the Query
Identifier field in the ICMP Query header.
Second, according to rfc 5508:
If a NAT device receives an ICMP Error packet from the private realm,
and the NAT does not have an active mapping for the embedded payload,
the NAT SHOULD silently drop the ICMP Error packet.
So the forged time exceeded message wouldn't get through. Here is more details about this.

Changing destination port using gopacket

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

How support concurrent connections with a UDP Server using go

I'm playing with my first basic udp server and I wondering how support concurrent connections? I think with my code only can get a connection at a time in order to process it, with a tcp simple server the things seems to be more clear than on this case, throwing a goroutine to process the data, but here I'm very lost, thanks in advance.
func main() {
ListenerUDP("127.0.0.1", 1111)
}
func ListenerUDP(ip string, port int) {
buffer := make([]byte, 1024)
log.Println("Listener Started!")
addr := net.UDPAddr{
Port: port,
IP: net.ParseIP(ip),
}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
log.Fatalf("Error Listening:%s\n", err.Error())
panic(err)
}
defer conn.Close()
for {
_, remoteAddr, err := conn.ReadFromUDP(buffer[0:])
if err != nil {
log.Fatalf("Error:%s\n", err)
}
// Process data here? using a > go something()?
fmt.Printf("Data:%s From:%v\n", buffer, remoteAddr)
}
}
UDP is a connectionless protocol--hosts send packets without establishing a connection first.
To get multiple cores handling UDP packets in parallel, you might start a bunch of goroutines that each do the ReadFromUDP loop:
package main
import (
"fmt"
"net"
"runtime"
)
func listen(connection *net.UDPConn, quit chan struct{}) {
buffer := make([]byte, 1024)
n, remoteAddr, err := 0, new(net.UDPAddr), error(nil)
for err == nil {
n, remoteAddr, err = connection.ReadFromUDP(buffer)
// you might copy out the contents of the packet here, to
// `var r myapp.Request`, say, and `go handleRequest(r)` (or
// send it down a channel) to free up the listening
// goroutine. you do *need* to copy then, though,
// because you've only made one buffer per listen().
fmt.Println("from", remoteAddr, "-", buffer[:n])
}
fmt.Println("listener failed - ", err)
quit <- struct{}{}
}
func main() {
addr := net.UDPAddr{
Port: 12345,
IP: net.IP{127, 0, 0, 1},
}
connection, err := net.ListenUDP("udp", &addr)
if err != nil {
panic(err)
}
quit := make(chan struct{})
for i := 0; i < runtime.NumCPU(); i++ {
go listen(connection, quit)
}
<-quit // hang until an error
}

Resources