How to set the source port when sending udp packets - go

On the client, I want to set the UDP source port when sending a udp packet.
On the server, I want to know what the UDP source port was received on.
Client:
package main
import (
"net"
)
func main() {
s, err := net.ResolveUDPAddr("udp4", "127.0.0.1:1234")
c, err := net.DialUDP("udp4", nil, s)
if err != nil {
fmt.Println(err)
return
}
}
Server:
package main
import (
"net"
"time"
)
func main() {
s, err := net.ResolveUDPAddr("udp4", "127.0.0.1:1234")
if err != nil {
fmt.Println(err)
return
}
connection, err := net.ListenUDP("udp4", s)
if err != nil {
fmt.Println(err)
return
}
}
In the above client code, is there a way for me to set the source port?
In the above server code, is there a way for me to know the source port used?

https://golang.org/pkg/net/#DialUDP
func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error)
Both laddr and raddr use UDPAddr struct, but you're not setting laddr.
laddr, err := net.ResolveUDPAddr("udp", "<source_int>:50000")
raddr := net.UDPAddr{IP: net.ParseIP("<dest>"), Port: 50000}
conn, err := net.DialUDP("udp", laddr, &raddr)

Related

How to measure RTT/latency through TCP clients (created in GoLang) from a TCP server created in GoLang?

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

How to extract the connected local ip address using http.Client in Go?

My PC has multiple IP addresses(ex: 10.1.1.20, 192.168.123.30, ...).
Can I extract the connected local ip address when connecting to remote server using http.Client?
If this is not possible with http.Client, is there any other possible way?
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://www.google.com", nil)
if err != nil {
panic(err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// extract the local ip address???
// getsockname(?????)
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Printf("StatusCode=%v\n", resp.StatusCode)
fmt.Printf("%v\n", string(data))
}
You can either:
loop through all network interfaces
or retrieve the preferred outbound ip address
But in both case, the fact that you are in the middle of using an http.Client and making a GET would not matter: you could get those IP addresses independently.
You can provide your own Transport implementation that extracts the outgoing local IP address right after establishing the TCP connection, e.g. like this:
client := &http.Client{
Transport: &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
conn, err := net.Dial(network, addr)
if err == nil {
localAddr := conn.LocalAddr().(*net.TCPAddr)
fmt.Println("LOCAL IP:", localAddr.IP)
}
return conn, err
},
},
}

Freeing a port before running a server instant

