Skip to content

Commit

Permalink
Fix panic when running ICMPv4 probe with DontFragment
Browse files Browse the repository at this point in the history
A recent change modified the way an IPv4 raw socket is created and BBE
is panicing when ICMPv4 is used with DontFragment set.

golang.org/x/net doesn't seem to have a way to create the necessary
socket, so fall back to the previous method for that case in particular
(ICMP, IPv4, DontFragment=true).

Fixes #685

Signed-off-by: Marcelo E. Magallon <marcelo.magallon@grafana.com>
  • Loading branch information
mem committed Aug 27, 2020
1 parent 7913a15 commit 97dff69
Showing 1 changed file with 27 additions and 21 deletions.
48 changes: 27 additions & 21 deletions prober/icmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr
setupStart := time.Now()
level.Info(logger).Log("msg", "Creating socket")

unprivileged := false
privileged := true
// Unprivileged sockets are supported on Darwin and Linux only.
tryUnprivileged := runtime.GOOS == "darwin" || runtime.GOOS == "linux"

Expand All @@ -119,11 +119,11 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr
if err != nil {
level.Debug(logger).Log("msg", "Unable to do unprivileged listen on socket, will attempt privileged", "err", err)
} else {
unprivileged = true
privileged = false
}
}

if !unprivileged {
if privileged {
icmpConn, err = icmp.ListenPacket("ip6:ipv6-icmp", srcIP.String())
if err != nil {
level.Error(logger).Log("msg", "Error listening to socket", "err", err)
Expand All @@ -140,42 +140,48 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr
srcIP = net.ParseIP("0.0.0.0")
}

var icmpConn *icmp.PacketConn
// If the user has set the don't fragment option we cannot use unprivileged
// sockets as it is not possible to set IP header level options.
if tryUnprivileged && !module.ICMP.DontFragment {
icmpConn, err = icmp.ListenPacket("udp4", srcIP.String())
if err != nil {
level.Debug(logger).Log("msg", "Unable to do unprivileged listen on socket, will attempt privileged", "err", err)
} else {
unprivileged = true
}
}

if !unprivileged {
icmpConn, err = icmp.ListenPacket("ip4:icmp", srcIP.String())
if module.ICMP.DontFragment {
icmpConn, err := net.ListenPacket("ip4:icmp", srcIP.String())
if err != nil {
level.Error(logger).Log("msg", "Error listening to socket", "err", err)
return
}
}

if module.ICMP.DontFragment {
rc, err := ipv4.NewRawConn(icmpConn)
if err != nil {
level.Error(logger).Log("msg", "Error creating raw connection", "err", err)
return
}
socket = &v4Conn{c: rc, df: true}
} else {
var icmpConn *icmp.PacketConn
// If the user has set the don't fragment option we cannot use unprivileged
// sockets as it is not possible to set IP header level options.
if tryUnprivileged {
icmpConn, err = icmp.ListenPacket("udp4", srcIP.String())
if err != nil {
level.Debug(logger).Log("msg", "Unable to do unprivileged listen on socket, will attempt privileged", "err", err)
} else {
privileged = false
}
}

if privileged {
icmpConn, err = icmp.ListenPacket("ip4:icmp", srcIP.String())
if err != nil {
level.Error(logger).Log("msg", "Error listening to socket", "err", err)
return
}
}

socket = icmpConn
}
}

defer socket.Close()

var dst net.Addr = ip
if unprivileged {
if !privileged {
dst = &net.UDPAddr{IP: ip.IP, Zone: ip.Zone}
}

Expand Down Expand Up @@ -217,7 +223,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr
// unprivileged sockets were used and the kernel used its own.
wm.Type = replyType
// Unprivileged cannot set IDs on Linux.
idUnknown := unprivileged && runtime.GOOS == "linux"
idUnknown := !privileged && runtime.GOOS == "linux"
if idUnknown {
body.ID = 0
}
Expand Down

0 comments on commit 97dff69

Please sign in to comment.