cannot receive time exceeded message - go

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.

Related

Encapsulating all traffic with a GRE header

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.

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

How to get a Zebra printer to return a new line character when using getvar?

I wrote a simple Go program to connect to the printer, run a get command
! U1 getvar "zpl.system_status"\r\n
I was then trying to read the response but my read listener kept timing out. I was expecting a \n at the end of the data coming from the printer but was not getting it. Is there a way to tell the printer to respond and terminate the line with \n?
If not, what's the best way to listen for a response. I ended up reading the stream and then setting a timeout to wait for more data, but that seems kind of hacky.
Is there a specific character I can wait for to indicate the printer is done sending the response?
I also logged in with a telnet client manually and saw the same behavior.
Here is the code I put together. It's rough at the moment, just trying to get things working before I clean it up. It does get the response with this code and with the commented out code, but I feel like I should be getting a line terminator from the server and I'm not.
package main
import (
"bufio"
"net"
"os"
"time"
)
func main() {
dialer := net.Dialer{Timeout: 1 * time.Second}
conn, err := dialer.Dial("tcp", "127.0.0.1:9100")
if err != nil {
println("Dial failed: ", err.Error())
os.Exit(1)
}
defer conn.Close()
rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
println("Sending string request")
n, err := rw.WriteString("! U1 getvar \"interface.network.active.mac_addr\"\r\n")
if err != nil {
println("Error getting status.", err)
}
println("Characters sent: ", n)
err = rw.Flush()
if err != nil {
println("Error on flush", err)
}
err = conn.SetReadDeadline(time.Now().Add(1 * time.Second))
if err != nil {
println("Set Deadline failed: ", err)
}
// buffer := make([]byte, 0, 1024)
// tmp := make([]byte, 128)
// for {
// n, err := conn.Read(tmp[:])
// if err != nil {
// println(err)
// break
// }
// println(n)
// buffer = append(buffer, tmp[:n]...)
// }
// println(string(buffer))
response, err := rw.ReadString('\n')
if err != nil {
println("Read error: ", err.Error())
}
println("Response: ", response)
}
Response - I changed the mac address below but this is basically what I get.
Sending string request
Characters sent: 49
Read error: read tcp i/o timeout
Response: "07:4d:07:79:47:ef"
Use the JSON wrapping of SGD:
send {}{"zpl.system_status":null}
The response will come back in JSON to you can look for the closing }

How to test TCP disconnection in GO

I do have a process receiving data from second local process. I need to test if connection errors are handled well AND if it automatically reconnects and keep receiving data after a disconnection.
To do so I am trying to make it disconnect abruptly or put the TCP connection in an error state from a unit test.
As seen in this question to check if a connection is closed I am checking for data to come and test if it returns an error.
I am not sure how to:
close the connection ungracefully
make it be in an error state
This is the essence of my data receiver:
import (
"bufio"
"encoding/json"
"fmt"
"io"
"net"
)
type Message struct {
ID string `json:"id"`
}
func ReceiveData(listener Listener) {
var tcpConn net.Conn
var addr string = "127.0.0.1:9999"
tcpConn, err := net.Dial("tcp", addr)
socketReader := bufio.NewReader(tcpConn)
decoder := json.NewDecoder(socketReader)
for {
var msg Message
if err := decoder.Decode(&msg); err == io.EOF {
listener.ProcessUpdate(Message{}, fmt.Errorf("Received EOF"), nil)
tcpConn = nil
return
} else if err != nil {
listener.ProcessUpdate(Message{}, nil, fmt.Errorf("Error decoding message: %s", err.Error()))
tcpConn = nil
return
}
// process message
_ = msg
// Test disconnection
// This does not disconnect:
// tcpConn = nil
// This does but gracefully:
// tcpConn.Close()
}
I am not mocking the TCP connection as I'd like to try with the real data producer. If is needed I'll look at it.
A solution is to set a deadline to the TCP connection itself:
tcpConn.SetDeadline(time.Now())
Later this will trigger a timeout error which can be caught with:
err := decoder.Decode(&msg);
if err != nil {
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
fmt.Errorf("TCP timeout : %s", err.Error())
} else {
fmt.Errorf("Received error decoding message: %s", err.Error())
}
}

Golang Server close the connection of the client : websocket

i have a problem with my golang server in which i'm using websockets.
The server opens the connection and the client could connect to it, but the problem is that when the server starts sending the data to the client, the client connection is closed after a small period of time. i suggest that the problem is with the server and not with the client because i tried to connect to the server with another web client, and it's the same issue. I didn't understand the cause ! Can someone help me?
server.go:
func Echo(ws *websocket.Conn) {
fmt.Println("Echoing")
for {
msg := MessageReceived{Name: "OrderCommand", Nbmsg: 3}
if err := websocket.JSON.Send(ws, msg); err != nil {
fmt.Println("Can't send")
break
}
//os.Exit(0)
}
}
func checkError(err error) {
if err != nil {
Log("Fatal error ", err.Error())
os.Exit(1)
}
}
func main() {
http.HandleFunc("/save", saveHandler)
http.Handle("/", websocket.Handler(Echo))
err:= http.ListenAndServe(":8081", nil)
checkError(err)
}
and client.go:
import (
"code.google.com/p/go.net/websocket"
"fmt"
"log"
)
func main() {
origin := "http://localhost/"
url := "ws://localhost:8081/echo"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Fatal(err)
}
var msg = make([]byte, 512)
var n int
if n, err = ws.Read(msg); err != nil {
log.Fatal(err)
}
fmt.Printf("Received: %s.\n", msg[:n])
}
Your problem, as others have pointed out, is that you must receive a message as well.
Currently, when someone connects, your program will step into the for-loop and start bombarding the client with messages. Probably not the intended behaviour of an echo server.
First you want to Receive a message, then Send a reply:
func Echo(ws *websocket.Conn) {
fmt.Println("Echoing")
msg := new(MessageReceived)
for {
// The server blocks here until a message from the client is received
websocket.JSON.Receive(ws, &msg)
fmt.Printf("Received message: %+v\n", msg)
// Reencode the same message and send it back
if err := websocket.JSON.Send(ws, msg); err != nil {
fmt.Println("Can't send echo")
break
}
}
}
A full working version can be found at Playground: http://play.golang.org/p/nQ3fJ5Nb0I
Since it uses websockets, you must compile it on your local computer.
Why using ws.Read when you can use websocket.JSON.Receive to deserialize the message?
Here are the server: http://play.golang.org/p/NZ6VJ4daGm
and the client: http://play.golang.org/p/rkJVKGhrGk (that I have changed to receive 10 messages before exiting).
The string "Can't send" will be printed by the server once the client closes the websocket connection.

Resources