Merge pull request #687 from MikeZappa87/issue/588/removegArp
Replace arping package with arp_notify
This commit is contained in:
commit
186edecd6c
1
go.mod
1
go.mod
@ -13,7 +13,6 @@ require (
|
||||
github.com/d2g/dhcp4client v1.0.0
|
||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5
|
||||
github.com/godbus/dbus/v5 v5.0.4
|
||||
github.com/j-keck/arping v1.0.2
|
||||
github.com/mattn/go-shellwords v1.0.12
|
||||
github.com/networkplumbing/go-nft v0.2.0
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
|
4
go.sum
4
go.sum
@ -178,8 +178,6 @@ github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNR
|
||||
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v1.0.0 h1:9VJe1a5uKtdeJIHC/UvbTweracOh6GafT0nfbEGVcQ0=
|
||||
github.com/containernetworking/cni v1.0.0/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
|
||||
github.com/containernetworking/cni v1.0.1 h1:9OIL/sZmMYDBe+G8svzILAlulUpaDTUjeAbtH/JNLBo=
|
||||
github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
|
||||
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
|
||||
@ -375,8 +373,6 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
|
||||
github.com/j-keck/arping v1.0.2 h1:hlLhuXgQkzIJTZuhMigvG/CuSkaspeaD9hRDk2zuiMI=
|
||||
github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
|
@ -36,9 +36,8 @@ var (
|
||||
func makeVethPair(name, peer string, mtu int, mac string, hostNS ns.NetNS) (netlink.Link, error) {
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: name,
|
||||
Flags: net.FlagUp,
|
||||
MTU: mtu,
|
||||
Name: name,
|
||||
MTU: mtu,
|
||||
},
|
||||
PeerName: peer,
|
||||
PeerNamespace: netlink.NsFd(int(hostNS.Fd())),
|
||||
@ -146,10 +145,6 @@ func SetupVethWithName(contVethName, hostVethName string, mtu int, contVethMac s
|
||||
return net.Interface{}, net.Interface{}, err
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetUp(contVeth); err != nil {
|
||||
return net.Interface{}, net.Interface{}, fmt.Errorf("failed to set %q up: %v", contVethName, err)
|
||||
}
|
||||
|
||||
var hostVeth netlink.Link
|
||||
err = hostNS.Do(func(_ ns.NetNS) error {
|
||||
hostVeth, err = netlink.LinkByName(hostVethName)
|
||||
|
@ -43,10 +43,6 @@ func ConfigureIface(ifName string, res *current.Result) error {
|
||||
return fmt.Errorf("failed to lookup %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
if err := netlink.LinkSetUp(link); err != nil {
|
||||
return fmt.Errorf("failed to set %q UP: %v", ifName, err)
|
||||
}
|
||||
|
||||
var v4gw, v6gw net.IP
|
||||
var has_enabled_ipv6 bool = false
|
||||
for _, ipc := range res.IPs {
|
||||
@ -99,6 +95,10 @@ func ConfigureIface(ifName string, res *current.Result) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := netlink.LinkSetUp(link); err != nil {
|
||||
return fmt.Errorf("failed to set %q UP: %v", ifName, err)
|
||||
}
|
||||
|
||||
if v6gw != nil {
|
||||
ip.SettleAddresses(ifName, 10)
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/j-keck/arping"
|
||||
"github.com/vishvananda/netlink"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
@ -324,6 +323,11 @@ func ensureVlanInterface(br *netlink.Bridge, vlanId int) (netlink.Link, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to lookup %q: %v", brGatewayIface.Name, err)
|
||||
}
|
||||
|
||||
err = netlink.LinkSetUp(brGatewayVeth)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to up %q: %v", brGatewayIface.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return brGatewayVeth, nil
|
||||
@ -524,6 +528,8 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
|
||||
|
||||
// Add the IP to the interface
|
||||
if err := ipam.ConfigureIface(args.IfName, result); err != nil {
|
||||
return err
|
||||
@ -551,23 +557,6 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Send a gratuitous arp
|
||||
if err := netns.Do(func(_ ns.NetNS) error {
|
||||
contVeth, err := net.InterfaceByName(args.IfName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ipc := range result.IPs {
|
||||
if ipc.Address.IP.To4() != nil {
|
||||
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.IsGW {
|
||||
var firstV4Addr net.IP
|
||||
var vlanInterface *current.Interface
|
||||
@ -618,6 +607,20 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := netns.Do(func(_ ns.NetNS) error {
|
||||
link, err := netlink.LinkByName(args.IfName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve link: %v", err)
|
||||
}
|
||||
// If layer 2 we still need to set the container veth to up
|
||||
if err = netlink.LinkSetUp(link); err != nil {
|
||||
return fmt.Errorf("failed to set %q up: %v", args.IfName, err)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Refetch the bridge since its MAC address may change when the first
|
||||
|
@ -28,8 +28,8 @@ import (
|
||||
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/containernetworking/cni/pkg/types/040"
|
||||
"github.com/containernetworking/cni/pkg/types/100"
|
||||
types040 "github.com/containernetworking/cni/pkg/types/040"
|
||||
types100 "github.com/containernetworking/cni/pkg/types/100"
|
||||
"github.com/containernetworking/plugins/pkg/ip"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/containernetworking/plugins/pkg/testutils"
|
||||
|
@ -18,10 +18,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
|
||||
"github.com/j-keck/arping"
|
||||
"github.com/vishvananda/netlink"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
@ -33,6 +31,7 @@ import (
|
||||
"github.com/containernetworking/plugins/pkg/ipam"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||
"github.com/containernetworking/plugins/pkg/utils/sysctl"
|
||||
)
|
||||
|
||||
type NetConf struct {
|
||||
@ -256,20 +255,11 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
result.Interfaces = []*current.Interface{ipvlanInterface}
|
||||
|
||||
err = netns.Do(func(_ ns.NetNS) error {
|
||||
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
|
||||
|
||||
if err := ipam.ConfigureIface(args.IfName, result); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contVeth, err := net.InterfaceByName(args.IfName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to look up %q: %v", args.IfName, err)
|
||||
}
|
||||
|
||||
for _, ipc := range result.IPs {
|
||||
if ipc.Address.IP.To4() != nil {
|
||||
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"net"
|
||||
"runtime"
|
||||
|
||||
"github.com/j-keck/arping"
|
||||
"github.com/vishvananda/netlink"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
@ -33,6 +32,7 @@ import (
|
||||
"github.com/containernetworking/plugins/pkg/ipam"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||
"github.com/containernetworking/plugins/pkg/utils/sysctl"
|
||||
)
|
||||
|
||||
type NetConf struct {
|
||||
@ -294,20 +294,11 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
err = netns.Do(func(_ ns.NetNS) error {
|
||||
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
|
||||
|
||||
if err := ipam.ConfigureIface(args.IfName, result); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contVeth, err := net.InterfaceByName(args.IfName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to look up %q: %v", args.IfName, err)
|
||||
}
|
||||
|
||||
for _, ipc := range result.IPs {
|
||||
if ipc.Address.IP.To4() != nil {
|
||||
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/j-keck/arping"
|
||||
"github.com/vishvananda/netlink"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
@ -83,15 +82,15 @@ func setupContainerVeth(netns ns.NetNS, ifName string, mtu int, pr *current.Resu
|
||||
|
||||
pr.Interfaces = []*current.Interface{hostInterface, containerInterface}
|
||||
|
||||
if err = ipam.ConfigureIface(ifName, pr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contVeth, err := net.InterfaceByName(ifName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to look up %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
if err = ipam.ConfigureIface(ifName, pr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ipc := range pr.IPs {
|
||||
// Delete the route that was automatically added
|
||||
route := netlink.Route{
|
||||
@ -139,13 +138,6 @@ func setupContainerVeth(netns ns.NetNS, ifName string, mtu int, pr *current.Resu
|
||||
}
|
||||
}
|
||||
|
||||
// Send a gratuitous arp for all v4 addresses
|
||||
for _, ipc := range pr.IPs {
|
||||
if ipc.Address.IP.To4() != nil {
|
||||
_ = arping.GratuitousArpOverIface(ipc.Address.IP, *contVeth)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -27,7 +27,6 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/j-keck/arping"
|
||||
"github.com/vishvananda/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
@ -315,11 +314,6 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := current.NewResultFromResult(tuningConf.PrevResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The directory /proc/sys/net is per network namespace. Enter in the
|
||||
// network namespace before writing on it.
|
||||
|
||||
@ -355,12 +349,6 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ipc := range result.IPs {
|
||||
if ipc.Address.IP.To4() != nil {
|
||||
_ = arping.GratuitousArpOverIfaceByName(ipc.Address.IP, args.IfName)
|
||||
}
|
||||
}
|
||||
|
||||
updateResultsMacAddr(tuningConf, args.IfName, tuningConf.Mac)
|
||||
}
|
||||
|
||||
|
1
vendor/github.com/j-keck/arping/.gitignore
generated
vendored
1
vendor/github.com/j-keck/arping/.gitignore
generated
vendored
@ -1 +0,0 @@
|
||||
arping
|
22
vendor/github.com/j-keck/arping/LICENSE
generated
vendored
22
vendor/github.com/j-keck/arping/LICENSE
generated
vendored
@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2016 j-keck [jhyphenkeck@gmail.com]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
31
vendor/github.com/j-keck/arping/README.md
generated
vendored
31
vendor/github.com/j-keck/arping/README.md
generated
vendored
@ -1,31 +0,0 @@
|
||||
[](https://pkg.go.dev/github.com/j-keck/arping)
|
||||
|
||||
# arping
|
||||
|
||||
arping is a native go library to ping a host per arp datagram, or query a host mac address
|
||||
|
||||
The currently supported platforms are: Linux and BSD.
|
||||
|
||||
|
||||
## Usage
|
||||
### arping library
|
||||
|
||||
* import this library per `import "github.com/j-keck/arping"`
|
||||
* export GOPATH if not already (`export GOPATH=$PWD`)
|
||||
* download the library `go get`
|
||||
* run it `sudo -E go run <YOUR PROGRAMM>`
|
||||
* or build it `go build`
|
||||
|
||||
|
||||
The library requires raw socket access. So it must run as root, or with appropriate capabilities under linux: `sudo setcap cap_net_raw+ep <BIN>`.
|
||||
|
||||
For api doc and examples see: [godoc](http://godoc.org/github.com/j-keck/arping) or check the standalone under 'cmd/arping/main.go'.
|
||||
|
||||
|
||||
|
||||
### arping executable
|
||||
|
||||
To get a runnable pinger use `go get -u github.com/j-keck/arping/cmd/arping`. This will build the binary in $GOPATH/bin.
|
||||
|
||||
arping requires raw socket access. So it must run as root, or with appropriate capabilities under Linux: `sudo setcap cap_net_raw+ep <ARPING_PATH>`.
|
||||
|
98
vendor/github.com/j-keck/arping/arp_datagram.go
generated
vendored
98
vendor/github.com/j-keck/arping/arp_datagram.go
generated
vendored
@ -1,98 +0,0 @@
|
||||
package arping
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
requestOper = 1
|
||||
responseOper = 2
|
||||
)
|
||||
|
||||
type arpDatagram struct {
|
||||
htype uint16 // Hardware Type
|
||||
ptype uint16 // Protocol Type
|
||||
hlen uint8 // Hardware address Length
|
||||
plen uint8 // Protocol address length
|
||||
oper uint16 // Operation 1->request, 2->response
|
||||
sha []byte // Sender hardware address, length from Hlen
|
||||
spa []byte // Sender protocol address, length from Plen
|
||||
tha []byte // Target hardware address, length from Hlen
|
||||
tpa []byte // Target protocol address, length from Plen
|
||||
}
|
||||
|
||||
func newArpRequest(
|
||||
srcMac net.HardwareAddr,
|
||||
srcIP net.IP,
|
||||
dstMac net.HardwareAddr,
|
||||
dstIP net.IP) arpDatagram {
|
||||
return arpDatagram{
|
||||
htype: uint16(1),
|
||||
ptype: uint16(0x0800),
|
||||
hlen: uint8(6),
|
||||
plen: uint8(4),
|
||||
oper: uint16(requestOper),
|
||||
sha: srcMac,
|
||||
spa: srcIP.To4(),
|
||||
tha: dstMac,
|
||||
tpa: dstIP.To4()}
|
||||
}
|
||||
|
||||
func (datagram arpDatagram) Marshal() []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
binary.Write(buf, binary.BigEndian, datagram.htype)
|
||||
binary.Write(buf, binary.BigEndian, datagram.ptype)
|
||||
binary.Write(buf, binary.BigEndian, datagram.hlen)
|
||||
binary.Write(buf, binary.BigEndian, datagram.plen)
|
||||
binary.Write(buf, binary.BigEndian, datagram.oper)
|
||||
buf.Write(datagram.sha)
|
||||
buf.Write(datagram.spa)
|
||||
buf.Write(datagram.tha)
|
||||
buf.Write(datagram.tpa)
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (datagram arpDatagram) MarshalWithEthernetHeader() []byte {
|
||||
// ethernet frame header
|
||||
var ethernetHeader []byte
|
||||
ethernetHeader = append(ethernetHeader, datagram.tha...)
|
||||
ethernetHeader = append(ethernetHeader, datagram.sha...)
|
||||
ethernetHeader = append(ethernetHeader, []byte{0x08, 0x06}...) // arp
|
||||
|
||||
return append(ethernetHeader, datagram.Marshal()...)
|
||||
}
|
||||
|
||||
func (datagram arpDatagram) SenderIP() net.IP {
|
||||
return net.IP(datagram.spa)
|
||||
}
|
||||
func (datagram arpDatagram) SenderMac() net.HardwareAddr {
|
||||
return net.HardwareAddr(datagram.sha)
|
||||
}
|
||||
|
||||
func (datagram arpDatagram) IsResponseOf(request arpDatagram) bool {
|
||||
return datagram.oper == responseOper && bytes.Equal(request.spa, datagram.tpa) &&
|
||||
bytes.Equal(request.tpa, datagram.spa)
|
||||
}
|
||||
|
||||
func parseArpDatagram(buffer []byte) arpDatagram {
|
||||
var datagram arpDatagram
|
||||
|
||||
b := bytes.NewBuffer(buffer)
|
||||
binary.Read(b, binary.BigEndian, &datagram.htype)
|
||||
binary.Read(b, binary.BigEndian, &datagram.ptype)
|
||||
binary.Read(b, binary.BigEndian, &datagram.hlen)
|
||||
binary.Read(b, binary.BigEndian, &datagram.plen)
|
||||
binary.Read(b, binary.BigEndian, &datagram.oper)
|
||||
|
||||
haLen := int(datagram.hlen)
|
||||
paLen := int(datagram.plen)
|
||||
datagram.sha = b.Next(haLen)
|
||||
datagram.spa = b.Next(paLen)
|
||||
datagram.tha = b.Next(haLen)
|
||||
datagram.tpa = b.Next(paLen)
|
||||
|
||||
return datagram
|
||||
}
|
233
vendor/github.com/j-keck/arping/arping.go
generated
vendored
233
vendor/github.com/j-keck/arping/arping.go
generated
vendored
@ -1,233 +0,0 @@
|
||||
// Package arping is a native go library to ping a host per arp datagram, or query a host mac address
|
||||
//
|
||||
// The currently supported platforms are: Linux and BSD.
|
||||
//
|
||||
//
|
||||
// The library requires raw socket access. So it must run as root, or with appropriate capabilities under linux:
|
||||
// `sudo setcap cap_net_raw+ep <BIN>`.
|
||||
//
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ping a host:
|
||||
// ------------
|
||||
// package main
|
||||
// import ("fmt"; "github.com/j-keck/arping"; "net")
|
||||
//
|
||||
// func main(){
|
||||
// dstIP := net.ParseIP("192.168.1.1")
|
||||
// if hwAddr, duration, err := arping.Ping(dstIP); err != nil {
|
||||
// fmt.Println(err)
|
||||
// } else {
|
||||
// fmt.Printf("%s (%s) %d usec\n", dstIP, hwAddr, duration/1000)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// resolve mac address:
|
||||
// --------------------
|
||||
// package main
|
||||
// import ("fmt"; "github.com/j-keck/arping"; "net")
|
||||
//
|
||||
// func main(){
|
||||
// dstIP := net.ParseIP("192.168.1.1")
|
||||
// if hwAddr, _, err := arping.Ping(dstIP); err != nil {
|
||||
// fmt.Println(err)
|
||||
// } else {
|
||||
// fmt.Printf("%s is at %s\n", dstIP, hwAddr)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// check if host is online:
|
||||
// ------------------------
|
||||
// package main
|
||||
// import ("fmt"; "github.com/j-keck/arping"; "net")
|
||||
//
|
||||
// func main(){
|
||||
// dstIP := net.ParseIP("192.168.1.1")
|
||||
// _, _, err := arping.Ping(dstIP)
|
||||
// if err == arping.ErrTimeout {
|
||||
// fmt.Println("offline")
|
||||
// }else if err != nil {
|
||||
// fmt.Println(err.Error())
|
||||
// }else{
|
||||
// fmt.Println("online")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
package arping
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTimeout error
|
||||
ErrTimeout = errors.New("timeout")
|
||||
|
||||
verboseLog = log.New(ioutil.Discard, "", 0)
|
||||
timeout = time.Duration(500 * time.Millisecond)
|
||||
)
|
||||
|
||||
// Ping sends an arp ping to 'dstIP'
|
||||
func Ping(dstIP net.IP) (net.HardwareAddr, time.Duration, error) {
|
||||
if err := validateIP(dstIP); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
iface, err := findUsableInterfaceForNetwork(dstIP)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return PingOverIface(dstIP, *iface)
|
||||
}
|
||||
|
||||
// PingOverIfaceByName sends an arp ping over interface name 'ifaceName' to 'dstIP'
|
||||
func PingOverIfaceByName(dstIP net.IP, ifaceName string) (net.HardwareAddr, time.Duration, error) {
|
||||
if err := validateIP(dstIP); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return PingOverIface(dstIP, *iface)
|
||||
}
|
||||
|
||||
// PingOverIface sends an arp ping over interface 'iface' to 'dstIP'
|
||||
func PingOverIface(dstIP net.IP, iface net.Interface) (net.HardwareAddr, time.Duration, error) {
|
||||
if err := validateIP(dstIP); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
srcMac := iface.HardwareAddr
|
||||
srcIP, err := findIPInNetworkFromIface(dstIP, iface)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
broadcastMac := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
request := newArpRequest(srcMac, srcIP, broadcastMac, dstIP)
|
||||
|
||||
sock, err := initialize(iface)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer sock.deinitialize()
|
||||
|
||||
type PingResult struct {
|
||||
mac net.HardwareAddr
|
||||
duration time.Duration
|
||||
err error
|
||||
}
|
||||
pingResultChan := make(chan PingResult, 1)
|
||||
|
||||
go func() {
|
||||
// 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 {
|
||||
pingResultChan <- PingResult{nil, 0, err}
|
||||
} else {
|
||||
for {
|
||||
// receive arp response
|
||||
response, receiveTime, err := sock.receive()
|
||||
|
||||
if err != nil {
|
||||
pingResultChan <- PingResult{nil, 0, err}
|
||||
return
|
||||
}
|
||||
|
||||
if response.IsResponseOf(request) {
|
||||
duration := receiveTime.Sub(sendTime)
|
||||
verboseLog.Printf("process received arp: srcIP: '%s', srcMac: '%s'\n",
|
||||
response.SenderIP(), response.SenderMac())
|
||||
pingResultChan <- PingResult{response.SenderMac(), duration, err}
|
||||
return
|
||||
}
|
||||
|
||||
verboseLog.Printf("ignore received arp: srcIP: '%s', srcMac: '%s'\n",
|
||||
response.SenderIP(), response.SenderMac())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case pingResult := <-pingResultChan:
|
||||
return pingResult.mac, pingResult.duration, pingResult.err
|
||||
case <-time.After(timeout):
|
||||
sock.deinitialize()
|
||||
return nil, 0, ErrTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// GratuitousArp sends an gratuitous arp from 'srcIP'
|
||||
func GratuitousArp(srcIP net.IP) error {
|
||||
if err := validateIP(srcIP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iface, err := findUsableInterfaceForNetwork(srcIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return GratuitousArpOverIface(srcIP, *iface)
|
||||
}
|
||||
|
||||
// GratuitousArpOverIfaceByName sends an gratuitous arp over interface name 'ifaceName' from 'srcIP'
|
||||
func GratuitousArpOverIfaceByName(srcIP net.IP, ifaceName string) error {
|
||||
if err := validateIP(srcIP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return GratuitousArpOverIface(srcIP, *iface)
|
||||
}
|
||||
|
||||
// GratuitousArpOverIface sends an gratuitous arp over interface 'iface' from 'srcIP'
|
||||
func GratuitousArpOverIface(srcIP net.IP, iface net.Interface) error {
|
||||
if err := validateIP(srcIP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srcMac := iface.HardwareAddr
|
||||
broadcastMac := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
request := newArpRequest(srcMac, srcIP, broadcastMac, srcIP)
|
||||
|
||||
sock, err := initialize(iface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sock.deinitialize()
|
||||
verboseLog.Printf("gratuitous arp over interface: '%s' with address: '%s'\n", iface.Name, srcIP)
|
||||
_, err = sock.send(request)
|
||||
return err
|
||||
}
|
||||
|
||||
// EnableVerboseLog enables verbose logging on stdout
|
||||
func EnableVerboseLog() {
|
||||
verboseLog = log.New(os.Stdout, "", 0)
|
||||
}
|
||||
|
||||
// SetTimeout sets ping timeout
|
||||
func SetTimeout(t time.Duration) {
|
||||
timeout = t
|
||||
}
|
||||
|
||||
func validateIP(ip net.IP) error {
|
||||
// ip must be a valid V4 address
|
||||
if len(ip.To4()) != net.IPv4len {
|
||||
return fmt.Errorf("not a valid v4 Address: %s", ip)
|
||||
}
|
||||
return nil
|
||||
}
|
104
vendor/github.com/j-keck/arping/arping_bsd.go
generated
vendored
104
vendor/github.com/j-keck/arping/arping_bsd.go
generated
vendored
@ -1,104 +0,0 @@
|
||||
// +build darwin freebsd openbsd
|
||||
|
||||
package arping
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BsdSocket struct {
|
||||
bpf *os.File
|
||||
bpfFd int
|
||||
buflen int
|
||||
}
|
||||
|
||||
var bpfArpFilter = []syscall.BpfInsn{
|
||||
// make sure this is an arp packet
|
||||
*syscall.BpfStmt(syscall.BPF_LD+syscall.BPF_H+syscall.BPF_ABS, 12),
|
||||
*syscall.BpfJump(syscall.BPF_JMP+syscall.BPF_JEQ+syscall.BPF_K, 0x0806, 0, 1),
|
||||
// if we passed all the tests, ask for the whole packet.
|
||||
*syscall.BpfStmt(syscall.BPF_RET+syscall.BPF_K, -1),
|
||||
// otherwise, drop it.
|
||||
*syscall.BpfStmt(syscall.BPF_RET+syscall.BPF_K, 0),
|
||||
}
|
||||
|
||||
func initialize(iface net.Interface) (s *BsdSocket, err error) {
|
||||
s = &BsdSocket{}
|
||||
verboseLog.Println("search available /dev/bpfX")
|
||||
for i := 0; i <= 10; i++ {
|
||||
bpfPath := fmt.Sprintf("/dev/bpf%d", i)
|
||||
s.bpf, err = os.OpenFile(bpfPath, os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
verboseLog.Printf(" open failed: %s - %s\n", bpfPath, err.Error())
|
||||
} else {
|
||||
verboseLog.Printf(" open success: %s\n", bpfPath)
|
||||
break
|
||||
}
|
||||
}
|
||||
s.bpfFd = int(s.bpf.Fd())
|
||||
if s.bpfFd == -1 {
|
||||
return s, errors.New("unable to open /dev/bpfX")
|
||||
}
|
||||
|
||||
if err := syscall.SetBpfInterface(s.bpfFd, iface.Name); err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
if err := syscall.SetBpfImmediate(s.bpfFd, 1); err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
s.buflen, err = syscall.BpfBuflen(s.bpfFd)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
if err := syscall.SetBpf(s.bpfFd, bpfArpFilter); err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
if err := syscall.FlushBpf(s.bpfFd); err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *BsdSocket) send(request arpDatagram) (time.Time, error) {
|
||||
_, err := syscall.Write(s.bpfFd, request.MarshalWithEthernetHeader())
|
||||
return time.Now(), err
|
||||
}
|
||||
|
||||
func (s *BsdSocket) receive() (arpDatagram, time.Time, error) {
|
||||
buffer := make([]byte, s.buflen)
|
||||
n, err := syscall.Read(s.bpfFd, buffer)
|
||||
if err != nil {
|
||||
return arpDatagram{}, time.Now(), err
|
||||
}
|
||||
|
||||
//
|
||||
// FreeBSD uses a different bpf header (bh_tstamp differ in it's size)
|
||||
// https://www.freebsd.org/cgi/man.cgi?bpf(4)#BPF_HEADER
|
||||
//
|
||||
var bpfHdrLength int
|
||||
if runtime.GOOS == "freebsd" {
|
||||
bpfHdrLength = 26
|
||||
} else {
|
||||
bpfHdrLength = 18
|
||||
}
|
||||
|
||||
// skip bpf header + 14 bytes ethernet header
|
||||
var hdrLength = bpfHdrLength + 14
|
||||
|
||||
return parseArpDatagram(buffer[hdrLength:n]), time.Now(), nil
|
||||
}
|
||||
|
||||
func (s *BsdSocket) deinitialize() error {
|
||||
return s.bpf.Close()
|
||||
}
|
43
vendor/github.com/j-keck/arping/arping_linux.go
generated
vendored
43
vendor/github.com/j-keck/arping/arping_linux.go
generated
vendored
@ -1,43 +0,0 @@
|
||||
package arping
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LinuxSocket struct {
|
||||
sock int
|
||||
toSockaddr syscall.SockaddrLinklayer
|
||||
}
|
||||
|
||||
func initialize(iface net.Interface) (s *LinuxSocket, err error) {
|
||||
s = &LinuxSocket{}
|
||||
s.toSockaddr = syscall.SockaddrLinklayer{Ifindex: iface.Index}
|
||||
|
||||
// 1544 = htons(ETH_P_ARP)
|
||||
const proto = 1544
|
||||
s.sock, err = syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, proto)
|
||||
return s, err
|
||||
}
|
||||
|
||||
func (s *LinuxSocket) send(request arpDatagram) (time.Time, error) {
|
||||
return time.Now(), syscall.Sendto(s.sock, request.MarshalWithEthernetHeader(), 0, &s.toSockaddr)
|
||||
}
|
||||
|
||||
func (s *LinuxSocket) receive() (arpDatagram, time.Time, error) {
|
||||
buffer := make([]byte, 128)
|
||||
socketTimeout := timeout.Nanoseconds() * 2
|
||||
t := syscall.NsecToTimeval(socketTimeout)
|
||||
syscall.SetsockoptTimeval(s.sock, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &t)
|
||||
n, _, err := syscall.Recvfrom(s.sock, buffer, 0)
|
||||
if err != nil {
|
||||
return arpDatagram{}, time.Now(), err
|
||||
}
|
||||
// skip 14 bytes ethernet header
|
||||
return parseArpDatagram(buffer[14:n]), time.Now(), nil
|
||||
}
|
||||
|
||||
func (s *LinuxSocket) deinitialize() error {
|
||||
return syscall.Close(s.sock)
|
||||
}
|
28
vendor/github.com/j-keck/arping/arping_windows.go
generated
vendored
28
vendor/github.com/j-keck/arping/arping_windows.go
generated
vendored
@ -1,28 +0,0 @@
|
||||
// windows currently not supported.
|
||||
// dummy implementation to prevent compilation errors under windows
|
||||
|
||||
package arping
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errWindowsNotSupported = errors.New("arping under windows not supported")
|
||||
|
||||
func initialize(iface net.Interface) error {
|
||||
return errWindowsNotSupported
|
||||
}
|
||||
|
||||
func send(request arpDatagram) (time.Time, error) {
|
||||
return time.Now(), errWindowsNotSupported
|
||||
}
|
||||
|
||||
func receive() (arpDatagram, time.Time, error) {
|
||||
return arpDatagram{}, time.Now(), errWindowsNotSupported
|
||||
}
|
||||
|
||||
func deinitialize() error {
|
||||
return errWindowsNotSupported
|
||||
}
|
3
vendor/github.com/j-keck/arping/go.mod
generated
vendored
3
vendor/github.com/j-keck/arping/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
||||
module github.com/j-keck/arping
|
||||
|
||||
go 1.12
|
64
vendor/github.com/j-keck/arping/netutils.go
generated
vendored
64
vendor/github.com/j-keck/arping/netutils.go
generated
vendored
@ -1,64 +0,0 @@
|
||||
package arping
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func findIPInNetworkFromIface(dstIP net.IP, iface net.Interface) (net.IP, error) {
|
||||
addrs, err := iface.Addrs()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, a := range addrs {
|
||||
if ipnet, ok := a.(*net.IPNet); ok {
|
||||
if ipnet.Contains(dstIP) {
|
||||
return ipnet.IP, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("iface: '%s' can't reach ip: '%s'", iface.Name, dstIP)
|
||||
}
|
||||
|
||||
func findUsableInterfaceForNetwork(dstIP net.IP) (*net.Interface, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isDown := func(iface net.Interface) bool {
|
||||
return iface.Flags&1 == 0
|
||||
}
|
||||
|
||||
hasAddressInNetwork := func(iface net.Interface) bool {
|
||||
if _, err := findIPInNetworkFromIface(dstIP, iface); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
verboseLog.Println("search usable interface")
|
||||
logIfaceResult := func(msg string, iface net.Interface) {
|
||||
verboseLog.Printf("%10s: %6s %18s %s", msg, iface.Name, iface.HardwareAddr, iface.Flags)
|
||||
}
|
||||
|
||||
for _, iface := range ifaces {
|
||||
if isDown(iface) {
|
||||
logIfaceResult("DOWN", iface)
|
||||
continue
|
||||
}
|
||||
|
||||
if !hasAddressInNetwork(iface) {
|
||||
logIfaceResult("OTHER NET", iface)
|
||||
continue
|
||||
}
|
||||
|
||||
logIfaceResult("USABLE", iface)
|
||||
return &iface, nil
|
||||
}
|
||||
return nil, errors.New("no usable interface found")
|
||||
}
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -78,9 +78,6 @@ github.com/gogo/protobuf/proto
|
||||
github.com/gogo/protobuf/protoc-gen-gogo/descriptor
|
||||
# github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
|
||||
github.com/golang/groupcache/lru
|
||||
# github.com/j-keck/arping v1.0.2
|
||||
## explicit
|
||||
github.com/j-keck/arping
|
||||
# github.com/mattn/go-shellwords v1.0.12
|
||||
## explicit
|
||||
github.com/mattn/go-shellwords
|
||||
|
Loading…
x
Reference in New Issue
Block a user