How to listen at the data link layer (ethernet) and respond at the transport layer - sockets

What I am trying to do is listen to ethernet frames for IPv6 and respond to UDP calls on a specific port.
I am able to capture the ethernet frames I care about and parse out the UDP payload, but when I attempt to echo that payload back is where I have a problem. Here is my "server" code:
func main() {
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(htons(syscall.ETH_P_IPV6)))
iface, err := net.InterfaceByName("lo")
if err != nil {
log.Fatal(err)
}
err = syscall.BindToDevice(fd, iface.Name)
if err != nil {
log.Fatal(err)
}
for {
buf := make([]byte, iface.MTU)
n, callerAddr, err := syscall.Recvfrom(fd, buf, 0)
if err != nil {
log.Fatal(err)
}
data := buf[:n]
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.Default)
udpPacket := packet.Layer(layers.LayerTypeUDP)
if udpPacket != nil {
udpPck, _ := udpPacket.(*layers.UDP)
// I only care about calls to 8080 for this example
if udpPck.DstPort != 8080 {
continue
}
err = udpPck.SetNetworkLayerForChecksum(packet.NetworkLayer()); if err != nil {
log.Fatal(err)
}
log.Print(packet)
log.Printf("UDP Port from %v --> %v", udpPck.SrcPort, udpPck.DstPort)
log.Printf("Payload '%v'", string(udpPck.Payload))
// Flip the source and destination so it can go back to the caller
ogDst := udpPck.DstPort
udpPck.DstPort = udpPck.SrcPort
udpPck.SrcPort = ogDst
buffer := gopacket.NewSerializeBuffer()
options := gopacket.SerializeOptions{ComputeChecksums: true}
// Rebuild the packet with the new source and destination port
err := gopacket.SerializePacket(buffer, options, packet)
if err != nil {
log.Fatal(err)
}
log.Printf("Writing the payload back to the caller: %v", callerAddr)
log.Print(packet)
err = syscall.Sendto(fd, buffer.Bytes(), 0, callerAddr)
if err != nil {
log.Fatal(err)
}
}
}
And then my client code which is running on the same machine:
func main() {
conn, err := net.DialUDP("udp6", &net.UDPAddr{
IP: net.IPv6loopback,
Port: 0,
}, &net.UDPAddr{
IP: net.IPv6loopback,
Port: 8080,
})
if err != nil {
log.Fatal(err)
}
_, _ = conn.Write([]byte("Hello World"))
log.Print("Waiting for response")
buf := make([]byte, 65535)
n, _, err := conn.ReadFrom(buf)
if err != nil {
log.Fatal(err)
}
log.Printf("Response message '%v'", string(buf[:n]))
}
The problem from the client side is a connection refused read udp6 [::1]:56346->[::1]:8080: recvfrom: connection refused which my guess would be coming from the linux kernel since I have not bound anything to 8080 strictly speaking.
There is data I need from the IPv6 header (not seen above) which is why I need to listen on the data link layer, but since I also need to respond to UDP requests things get a little tricky.
An option I have but don't like would be to in a separate goroutine do a standard net.ListenUDP and then block after reading data until the IPv6 header is read from the syscall socket listener, then from there responding on the udp connection. If this is my only option I will take it but I would interested to see if there is something better I could do.

I think you still need to listen on the UDP port even though you are responding by constructing a link layer frame. Otherwise the system's networking stack will respond with an ICMP message, which is what caused the "connection refused" error.
I haven't tried this but I think if you remove the IP address from the interface, it'd prevent the kernel IP stack from running on it. But then there might be ARP messages you need to deal with.
Alternatively you might try using a TUN/TAP interface, so that you have full control over what happens on it from user space.

Related

How to get MAC address of Ethernet interface of a UDP socket?