I want to run a go server at linux based system, it happened in soe cases that i found the same port is busy with another app, so i want to kill the running process at that port, and run my server instead, so I wrote the below code:
func main() {
host := "127.0.0.1"
port := "8070"
server := http.Server{
Addr: "127.0.0.1:8070",
}
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
ln, err := net.Listen("tcp", ":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
_, err := exec.Command("fuser", "-k", "8070/tcp").Output()
if err != nil {
fmt.Printf("Failed to kill process at Port %q\n", port)
} else {
fmt.Printf("TCP Port %q is available\n", port)
server.ListenAndServe()
}
} else {
ln.Close()
server.ListenAndServe()
}
}
I was able to get the response TCP Port 8070 is available whihc means there was another running process and it had been killed, but my app is closed directly without running my server at the same port which had been already closed!
hajsf#AIS-DM-YOUSEF-L:~/myapp$ go run myapp
Can't listen on port "8070": listen tcp :8070: bind: address already in use
TCP Port "8070" is available
hajsf#AIS-DM-YOUSEF-L:~/myapp$
In the origional terminal (the old instance of the app0 I got;
hajsf#AIS-DM-YOUSEF-L:~/myapp$ go run myapp
signal: killed
hajsf#AIS-DM-YOUSEF-L:~/myapp$
As you can see in the response How to kill a process running on particular port in Linux?
Your command _, err := exec.Command("fuser", "-k", "8070/tcp").Output() kill the process but doesn't cleanup the resource ie: port listening.
The port is put into TIME_WAIT state after the parent process is killed.
And you need to wait some time your OS/Kernel cleanup the port/socket
A better alternative is to handle the kill sigint from fuser and do a graceful shutdown
package main
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"time"
)
func runServer(host, port string) {
server := http.Server{
Addr: host + ":" + port,
}
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
go func() {
if err := server.ListenAndServe(); err != nil {
}
}()
// Setting up signal capturing
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
// Waiting for SIGINT (kill -2)
<-stop
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
// handle err
}
}
func main() {
host := "127.0.0.1"
port := "8070"
ln, err := net.Listen("tcp", host+":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
cmd := exec.Command("fuser", "-k", "-2", "8070/tcp")
fmt.Println("wait")
err = cmd.Run()
if err != nil {
fmt.Printf("Failed to kill process at Port %q\n", port)
} else {
fmt.Printf("TCP Port %q is available\n", port)
runServer(host, port)
}
} else {
ln.Close()
runServer(host, port)
}
}
worked well on CentOS 7, but same issue with a Ubuntu server. #MoiioM 's answer is fine. But if another app is not the golang app itself, here is another way: set a SO_REUSEADDR flag on the socket
package main
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/exec"
"syscall"
"golang.org/x/sys/unix"
)
func reusePort(network, address string, conn syscall.RawConn) error {
return conn.Control(func(descriptor uintptr) {
syscall.SetsockoptInt(int(descriptor), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
})
}
func main() {
port := "8070"
server := http.Server{}
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
ln, err := net.Listen("tcp", ":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
_, err := exec.Command("fuser", "-k", "8070/tcp").Output()
if err != nil {
fmt.Printf("Failed to kill process at Port %q\n", port)
} else {
fmt.Printf("TCP Port %q is available\n", port)
config := &net.ListenConfig{Control: reusePort}
listener, err := config.Listen(context.Background(), "tcp", ":"+port)
if err != nil {
panic(err)
}
if err := server.Serve(listener); err != nil {
panic(err)
}
}
} else {
if err := server.Serve(ln); err != nil {
panic(err)
}
}
}
I was able to solve it with panic ... recover as below:
package main
import (
"fmt"
"net"
"net/http"
"onsen/resources"
"onsen/routes"
"os"
"os/exec"
)
func main() {
http.Handle("/webUI/", http.StripPrefix("/webUI/", http.FileServer(http.FS(resources.WebUI))))
http.Handle("/www/", http.StripPrefix("/www/", http.FileServer(http.Dir("./www"))))
for key, value := range routes.Urls() {
http.HandleFunc(key, value)
}
runServer()
}
func runServer() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
runServer()
}
}()
host := "127.0.0.1"
port := "8070"
server := http.Server{
Addr: fmt.Sprintf("%v:%v", host, port),
}
ln, err := net.Listen("tcp", ":"+port)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s \n", port, err)
// kill the running process at this port
_, err := exec.Command("fuser", "-k", "8070/tcp").Output()
if err != nil {
panic(fmt.Sprintf("Failed to kill process at Port %q\n", port))
} else {
fmt.Printf("TCP Port %q is available\n", port)
fmt.Println("server started...")
if err := server.Serve(ln); err != nil {
panic(err)
}
}
} else {
fmt.Println("server started...")
if err := server.Serve(ln); err != nil {
panic(err)
}
}
}
And got the output as below:

How change the source ip address udp package to a fake ip in golang?

