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
Related
I setup a udp server listening multicast trafic, and create a client to sent test packet. When the server receives the package, it will send a response. Everything is ok, except the client cannot receive the packet from the server. Why?
package main
import (
"log"
"net"
"os"
"time"
"golang.org/x/net/ipv4"
)
func SetupMulticast(ifn, addr string) {
ifi, err := net.InterfaceByName(ifn)
if err != nil {
log.Fatal(err)
}
//server
c, err := net.ListenPacket("udp4", addr)
if err != nil {
log.Fatal(err)
}
log.Printf("listen ad:%s\n", addr)
p := ipv4.NewPacketConn(c)
gAddr, err2 := net.ResolveUDPAddr("udp4", addr)
if err2 != nil {
log.Fatal(err2)
}
if err := p.JoinGroup(ifi, gAddr); err != nil {
log.Fatal(err)
}
if err := p.SetControlMessage(ipv4.FlagDst|ipv4.FlagSrc, true); err != nil {
log.Fatal(err)
}
go func() {
b := make([]byte, 1500)
for {
n, cm, src, err := p.ReadFrom(b)
if err != nil {
break
}
log.Println("receive:", string(b[:n]), cm.Dst.IsMulticast(), cm.Dst)
if n2, err := p.WriteTo([]byte("world!"), nil, src); err != nil {
log.Printf("fail to write back:%v\n", err)
} else {
log.Printf("write back addr: %s length:%d\n", src, n2)
}
}
}()
//client
if conn, err2 := net.DialUDP("udp4", nil /*src*/, gAddr); err2 != nil {
log.Fatal(err)
} else {
go func() {
for {
log.Println("write hello...")
conn.Write([]byte("hello"))
time.Sleep(time.Second * 2)
}
}()
go func() {
b2 := make([]byte, 1500)
for {
n, err := conn.Read(b2)
if err != nil {
log.Panic(err)
}
log.Printf("sender received response:%s\n", string(b2[:n]))
}
}()
}
}
func main() {
If := os.Args[1] //ens33
Addr := os.Args[2] //224.0.0.248:1025
SetupMulticast(If, Addr)
for {
}
}
And the output:
2022/08/17 22:53:53 listen ad:224.0.0.248:1025
2022/08/17 22:53:53 write hello...
2022/08/17 22:53:53 receive: hello true 224.0.0.248
2022/08/17 22:53:53 write back addr: 192.168.19.131:43925 length:6
2022/08/17 22:53:55 write hello...
2022/08/17 22:53:55 receive: hello true 224.0.0.248
2022/08/17 22:53:55 write back addr: 192.168.19.131:43925 length:6
From the logs, there are no any "sender received response" record. I don't know why?
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
I want get tls conn base on udp, just like:
package main
import (
"crypto/tls"
"fmt"
"io"
"net"
"time"
)
func handleConn(conn net.Conn) {
defer conn.Close()
var buf []byte = make([]byte, 2000)
for {
if n, err := conn.Read(buf); err != nil && err != io.EOF {
panic(err)
} else {
conn.Write(buf[:n])
}
}
}
func server() {
cert, err := tls.LoadX509KeyPair("./serve.cert.pem", "./serve.key.pem")
if err != nil {
panic(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19986}, &net.UDPAddr{Port: 19987})
if err != nil {
panic(err)
}
tconn := tls.Server(conn, config)
defer tconn.Close()
if err = tconn.Handshake(); err != nil {
panic(err)
}
handleConn(tconn)
}
func main() {
go server()
time.Sleep(time.Second)
client()
}
func client() {
conf := &tls.Config{
InsecureSkipVerify: true,
}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19987}, &net.UDPAddr{Port: 19986})
if err != nil {
panic(err)
}
tconn := tls.Client(conn, conf)
defer tconn.Close()
if err = tconn.Handshake(); err != nil {
panic(err)
}
_, err = conn.Write([]byte("hello"))
if err != nil {
panic(err)
}
buf := make([]byte, 100)
n, err := conn.Read(buf)
if err != nil {
panic(err)
}
fmt.Println(string(buf[:n]))
}
panic:
panic: read udp 127.0.0.1:19987->127.0.0.1:19986: wsarecv: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
goroutine 1 [running]:
main.client()
D:/OneDrive/code/go/ctest/main.go:65 +0x2d1
main.main()
D:/OneDrive/code/go/ctest/main.go:49 +0x34
exit status 2
Appendix:
serve.cert.pem
-----BEGIN CERTIFICATE-----
MIIBbjCCARSgAwIBAgIRAI+jBYEYS5aBXDUedBt7PKYwCgYIKoZIzj0EAwIwEjEQ
MA4GA1UEChMHQWNtZSBDbzAeFw0yMjAxMDkxNzQxMjBaFw0yMzAxMDkxNzQxMjBa
MBIxEDAOBgNVBAoTB0FjbWUgQ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQy
l1/gWhTxZ3rS/XJOMLHhmkQp64EtPrEgq9SjKDpWBZQC+kNZdM5xzJrv3bLqcyOS
JywZfEpTZzW7sxko4maBo0swSTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI
KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYI
KoZIzj0EAwIDSAAwRQIhAICxMC8o603GwL3bf42EXrtPP5/LtEIc/hjdJpilqc3b
AiBTEdrE+/oCgUjsxV2RFj1+42CTGtcav4sJyCPjme0N/w==
-----END CERTIFICATE-----
serve.key.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmH+BleetLN1fK0dy
JpedWG8C2yxtb7gEEAwvdwXf6FihRANCAAQyl1/gWhTxZ3rS/XJOMLHhmkQp64Et
PrEgq9SjKDpWBZQC+kNZdM5xzJrv3bLqcyOSJywZfEpTZzW7sxko4maB
-----END PRIVATE KEY-----
I try set udp conn's buff, useless!
The certificate only 558 Bytes, but the UDP has a capacity of 65536 Bytes. then, I debug found: in crypt/tls/conn.go>readRecordOrCCS c.readFromUntil(c.conn, recordHeaderLen), the recordHeaderLen is constant 5, it add bytes.MinRead; so the reader buff's len is 517. Actually data size about 700 Bytes.
So? What should I do?
You cannot sensibly expect to make the thing work: TLS (and SSL) is designed to be carried out using the application layer of another protocol.
What this means in simpler terms is that while TLS is oblivious to what particular protocol transports its bytes, as a client of the application layer, it expects two properties from the underlying stack: it transports arbitrary opaque streams of data, ensuring robustness and in-order delivery.
In the TCP/IP world, this means TCP because UDP does not provide neither of the properties TLS expects.
Still, some solutions do successfully employ TLS over UDP, with OpenVPN being a prime example of this—it uses TLS for handshake and initial key exchange while having UDP as its default, and recommended, transport protocol,—but all of them have a layer implemented over UDP which "arms" it with the properties typically found in TCP: such layers deal with dropped, reordered, duplicated and corrupted UDP frames, "exporting" to the upper layer a protocol which is OK to use for application layer.
This basically means than if you're after using TLS over UDP, you first need to implemet a custom type having the net.Conn interface which would use a UDP association to shovel the bytes back and forth and "export" to its client a connection which has the properties of robustness and in-order delivery—just as net.TCPConn does.
I GOT IT!
just make udp conn become to stream io.
package main
import (
"bufio"
"crypto/tls"
"fmt"
"io"
"net"
"time"
)
func handleConn(conn net.Conn) {
defer conn.Close()
var buf []byte = make([]byte, 2000)
for {
if n, err := conn.Read(buf); err != nil && err != io.EOF {
panic(err)
} else {
fmt.Println(string(buf[:n]))
conn.Write(append([]byte("got: "), buf[:n]...))
}
}
}
func server() {
cert, err := tls.LoadX509KeyPair("./serve.cert.pem", "./serve.key.pem")
if err != nil {
panic(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19986}, &net.UDPAddr{Port: 19987})
if err != nil {
panic(err)
}
sconn := NewSconn(conn)
tconn := tls.Server(sconn, config)
defer tconn.Close()
handleConn(tconn)
}
func main() {
go server()
time.Sleep(time.Second)
client()
}
func client() {
conf := &tls.Config{
InsecureSkipVerify: true,
CipherSuites: []uint16{
tls.TLS_AES_128_GCM_SHA256,
},
}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19987}, &net.UDPAddr{Port: 19986})
if err != nil {
panic(err)
}
sconn := NewSconn(conn)
tconn := tls.Client(sconn, conf)
defer tconn.Close()
_, err = tconn.Write([]byte("hello"))
if err != nil {
panic(err)
}
buf := make([]byte, 100)
n, err := tconn.Read(buf)
if err != nil {
panic(err)
}
fmt.Println(string(buf[:n]))
}
//
//
//
//
// --------------------------------------------------
type sconn struct {
conn net.Conn
buf *bytes.Buffer
rLen int
lock sync.Mutex
}
func NewSconn(conn net.Conn) *sconn {
return &sconn{
conn: conn,
buf: bytes.NewBuffer(nil),
rLen: 2000,
lock: sync.Mutex{},
}
}
func (s *sconn) Read(b []byte) (n int, err error) {
s.lock.Lock()
defer s.lock.Unlock()
if s.buf.Len() != 0 {
n, err = s.buf.Read(b)
} else {
s.push(&s.rLen)
n, err = s.buf.Read(b)
}
return n, err
}
// push push UDP package to buff
func (s *sconn) push(rLen *int) (err error) {
defer func() {
if e := recover(); e != nil {
if *rLen < 65536 {
*rLen = *rLen + 2000
s.push(rLen)
} else {
err = errors.New(fmt.Sprintln(e))
}
}
}()
var tmp []byte = make([]byte, *rLen)
if n, err := s.conn.Read(tmp); err != nil {
return err
} else {
_, err := s.buf.Write(tmp[:n])
return err
}
}
func (s *sconn) Write(b []byte) (n int, err error) {
for i := 0; i < len(b); i = i + 512 {
j := i + 512
if j > len(b) {
j = len(b)
}
if n, err = s.conn.Write(b[i:j]); err != nil {
return n, err
}
}
return len(b), nil
}
func (s *sconn) Close() error { return nil } // only close TLS conn, don't close UDP conn
func (s *sconn) LocalAddr() net.Addr { return s.conn.LocalAddr() }
func (s *sconn) RemoteAddr() net.Addr { return s.conn.RemoteAddr() }
func (s *sconn) SetDeadline(t time.Time) error { return s.conn.SetDeadline(t) }
func (s *sconn) SetReadDeadline(t time.Time) error { return s.conn.SetReadDeadline(t) }
func (s *sconn) SetWriteDeadline(t time.Time) error { return s.conn.SetWriteDeadline(t) }
This seemingly simple example is not working as expected and I feel bad for asking but here goes:
There's a client that retries connecting to the server, sends a message, and then waits for a response:
func client() {
var conn net.Conn
var err error
// retry server until it is up
for {
conn, err = net.Dial("tcp", ":8081")
if err == nil {
break
}
log.Println(err)
time.Sleep(time.Second)
}
// write to server
_, err = conn.Write([]byte("request"))
if err != nil {
log.Println(err)
return
}
// block & read from server
var buf []byte
n, err := conn.Read(buf)
if err != nil {
log.Println(err)
return
}
log.Printf("From server: %s\n", buf[:n])
}
It connects to a server which for each connection, reads and interprets the sent data, and sends a response if needed:
func server() {
ln, _ := net.Listen("tcp", ":8081")
for {
conn, _ := ln.Accept()
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
var buf []byte
n, err := conn.Read(buf)
if err != nil {
return
}
log.Printf("Server got: %s\n", buf)
if string(buf[:n]) == "request" {
_, _ = conn.Write([]byte("response"))
}
}
All driven by the main function:
func main() {
go client()
server()
}
Error handling is omitted for brevity. The expected behavior is that the client will connect to the server and send the message "request" and then block on the read. The server receives "request" and sends the message "response" back to the same connection. The client unblock, prints the received message and exits. Instead, when the program is run, the following is printed:
2019/09/01 22:24:02 From server:
2019/09/01 22:24:02 Server got:
Suggesting that no data was exchanged, and that the client did not block.
The looping in client is strange!
The looping not make sense if read/write is out.
But the error is only this:
//var buf []byte <--- this read 0 bytes
buf := make([]byte, 1024)
n, err := conn.Read(buf)
A proposal for you:
package main
import (
"log"
"net"
"time"
)
func client() {
var conn net.Conn
var err error
// retry server until it is up
for {
log.Printf("Connecting...")
conn, err = net.Dial("tcp", ":8082")
if err != nil {
log.Println(err)
break
}
time.Sleep(time.Second)
// write to server
log.Printf("Writing...")
_, err = conn.Write([]byte("request"))
if err != nil {
log.Println(err)
return
}
// block & read from server
log.Printf("Reading...")
var buf []byte
n, err := conn.Read(buf)
if err != nil {
log.Println(err)
return
}
log.Printf("From server: %s\n", buf[:n])
}
}
func server() {
ln, _ := net.Listen("tcp", ":8082")
for {
conn, _ := ln.Accept()
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
return
}
log.Printf("Server got: [%d bytes] %s\n", n, buf)
if string(buf[:n]) == "request" {
_, _ = conn.Write([]byte("response"))
}
conn.Close()
}
func main() {
go client()
server()
}
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.