I want to create a UDP server.
The server has several network interfaces : I want each interface to respond even if it is not in the same subnet as clients (clients send broadcast Ethernet packets).
How to do it ?
// The UDP server receives the client's request but fails to respond if it is not in the same subnet mask.
func udp_server(local_interface_ip net.IP){
p := make([]byte, 2048)
addr := net.UDPAddr{
Port: 1234,
IP: local_interface_ip,
}
ser, err := net.ListenUDP("udp", &addr)
if err != nil {
fmt.Printf("Some error %v\r\n", err)
return
}
for {
packetLen, remoteaddr, err := ser.ReadFromUDP(p)
if err != nil {
fmt.Printf("Some error %v", err)
continue
}
fmt.Printf("[RX %v] message(len : %d) : %s\r\n", remoteaddr, packetLen, p)
sendResponse(ser, remoteaddr)
}
}
func sendResponse(conn *net.UDPConn, addr *net.UDPAddr) {
data := []byte("1234")
_, err := conn.WriteToUDP(data, addr)
if err != nil {
fmt.Printf("[TX] Couldn't send response to %v (%v)\r\n", addr, err)
}
}
Then, for the server response, I want to put in the UDP data the MAC address of the server interface: How to do?
// This function get all MAC Address of the server but to know what is the good interface ?
func getMacAddr() ([]string, error) {
ifas, err := net.Interfaces()
if err != nil {
return nil, err
}
var as []string
for _, ifa := range ifas {
a := ifa.HardwareAddr.String()
if a != "" {
as = append(as, a)
}
}
return as, nil
}
It is a custom protocol based on UDP which is imposed to me which allows the clients to be able to discover IP address and MAC address of server interfaces.

golang socket doesn't send all bytes before Write() method returns

Today when I try to send 100M data to my server (a very simple TCP server also written in Golang), I found that the TCPConn.Write method returns 104857600 and nil error and then I close the socket. But my server only receives very little data. I think it is because Write method works in async mode, so although the method returns 104857600, only a little data is sent to the server. So I want to know whether there is a way to set the Write work in sync mode or how to detect whether all data is sent to the server from the socket.
The code is as follows:
server:
const ListenAddress = "192.168.0.128:8888"
func main() {
var l net.Listener
var err error
l, err = net.Listen("tcp", ListenAddress)
if err != nil {
fmt.Println("Error listening:", err)
os.Exit(1)
}
defer l.Close()
fmt.Println("listen on " + ListenAddress)
for {
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err)
os.Exit(1)
}
//logs an incoming message
fmt.Printf("Received message %s -> %s \n", conn.RemoteAddr(), conn.LocalAddr())
// Handle connections in a new goroutine.
go handleRequest(conn)
}
}
func handleRequest(conn net.Conn) {
defer conn.Close()
rcvLen := 0
rcvData := make([]byte,20 * 1024 * 1024) // 20M
for {
l , err := conn.Read(rcvData)
if err != nil {
fmt.Printf("%v", err)
return
}
rcvLen += l
fmt.Printf("recv: %d\r\n", rcvLen)
conn.Write(rcvData[:l])
}
}
Client:
conn, err := net.Dial("tcp", "192.168.0.128:8888")
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
defer conn.Close()
data := make([]byte, 500 * 1024 * 1024)
length, err := conn.Write(data)
fmt.Println("send len: ", length)
The output of the client:
send len: 524288000
The output of the server:
listen on 192.168.0.128:8888
Received message 192.168.0.2:50561 -> 192.168.0.128:8888
recv: 166440
recv: 265720
EOF
I know if I can make the client wait for a while by SetLinger method, the data will be all sent to the server before the socket is closed. But I want to find a way to make the socket send all data before returns without calling SetLinger().
Please excuse my poor English.
Did you poll the socket before trying to write?
Behind the socket is your operating system's tcp stack. When writing on a socket, you push bytes to the send buffer. Your operating system then self determines when and how to send. If the receiving end has no buffer space.available in their receice buffer, your sending end knows this and will not put any more information in the send buffer.
Make sure your send buffer has enough space for whatever you are trying to send next. This is done by polling the socket. This method is usually called Socket.Poll. I.recommend you ccheck the golang docs for the exact usage.
You are not handling the error returned by conn.Read correctly. From the docs (emphasis mine):
When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. [...]
Callers should always process the n > 0 bytes returned before considering the error err. Doing so correctly handles I/O errors that happen after reading some bytes and also both of the allowed EOF behaviors.
Note that you are re-inventing io.Copy (albeit with an excessive buffer size). Your server code can be rewritten as:
func handleRequest(conn net.Conn) {
defer conn.Close()
n, err := io.Copy(conn, conn)
}

