Unable to use quic.Dial/DialAddr on arm64
Hello, I have the following code that works fine on amd64. It basically sends some datagrams over the network. I'm able to send the datagrams from the client and receive them at the server.
quic_go_client/main.go
package main
import (
"context"
"crypto/ed25519"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"log"
"math/big"
"net"
"os"
"sync"
"strconv"
"time"
"github.com/quic-go/quic-go"
)
var host string;
var port int;
var debug bool;
var numeric bool
const PacketLength = 1200
func Usage() {
fmt.Printf("Usage: %s port\n", os.Args[0])
flag.PrintDefaults()
}
func main() {
flag.StringVar(&host, "host", "", "Specify hostname, if none specified, will run as server")
flag.IntVar(&port, "port", 55678, "Port number to connect to, or to start server on")
flag.BoolVar(&numeric, "num", false, "Numeric only IP daddress, no DNS lookup")
flag.BoolVar(&debug, "debug", false, "Print debug info")
flag.Parse()
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
wg := sync.WaitGroup{}
wg.Add(1)
if (host =="") {
go func() {
log.Fatal(echoServer())
}()
} else {
go func() {
log.Fatal(throughputClient())
}()
}
wg.Wait()
}
// Setup a bare-bones TLS config for the server
func generateTLSConfig() *tls.Config {
_, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
template := x509.Certificate{SerialNumber: big.NewInt(1)}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv)
if err != nil {
panic(err)
}
return &tls.Config{
Certificates: []tls.Certificate{{
Certificate: [][]byte{certDER},
PrivateKey: priv,
}},
NextProtos: []string{"quic-echo-example"},
}
}
func generateQuicConfig() *quic.Config {
return &quic.Config{
EnableDatagrams: true,
KeepAlivePeriod: time.Second,
}
}
func echoServer() error {
fmt.Printf("Setting up server on port: %s\n", port)
udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: port})
tr := quic.Transport{
Conn: udpConn,
}
// listener, err := quic.ListenAddr("0.0.0.0:" + port , generateTLSConfig(), generateQuicConfig())
if err != nil {
fmt.Println("Error here1")
return err
}
for true {
log.Println("Starting up server")
listener, err := tr.Listen(generateTLSConfig(), generateQuicConfig())
conn, err := listener.Accept(context.Background())
if err != nil {
fmt.Println("Error here2")
return err
}
log.Println("Trying to send test Datagram")
err = conn.SendDatagram([]byte("HELLO"))
currentItr := 0
lastItr := 0
refEpoch := time.Now().Unix()
packetCount := 0
for true {
msg, err := conn.ReceiveDatagram(context.Background())
if err != nil {
fmt.Println("Error here3")
break
}
// fmt.Printf("length of message received: %d\n",len(msg))
currentItr +=len(msg)
packetCount += 1
if debug {
log.Println("Recv Packet Count: " , packetCount)
log.Println("Recv Total Bytes: " , currentItr)
}
if time.Now().Unix() >refEpoch {
log.Println("Recv Throughput: " + strconv.Itoa(currentItr - lastItr) + " bytes")
lastItr = currentItr
refEpoch = time.Now().Unix()
}
//fmt.Printf("Message recevied: %s\n", msg)
// Echo through the loggingWriter
// _, err = io.Copy(loggingWriter{stream}, stream)
}
log.Println("Total Recv Bytes: ", currentItr)
listener.Close()
}
return nil
}
func throughputClient() error {
tlsConf := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"quic-echo-example"},
}
//Creating a large buffer of random data
var conn *quic.Conn
var err error
log.Println("Creating random data")
data := make([]byte, 1024 *10)
_, err = rand.Read(data)
if err != nil {
return err
}
log.Println("Creating connection with server")
if !numeric {
conn, err = quic.DialAddr(context.Background(), host + ":"+strconv.Itoa(port) , tlsConf, generateQuicConfig())
if err != nil {
return err
}
} else {
//udpServerConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: ip, Port: port})
serverAddr, err := net.ResolveUDPAddr("udp4",host+":"+strconv.Itoa(port))
if err != nil {
log.Println("Error resolving serverAddr")
return err
}
log.Println("serverAddr: ", serverAddr)
udpClientConn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: port})
if err!= nil {
log.Println("Error creating udpClientConn")
return err
}
conn, err = quic.Dial(context.Background(), udpClientConn, serverAddr, tlsConf, generateQuicConfig())
if err!=nil {
log.Println("Error running quic.Dial")
return err
}
}
log.Println("QUIC connection made")
currentItr := 0
lastItr := 0
packetCount := 0
refEpoch := time.Now().Unix()
sendData := make([]byte, PacketLength)
for currentItr < len(data) {
if len(data) >= (currentItr + PacketLength) {
copy(data[currentItr:currentItr+PacketLength], sendData)
currentItr += PacketLength
} else {
copy(data[currentItr:len(data)], sendData)
currentItr = len(data)
}
err = conn.SendDatagram([]byte(sendData))
if err != nil {
return err
}
packetCount += 1
if debug {
log.Println("Send Packet Count: ", packetCount)
log.Println("Send Total Bytes: " , currentItr)
}
if time.Now().Unix() >refEpoch {
log.Println("Send Throughput: " + strconv.Itoa(currentItr - lastItr) + " bytes")
lastItr = currentItr
refEpoch = time.Now().Unix()
}
}
log.Println("Data send complete")
log.Println("Sleeping for a second")
time.Sleep(time.Second)
defer conn.CloseWithError(0, "Connection closed")
return nil
}
However, I'm having trouble running the same code on arm64. I'm using go v1.25.1 and quic-go v0.54 I see no UDP traffic being output from the node. Using QUIC_GO_LOG_LEVEL=DEBUG, I see the following output at the client:
Client Output
root@abc:/tmp/quic_go_client# QUIC_GO_LOG_LEVEL=DEBUG ./quic_go_unreliable_app -host 10.0.0.23
2025/09/09 16:29:07.804217 Creating random data
2025/09/09 16:29:07.805173 Creating connection with server
2025/09/09 16:29:07.805737 Conn has receive buffer of 10240 kiB (wanted: at least 7168 kiB)
2025/09/09 16:29:07.805803 Conn has send buffer of 10240 kiB (wanted: at least 7168 kiB)
2025/09/09 16:29:07.805857 Setting DF for IPv4 and IPv6.
2025/09/09 16:29:07.805929 Activating reading of ECN bits for IPv4 and IPv6.
2025/09/09 16:29:07.805946 Activating reading of packet info for IPv4 and IPv6.
2025/09/09 16:29:07.806115 client Starting new connection to 10.0.0.23 ([::]:44854 -> 10.0.0.23:55678), source connection ID (empty), destination connection ID 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, version v1
2025/09/09 16:29:07.810539 client Not doing 0-RTT. Has sealer: false, has params: false
2025/09/09 16:29:07.810866 client -> Sending packet 0 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:07.810927 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 0, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:07.810989 client -> &wire.CryptoFrame{Offset: 0, Data length: 1229, Offset + Data length: 1229}
2025/09/09 16:29:07.811078 client -> Sending packet 1 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:07.811119 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 1, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:07.811228 client -> &wire.CryptoFrame{Offset: 1229, Data length: 274, Offset + Data length: 1503}
2025/09/09 16:29:08.011860 client Loss detection alarm for Initial fired in PTO mode. PTO count: 1
2025/09/09 16:29:08.012001 client -> Sending packet 2 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:08.012043 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 2, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:08.012170 client -> &wire.CryptoFrame{Offset: 0, Data length: 1229, Offset + Data length: 1229}
2025/09/09 16:29:08.012272 client -> Sending packet 3 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:08.012333 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 3, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:08.012364 client -> &wire.CryptoFrame{Offset: 1229, Data length: 274, Offset + Data length: 1503}
2025/09/09 16:29:08.412612 client Loss detection alarm for Initial fired in PTO mode. PTO count: 2
2025/09/09 16:29:08.412715 client Sending a keep-alive PING to keep the connection alive.
2025/09/09 16:29:08.412801 client -> Sending packet 4 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:08.412879 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 4, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:08.412978 client -> &wire.CryptoFrame{Offset: 0, Data length: 1229, Offset + Data length: 1229}
2025/09/09 16:29:08.413088 client -> Sending packet 5 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:08.413115 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 5, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:08.413152 client -> &wire.CryptoFrame{Offset: 1229, Data length: 274, Offset + Data length: 1503}
2025/09/09 16:29:09.213294 client Loss detection alarm for Initial fired in PTO mode. PTO count: 3
2025/09/09 16:29:09.213532 client -> Sending packet 6 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:09.213634 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 6, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:09.213754 client -> &wire.CryptoFrame{Offset: 0, Data length: 1229, Offset + Data length: 1229}
2025/09/09 16:29:09.213898 client -> Sending packet 7 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:09.213932 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 7, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:09.213991 client -> &wire.CryptoFrame{Offset: 1229, Data length: 274, Offset + Data length: 1503}
2025/09/09 16:29:10.813883 client Loss detection alarm for Initial fired in PTO mode. PTO count: 4
2025/09/09 16:29:10.814066 client -> Sending packet 8 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:10.814159 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 8, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:10.814301 client -> &wire.CryptoFrame{Offset: 0, Data length: 1229, Offset + Data length: 1229}
2025/09/09 16:29:10.814380 client -> Sending packet 9 (1280 bytes) for connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, Initial
2025/09/09 16:29:10.814403 client Long Header{Type: Initial, DestConnectionID: 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9, SrcConnectionID: (empty), Token: (empty), PacketNumber: 9, PacketNumberLen: 2, Length: 1251, Version: v1}
2025/09/09 16:29:10.814442 client -> &wire.CryptoFrame{Offset: 1229, Data length: 274, Offset + Data length: 1503}
2025/09/09 16:29:12.812055 client Destroying connection: timeout: no recent network activity
2025/09/09 16:29:12.812180 Removing connection ID (empty).
2025/09/09 16:29:12.812220 client Connection 4e01522fa7e1d83f959e2bf2a61b4dcb92fab9 closed.
2025/09/09 16:29:12.814191 timeout: no recent network activity
Using tcpdump -i eth0 dst 10.0.0.23 and udp and port 55678 at the sender, I see no output. Just to check if there was some issue with golang and UDP traffic in general, I do see the following code generating UDP traffic on the wire:
udpexample/main.go
package main
import (
"fmt"
"net"
"bufio"
)
func main() {
p := make([]byte, 2048)
conn, err := net.Dial("udp", "10.0.0.23:55678")
if err != nil {
fmt.Printf("Some error %v", err)
return
}
fmt.Fprintf(conn, "Hi UDP Server, How are you doing?")
_, err = bufio.NewReader(conn).Read(p)
if err == nil {
fmt.Printf("%s\n", p)
} else {
fmt.Printf("Some error %v\n", err)
}
conn.Close()
}
The tcpdump output at the sender while running this example:
root@abc:~# tcpdump -i eth0 dst 10.0.0.23 and udp and port 55678
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:55:03.082255 IP 10.0.0.35.55004 > 10.0.0.23.55678: UDP, length 33
I've tried building the applications using:
GOOS=linux GOARCH=arm64 go buildCGO_ENABLED=1 CC=<path to arm64 cross compiler> GOOS=linux GOARCH=arm64 go build- Using arm64 version of go1.25.1 and building the applications on the nodes themselves
There has been no change in the output. I will really appreciate any pointers in debugging this.
Thanks,
This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.