go-ping library for unprivileged ICMP ping in golang - go

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.

Related

Why won't the socket open in bulk at once?

OSX socket programming
Why won't the socket open in bulk at once?
I am using Intel macOS Big Sur 11.5.1
The connection test is being conducted with the local docker nginx server.
We are using Golang to conduct tests with the following codes:
func TestBulkConnection(t *testing.T) {
var worker = 1000
var wg sync.WaitGroup
for i := 0; i < worker; i++ {
wg.Add(1)
//time.Sleep(time.Millisecond * 10)
go func(id int) {
conn, err := net.Dial("tcp", "localhost:9000")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
defer wg.Done()
fmt.Println("waiting... ", id)
time.Sleep(time.Second * 30)
}(i)
}
wg.Wait()
}
1000 goroutine connecting to nginx only.
After the connection, the sleep() function was used to make sure that nothing was done.
The client created 1000 goroutines, but found that only 200 to 300 nginx and connections worked and the rest did not (we confirmed with netstat-anv | grep 9000).
When connecting, it was confirmed that all connections are well established when the sleep() function is executed.
With nginx and client code, when spun from private ubuntu 18.04, the connection was confirmed at once.
I think it's a problem on the nginx server side, but I don't know the cause of the problem.
Is there a difference between Mac and Ubuntu in this test?
Added
let net = require('net');
for (let i = 0; i < 1000; i++) {
const socket = net.connect({ port: 9000 });
socket.on('connect', function () {
console.log('connected to server!');
});
}
netstat -anv | grep 9000 | wc -l
2000 connection ok
Added
The following links are used to increase the file descriptors of OSX.
https://wilsonmar.github.io/maximum-limits/
In recovery mode, 'csrutil disable' was also executed.
$ ulimit -a
-t: cpu time (seconds) unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) unlimited
-s: stack size (kbytes) 8192
-c: core file size (blocks) 0
-v: address space (kbytes) unlimited
-l: locked-in-memory size (kbytes) unlimited
-u: processes 2048
-n: file descriptors 524288
But still.
$ netstat -anv | grep 9000 | wc -l
287
Every unix based OS has limits on the number of file descriptors a process can open. Also, every socket consumes a file descriptor, just like opening a file on disk or your stdin, stdout & stderr.
MacOS by default sets the limit of file descriptors to 256 per process. Therefore your statement that your Go process stops at around 200-300 connections sounds right. In theory it should stop being able to open sockets after 253 connections (3 file descriptors already assigned to stdin, stdout & stderr).
Ubuntu on the other hand sets the default limit to 1024. You will still have this issue on Ubuntu but it will be able to open more sockets before you hit the wall.
On both systems you can check this limit by running the following command:
ulimit -n
Note: you can run ulimit -a to see all the limits.
On MacOS you can change this limit temporarily system-wide (it will reset after reboot) with the following command:
sudo launchctl limit maxfiles 1024 1024
On Ubuntu you can change this limit in your current shell with the following command:
ulimit -n 1024
This should let your 1000 connections to succeed. Note that the number does not have to be powers of 2. You can pass 1500 for example. Just remember that your process use file descriptors for things other than sockets.

TCP Listener is not shut down completely

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

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.

golang exec incorrect behavior

I'm using following code segment to get the XML definition of a virtual machine running on XEN Hypervisor. The code is trying to execute the command virsh dumpxml Ubutnu14 which will give the XML of the VM named Ubuntu14
virshCmd := exec.Command("virsh", "dumpxml", "Ubuntu14")
var virshCmdOutput bytes.Buffer
var stderr bytes.Buffer
virshCmd.Stdout = &virshCmdOutput
virshCmd.Stderr = &stderr
err := virshCmd.Run()
if err != nil {
fmt.Println(err)
fmt.Println(stderr.String())
}
fmt.Println(virshCmdOutput.String())
This code always goes into the error condition for the given domain name and I get the following output.
exit status 1
error: failed to get domain 'Ubuntu14'
error: Domain not found: no domain with matching name 'Ubuntu14'
But if I run the standalone command virsh dumpxml Ubuntu14, I get the correct XML definition.
I would appreciate if someone could give me some hints on what I'm doing wrong. My host machine is Ubuntu-16.04 and golang version is go1.6.2 linux/amd64
I expect you are running virsh as a different user in these two scenarios, and since you don't provide any URI, it is connecting to a different libvirtd instance. If you run virsh as non-root, then it'll usually connect to qemu:///session, but if you run virsh as root, then it'll usually connect to qemu:///system. VMs registered against one URI, will not be visible when connecting to the other URI.
BTW, if you're using go, you'd be much better off using the native Go library bindings for libvirt instead of exec'ing virsh. Your "virsh dumpxml" invokation is pretty much equivalent to this:
import (
"github.com/libvirt/libvirt-go"
)
conn, err := libvirt.NewConnect("qemu:///system")
dom, err := conn.LookupDomainByName("Ubuntu14")
xml, err := dom.GetXMLDesc(0)
(obviously do error handling too)

Scapy Sniffer - Receiving RSSI

I am interested in getting the RSSI values if APs using a scapy sniffer. I am using sig_str = -(256-ord(packet.notdecoded[-4:-3]))
to get the RSSI values. However, I am getting -256 for all the APs. The notdecoded part is then 0. Could someone please help me figure this one out?
PS: I have already referenced this relevant post.
https://stackoverflow.com/a/34118234/4804221
TIA!
Prerequisite
Assuming the interface is in monitor mode, and correct channel assigned.
Following example configures iface=wlan0 to monitor mode and listens to channel=6
$ sudo ip link set wlan0 down
$ sudo iw dev wlan0 set type monitor
$ sudo ip link set wlan0 up
$ sudo iw dev wlan0 set channel 6
Python3
RSSI from a packet can be earned by dBm_AntSignal if RadioTap header is correctly sniffed together.
from scapy.all import RadioTap
from scapy.all import sniff
# sniff a packet from the interface
pkt = sniff(iface="wlan0", count=1)
pkt = pkt[0]
# getting the RSSI
radiotap = pkt.getlayer(RadioTap)
rssi = radiotap.dBm_AntSignal
print("RSSI={}".format(rssi)) # RSSI=-84
Python2
Seems like dBm_AntSignal is not working on python2 scapy, following example will work.
extra = pkt.notdecoded
rssi = -(256-ord(extra[-4:-3]))
Hope this helps.

Resources