Write on a closed net.Conn but returned nil error

Talk is cheap, so here we go the simple code:
package main
import (
"fmt"
"time"
"net"
)
func main() {
addr := "127.0.0.1:8999"
// Server
go func() {
tcpaddr, err := net.ResolveTCPAddr("tcp4", addr)
if err != nil {
panic(err)
}
listen, err := net.ListenTCP("tcp", tcpaddr)
if err != nil {
panic(err)
}
for {
if conn, err := listen.Accept(); err != nil {
panic(err)
} else if conn != nil {
go func(conn net.Conn) {
buffer := make([]byte, 1024)
n, err := conn.Read(buffer)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(">", string(buffer[0 : n]))
}
conn.Close()
}(conn)
}
}
}()
time.Sleep(time.Second)
// Client
if conn, err := net.Dial("tcp", addr); err == nil {
for i := 0; i < 2; i++ {
_, err := conn.Write([]byte("hello"))
if err != nil {
fmt.Println(err)
conn.Close()
break
} else {
fmt.Println("ok")
}
// sleep 10 seconds and re-send
time.Sleep(10*time.Second)
}
} else {
panic(err)
}
}
Ouput:
> hello
ok
ok
The Client writes to the Server twice. After the first read, the Server closes the connection immediately, but the Client sleeps 10 seconds and then re-writes to the Server with the same already closed connection object(conn).
Why can the second write succeed (returned error is nil)?
Can anyone help?
PS:
In order to check if the buffering feature of the system affects the result of the second write, I edited the Client like this, but it still succeeds:
// Client
if conn, err := net.Dial("tcp", addr); err == nil {
_, err := conn.Write([]byte("hello"))
if err != nil {
fmt.Println(err)
conn.Close()
return
} else {
fmt.Println("ok")
}
// sleep 10 seconds and re-send
time.Sleep(10*time.Second)
b := make([]byte, 400000)
for i := range b {
b[i] = 'x'
}
n, err := conn.Write(b)
if err != nil {
fmt.Println(err)
conn.Close()
return
} else {
fmt.Println("ok", n)
}
// sleep 10 seconds and re-send
time.Sleep(10*time.Second)
} else {
panic(err)
}
And here is the screenshot:
attachment
There are several problems with your approach.
Sort-of a preface
The first one is that you do not wait for the server goroutine
to complete.
In Go, once main() exits for whatever reason,
all the other goroutines still running, if any, are simply
teared down forcibly.
You're trying to "synchronize" things using timers,
but this only works in toy situations, and even then it
does so only from time to time.
Hence let's fix your code first:
package main
import (
"fmt"
"log"
"net"
"time"
)
func main() {
addr := "127.0.0.1:8999"
tcpaddr, err := net.ResolveTCPAddr("tcp4", addr)
if err != nil {
log.Fatal(err)
}
listener, err := net.ListenTCP("tcp", tcpaddr)
if err != nil {
log.Fatal(err)
}
// Server
done := make(chan error)
go func(listener net.Listener, done chan<- error) {
for {
conn, err := listener.Accept()
if err != nil {
done <- err
return
}
go func(conn net.Conn) {
var buffer [1024]byte
n, err := conn.Read(buffer[:])
if err != nil {
log.Println(err)
} else {
log.Println(">", string(buffer[0:n]))
}
if err := conn.Close(); err != nil {
log.Println("error closing server conn:", err)
}
}(conn)
}
}(listener, done)
// Client
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
for i := 0; i < 2; i++ {
_, err := conn.Write([]byte("hello"))
if err != nil {
log.Println(err)
err = conn.Close()
if err != nil {
log.Println("error closing client conn:", err)
}
break
}
fmt.Println("ok")
time.Sleep(2 * time.Second)
}
// Shut the server down and wait for it to report back
err = listener.Close()
if err != nil {
log.Fatal("error closing listener:", err)
}
err = <-done
if err != nil {
log.Println("server returned:", err)
}
}
I've spilled a couple of minor fixes
like using log.Fatal (which is
log.Print + os.Exit(1)) instead of panicking,
removed useless else clauses to adhere to the coding standard of keeping the main
flow where it belongs, and lowered the client's timeout.
I have also added checking for possible errors Close on sockets may return.
The interesting part is that we now properly shut the server down by closing the listener and then waiting for the server goroutine to report back (unfortunately Go does not return an error of a custom type from net.Listener.Accept in this case so we can't really check that Accept exited because we've closed the listener).
Anyway, our goroutines are now properly synchronized, and there is
no undefined behaviour, so we can reason about how the code works.
Remaining problems
Some problems still remain.
The more glaring is you making wrong assumption that TCP preserves
message boundaries—that is, if you write "hello" to the client
end of the socket, the server reads back "hello".
This is not true: TCP considers both ends of the connection
as producing and consuming opaque streams of bytes.
This means, when the client writes "hello", the client's
TCP stack is free to deliver "he" and postpone sending "llo",
and the server's stack is free to yield "hell" to the read
call on the socket and only return "o" (and possibly some other
data) in a later read.
So, to make the code "real" you'd need to somehow introduce these
message boundaries into the protocol above TCP.
In this particular case the simplest approach would be either
using "messages" consisting of a fixed-length and agreed-upon
endianness prefix indicating the length of the following
data and then the string data itself.
The server would then use a sequence like
var msg [4100]byte
_, err := io.ReadFull(sock, msg[:4])
if err != nil { ... }
mlen := int(binary.BigEndian.Uint32(msg[:4]))
if mlen < 0 {
// handle error
}
if mlen == 0 {
// empty message; goto 1
}
_, err = io.ReadFull(sock, msg[5:5+mlen])
if err != nil { ... }
s := string(msg[5:5+mlen])
Another approach is to agree on that the messages do not contain
newlines and terminate each message with a newline
(ASCII LF, \n, 0x0a).
The server side would then use something like
a usual bufio.Scanner loop to get
full lines from the socket.
The remaining problem with your approach is to not dealing with
what Read on a socket returns: note that io.Reader.Read
(that's what sockets implement, among other things) is allowed
to return an error while having had read some data from the
underlying stream. In your toy example this might rightfully
be unimportant, but suppose that you're writing a wget-like
tool which is able to resume downloading of a file: even if
reading from the server returned some data and an error, you
have to deal with that returned chunk first and only then
handle the error.
Back to the problem at hand
The problem presented in the question, I beleive, happens simply because in your setup you hit some TCP buffering problem due to the tiny length of your messages.
On my box which runs Linux 4.9/amd64 two things reliably "fix"
the problem:
Sending messages of 4000 bytes in length: the second call
to Write "sees" the problem immediately.
Doing more Write calls.
For the former, try something like
msg := make([]byte, 4000)
for i := range msg {
msg[i] = 'x'
}
for {
_, err := conn.Write(msg)
...
and for the latter—something like
for {
_, err := conn.Write([]byte("hello"))
...
fmt.Println("ok")
time.Sleep(time.Second / 2)
}
(it's sensible to lower the pause between sending stuff in
both cases).
It's interesting to note that the former example hits the
write: connection reset by peer (ECONNRESET in POSIX)
error while the second one hits write: broken pipe
(EPIPE in POSIX).
This is because when we're sending in chunks worth 4k bytes,
some of the packets generated for the stream manage to become
"in flight" before the server's side of the connection manages
to propagate the information on its closure to the client,
and those packets hit an already closed socket and get rejected
with the RST TCP flag set.
In the second example an attempt to send another chunk of data
sees that the client side already knows that the connection
has been teared down and fails the sending without "touching
the wire".
TL;DR, the bottom line
Welcome to the wonderful world of networking. ;-)
I'd recommend buying a copy of "TCP/IP Illustrated",
read it and experiment.
TCP (and IP and other protocols above IP)
sometimes works not like people expect them to by applying
their "common sense".

Golang UDP and TCP beside each other

is it possible to use TCP and UDP with each other in a single script? I need some of my packages to send and receive with TCP and some of them with UDP
func main() {
//
// ─── TCP ────────────────────────────────────────────────────────────────────
//
// Listen for incoming connections.
l, err := net.Listen("tcp", "localhost"+":"+"3000")
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
// Close the listener when the application closes.
defer l.Close()
fmt.Println("Listening on " + "localhost" + ":" + "3000")
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
// Handle connections in a new goroutine.
go gotcp.HandleRequest(conn)
//go handler(conn)
}
//
// ─── UDP ────────────────────────────────────────────────────────────────────
//
// then we should check which struct is empty and fill them
/* Lets prepare a address at any address at port 10001*/
ServerAddr, err := net.ResolveUDPAddr("udp", ":3000")
goudp.CheckError(err)
/* Now listen at selected port */
ServerConn, err := net.ListenUDP("udp", ServerAddr)
goudp.CheckError(err)
defer ServerConn.Close()
buf := make([]byte, 1024)
for {
n, addr, err := ServerConn.ReadFromUDP(buf)
//fmt.Println("Received ", string(buf[0:n]), " from ", addr)
if err != nil {
fmt.Println("Error: ", err)
}
// *** broadcasting
//start := time.Now()
if v, ok := goudp.RRoom()[djr]; ok {
//fmt.Println("get room name ", v)
go goudp.BroadCast(string(buf[0:n]), djr, ServerConn, v)
//delete(R, "x")
//go sendResponse(ServerConn, v.UserAddr1)
}
//elapsed := time.Since(start)
//log.Printf("Binomial took %s", elapsed)
}
}
EDIT:
By passing tcp part or udp part in a function and call it like go tcpServer() we can use Both UDP and TCP with each other
As noted by putu you need some concurrency to get it working properly.
NodeJS works with callbacks by default, which means that once you pass a function as a parameter to a function it will release the main loop to the next instruction. This is why NodeJS apps have the object.method(function(){}) pattern. To achieve something similar to this in Go, you need to wrap the TCP and UDP portion of the program in a separate goroutine with a infinite loop each.
For a simple proof the concept, do something like this:
...
go func(){
// paste your tcp code here
}()
...
go func(){
// paste your udp code here
}()
That "go" instruction says to the compiler that a portion of code should run concurrently. In a real-world project, you will put that portion of code in a proper function and just call it by name from your main function:
...
go serveTCP();
go serve UDP();
...
More about concurrency in go here => https://tour.golang.org/concurrency/1

Reading TCP packets via raw sockets in GO

I'm researching raw sockets in GO. I would like to be able to read all TCP packets going to my computer (OSX, en0: 192.168.1.65)
If I switch the protocol from tcp to icmp, I will get packets. Why do I have no packets being read with my code?
package main
import (
"fmt"
"net"
)
func main() {
netaddr, err := net.ResolveIPAddr("ip4", "192.168.1.65")
if err != nil {
fmt.Println(err)
}
conn, err := net.ListenIP("ip4:tcp", netaddr)
if err != nil {
fmt.Println(err)
}
buf := make([]byte, 2048)
for {
numRead, recvAddr, err := conn.ReadFrom(buf)
if err != nil {
fmt.Println(err)
}
if recvAddr != nil {
fmt.Println(recvAddr)
}
s := string(buf[:numRead])
fmt.Println(s)
}
}
The problem with this is that OS X is based on BSD, and BSD doesn't allow you to program raw sockets at the TCP level. You have to use go down to the Ethernet level in order to do so.
I'm using the pcap library with gopackets to do the job.
https://godoc.org/code.google.com/p/gopacket/pcap