TCP Listener is not shut down completely - go

I have a TCP Listener that initialized as next:
myListener := net.Listen("tcp", addr)
Then am able to receive connections and process them. Then I need to close the server in order that I can reuse the same port but this is not happening, this is how am closing the tcp server:
myListener.Close()
In the client side am closing all the existent TCP connections to that server and then from the terminal I see that those connections are being close but the port is still in use by the server and listening (even when is not accepting new connections which is right according to documentation). This is how I check in the terminal:
netstat -an | grep 8080
And after close the client side connections I get this and cannot reuse the port:
tcp46 0 0 *.8080 *.* LISTEN
After doing myListener.Close() I waited some time but in the terminal the port is still in use.

In addition to checking the error from the net.Listener as stated in https://stackoverflow.com/a/65638937/1435495
You will also want to add a defer to your myListener.Close() will help ensure that the close does actually execute even if something would cause the app to exit prematurely.
defer myListener.Close()

The net.Listen function returns two parameters (Listener, error), in your example above you appear to only be capturing the Listener and not the error.
Assuming you're actually capturing it, you should check if the error is empty before you begin using the listener.
package main
import "net"
func main() {
myListener, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
myListener.Close()
}
Something similar to the snippet above should work. Now if you're not getting an error (I presume you will get an error), the problem you likely have is that something else is already using that port.
Try running your netstat as root so you can see all processes which will give you a better idea of what is holding on to that port.
sudo netstat -apn | grep -i listen | grep 8080

Related

How can I get HTTP RPC Server and client to work?

I am trying to send messages from client to server and back using the exact HTTP RPC server/client code given here.
However, when I run the server, my command line becomes blank because the server starts listening using:
err := http.ListenAndServe(":1234", nil)
if err != nil {
fmt.Println(err.Error())
}
In the client code, I need to get an argument from the command line for client to run:
serverAddress := os.Args[1]
However, this argument is not available because the server code makes my command line blank.
How can I get the server and client to work on the same command line window?

Go net.DialUDP auto-selecting loopback interface

I have a need to send some UDP packets from eth0 on a host to itself, also on eth0.
I have some working Go code, but it appears to be using the loopback interface instead of eth0 as expected.
package main
import (
"net"
)
func main() {
ip := net.ParseIP("192.168.1.158")
src := net.UDPAddr{IP: ip, Port: 8888,}
dest := net.UDPAddr{IP: ip, Port: 88}
conn, _ := net.DialUDP("udp", &src, &dest)
conn.Write([]byte("hi"))
}
192.168.1.158 is the primary and only IP address for the interface on my machine.
Running the following command shows me the traffic:
sudo tcpdump udp -v -i lo
However, I would expect the traffic be to/from the system interface with the IP address I've defined.
Am I missing a step here?
I have also tried this slightly different approach, but with the same results:
src, _ := net.ResolveUDPAddr("udp", "192.168.1.158:8888")
dest, _ := net.ResolveUDPAddr("udp", "192.168.1.158:88")
However, I would expect the traffic be to/from the system interface with the IP address I've defined.
This is simply the wrong expectation and unrelated to Go.
Just try ping 192.168.1.158 and check with tcpdump -i lo -n icmp vs. tcpdump -i eth0 -n icmp where the data actually gets transferred. You will see that the packets are transferred on the lo interface. Similar a ip route get 192.168.1.158 will show you that the route to your local address goes through the lo interface.

Why does http.Get("http://[::]:1234") work?