I need recive udp package and send their to broadcast address other interface.
I wrote udp forward server. Its work!
How change the source udp address new packages to src address income package?
package main
import (
"fmt"
"net"
"os"
)
func CheckError(err error) {
if err != nil {
fmt.Println("Error: " , err)
os.Exit(0)
}
}
func main() {
ServerAddr,err := net.ResolveUDPAddr("udp4",":10001")
CheckError(err)
LocalAddr, err := net.ResolveUDPAddr("udp4", "192.168.164.83:10001")
CheckError(err)
RemoteAddr, err := net.ResolveUDPAddr("udp4", "192.168.164.255:10002")
CheckError(err)
Conn, err := net.DialUDP("udp4", LocalAddr, RemoteAddr)
CheckError(err)
defer Conn.Close()
ServerConn, err := net.ListenUDP("udp4", ServerAddr)
CheckError(err)
defer ServerConn.Close()
buf := make([]byte, 2048)
for {
n,addr,err := ServerConn.ReadFromUDP(buf)
fmt.Println("Received ",n , "bytes from ",addr)
if err != nil {
fmt.Println("Error-recive: ",err)
} else {
go Conn.Write(buf[0:n])
}
}
}

bind: cannot assign requested address on UDPclient in local network

As I'm finding quite some examples how to write a go server and client, this works locally on one machine.
Now I'm trying to communicate in my local network between two PCs, one running the go server script, one the client.
However, I can't establish a connection because of the error:
Error: listen udp 192.168.11.6:10001: bind: cannot assign requested address
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x401376] // ...
Of course I will post my code (client, where the problem occurs):
package main
import (
"fmt"
"net"
"strconv"
"time"
)
func CheckError(err error) {
if err != nil {
fmt.Println("Error: ", err)
}
}
func main() {
ServerAddr, err := net.ResolveUDPAddr("udp", "192.168.11.6:10001")
CheckError(err)
Conn, err := net.ListenUDP("udp", ServerAddr)
CheckError(err)
defer Conn.Close()
i := 0
for {
msg := strconv.Itoa(i)
i++
buf := []byte(msg)
_, err = Conn.WriteToUDP(buf, ServerAddr)
time.Sleep(time.Second * 1)
}
}
Server:
package main
import (
"fmt"
"net"
"os"
)
/* A Simple function to verify error */
func CheckError(err error) {
if err != nil {
fmt.Println("Error: " , err)
os.Exit(0)
}
}
func main() {
ServerAddr,err := net.ResolveUDPAddr("udp",":10001")
CheckError(err)
ServerConn, err := net.ListenUDP("udp", ServerAddr)
CheckError(err)
defer ServerConn.Close()
buf := make([]byte, 1024)
for {
fmt.Println("Starting...")
n,addr,err := ServerConn.ReadFromUDP(buf)
fmt.Println("Received ",string(buf[0:n]), " from ",addr)
ServerConn.WriteToUDP([]byte("hello there!"), addr)
if err != nil {
fmt.Println("Error: ",err)
}
}
}
The client has the local network IP address 192.168.11.8 and the server 192.168.11.6. They can also ping each other, and I'm opening the port when Windows asks for it.
I'm happy about all suggestions. I struggle with this because I only find localhost server client go examples.
Okay, I figured it out. Weird that I had to allow the app to communicate on public networks? While I am on my home network. When starting the server - I had to enable public networks
I figured out that I do not have to open a socket on the client side, but use DialUDP
Also the server needed the full Ip address in
ServerAddr,err := net.ResolveUDPAddr("udp","192.168.11.6:10001")
Improved Client code: (main func)
ServerAddr, err := net.ResolveUDPAddr("udp", "192.168.11.6:10001")
CheckError(err)
buf := make([]byte, 1024)
Conn, err := net.DialUDP("udp", nil, ServerAddr)
CheckError(err)
defer Conn.Close()
i := 0
for {
msg := strconv.Itoa(i)
i++
fmt.Printf(msg)
n, err := Conn.Write([]byte(msg))
CheckError(err)
fmt.Printf("sent %d bytes", n)
n, addr, err := Conn.ReadFromUDP(buf)
if err == nil {
fmt.Printf("%s %s\n", buf, addr)
} else {
fmt.Printf("some err %v\n", err)
}
time.Sleep(time.Second * 1)
}

Resources