Skip to content

Commit

Permalink
remove the risk of file descriptor reuse from arping
Browse files Browse the repository at this point in the history
using sock.deinitialize() outside of the goroutine that is using the
socket leaves the potential for erroneous and unexpected behavior. When
calling Ping() very quickly the socket fd can be reused while a
goroutine is still trying to read from it and cause the goroutine to
deadlock.

Additionally removing the timeout from the select case because that
will/cannot work as intended. In linux close() does not cause system
calls using the socket to return. This contributes to the file
descriptor reuse issue mentioned above and with the defered
sock.deinitialize() can lead to double closing the socket.

Signed-off-by: Jacob Tanenbaum <[email protected]>
  • Loading branch information
JacobTanenbaum committed Feb 1, 2024
1 parent c50f431 commit 586e13f
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 4 deletions.
5 changes: 1 addition & 4 deletions arping.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ func PingOverIface(dstIP net.IP, iface net.Interface) (net.HardwareAddr, time.Du
if err != nil {
return nil, 0, err
}
defer sock.deinitialize()

type PingResult struct {
mac net.HardwareAddr
Expand All @@ -131,6 +130,7 @@ func PingOverIface(dstIP net.IP, iface net.Interface) (net.HardwareAddr, time.Du
pingResultChan := make(chan PingResult, 1)

go func() {
defer sock.deinitialize()
// send arp request
verboseLog.Printf("arping '%s' over interface: '%s' with address: '%s'\n", dstIP, iface.Name, srcIP)
if sendTime, err := sock.send(request); err != nil {
Expand Down Expand Up @@ -162,9 +162,6 @@ func PingOverIface(dstIP net.IP, iface net.Interface) (net.HardwareAddr, time.Du
select {
case pingResult := <-pingResultChan:
return pingResult.mac, pingResult.duration, pingResult.err
case <-time.After(timeout):
sock.deinitialize()
return nil, 0, ErrTimeout
}
}

Expand Down
3 changes: 3 additions & 0 deletions arping_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ func initialize(iface net.Interface) (s *LinuxSocket, err error) {
}

func (s *LinuxSocket) send(request arpDatagram) (time.Time, error) {
socketTimeout := timeout.Nanoseconds * 2
t := syscall.NsecToTimeval(socketTimeout)
syscall.SetsockoptTimeval(s.sock, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &t)
return time.Now(), syscall.Sendto(s.sock, request.MarshalWithEthernetHeader(), 0, &s.toSockaddr)
}

Expand Down

0 comments on commit 586e13f

Please sign in to comment.