I was writing a test where I wanted an HTTP server to listen on a random port and then connect to this port. I wrote:
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("foo")
})
listener, err := net.Listen("tcp", ":0")
fmt.Println(err)
httpServer := &http.Server{Handler: mux}
go httpServer.Serve(listener)
fmt.Println("http://" + listener.Addr().String())
r, err := http.Get("http://" + listener.Addr().String())
fmt.Println(r)
fmt.Println(err)
I meant to write net.Listen("tcp", "127.0.0.1:0") but accidentally wrote net.Listen("tcp", ":0").
For "http://" + listener.Addr().String() it prints:
http://[::]:1709
where as far as I understand the "bracket colon colon bracket" means "all interfaces".
To my surprise, the http.Get("http://[::]:1709") works, it connects to the webserver and "foo" is printed.
How is "http://[::]:1709" a valid address?
At least on a Linux system, this results in a connection being made to localhost.
The address :: is IN6ADDR_ANY, typically used when listening to listen for connections to any IPv6 address on the system. It's analogous to INADDR_ANY, also known as 0.0.0.0 in IPv4.
Occasionally someone attempts to use one of these addresses as the destination address for an outgoing connection. When this happens:
When making an outgoing connection to 0.0.0.0, Linux actually connects from 127.0.0.1 to 127.0.0.1.
Similarly, when making an outgoing connection to ::, Linux actually connects from ::1 to ::1. Here is an example, taken from one of my websites (which happens to be an IP address lookup tool):
[error#murloc ~]$ curl -k -H "Host: myip.addr.space" https://[::]:8443/
::1
For completeness, here is the IPv4 version:
[error#murloc ~]$ curl -k -H "Host: myip.addr.space" https://0.0.0.0:8443/
127.0.0.1
Note that this is OS-specific. You would have received an error on Windows.

go-ping library for unprivileged ICMP ping in golang

I have been using go-ping library for the unprivileged ping and calculate various statistics of network in golang.
code snippet is as->
func (p *Ping) doPing() (latency, jitter, packetLoss float64, err error) {
timeout := time.Second*1000
interval := time.Second
count := 5
host := p.ipAddr
pinger, cmdErr := ping.NewPinger(host)
if cmdErr != nil {
glog.Error("Failed to ping " + p.ipAddr)
err = cmdErr
return
}
pinger.Count = count
pinger.Interval = interval
pinger.Timeout = timeout
pinger.SetPrivileged(false)
pinger.Run()
stats := pinger.Statistics()
latency = float64(stats.AvgRtt)
jitter = float64(stats.StdDevRtt)
packetLoss = stats.PacketLoss
return
}
It was working fine but now it has started throwing :-
"Error listening for ICMP packets: socket: permission denied" error.
Anyone knows the reason behind this? Go version I am using is go1.7.4.
This is in the README.md of the library you're using :
This library attempts to send an "unprivileged" ping via UDP. On linux, this must be enabled by setting
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
If you do not wish to do this, you can set pinger.SetPrivileged(true) and use setcap to allow your binary using go-ping to bind to raw sockets (or just run as super-user):
setcap cap_net_raw=+ep /bin/goping-binary
See this blog and the Go icmp library for more details.
Hope it helps !
Make sure your setting haven't changed in any way. Using ping from the package still works for me on a 32-bit Ubuntu 16.04 with Go 1.7.4 (linux/386) if I previousely set the net.ipv4.ping_group_range according to the instructions on Github.
Note on Linux Support:
This library attempts to send an "unprivileged" ping via UDP. On linux, this must be enabled by setting
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
If you do not wish to do this, you can set pinger.SetPrivileged(true) and use setcap to allow your binary
using go-ping to bind to raw sockets (or just run as super-user):
setcap cap_net_raw=+ep /bin/goping-binary
See this blog
and the Go icmp library for
more details.

Faking a FTP service

I am writing a piece of software which can fool Nmap into believing that GuildFTPd FTP Server is running on port 21. My python code so far looks like this:
import socket
s = socket.socket( )
s.bind(('', 21))
s.listen(1)
conn, addr = s.accept()
conn.send("220-GuildFTPd FTP Server (c) 1997-2002\r\n220-Version 0.999.14")
conn.close()
The Nmap regexp for matching this particular service is:
match ftp m|^220-GuildFTPd FTP Server \(c\) \d\d\d\d(-\d\d\d\d)?\r\n220-Version (\d[-.\w]+)\r\n| p/Guild ftpd/ v/$2/ o/Windows/
However when I scan the host which is running the script with Nmap the results are:
21/tcp open ftp?
How can this be? When I scan the real service with Nmap it identifies the service correctly.
First, you're missing a \r\n at the end of your fake response that the match line needs.
The other major issue is that your program only handles one connection, then closes. Nmap will first do a port scan, then send service fingerprinting probes. If you ran nmap as root (or Administrator on Windows), it would use a half-open TCP SYN scan, and your application wouldn't see the portscan as a connection, but otherwise it will accept the portscan, close the connection, and be unavailable for the service scan phase.
Here's a very basic adaptation of your script that can handle sequential connections (but not parallel), which is enough to fool Nmap:
import socket
s = socket.socket( )
s.bind(('', 21))
s.listen(1)
while True:
conn, addr = s.accept()
conn.send("220-GuildFTPd FTP Server (c) 1997-2002\r\n220-Version 0.999.14\r\n")
conn.close()

Resources