added cidr validation and made hook execs to command array with args
This commit is contained in:
parent
fd9f8fc1fd
commit
85a2e39a4b
6 changed files with 54 additions and 165 deletions
2
go.mod
2
go.mod
|
|
@ -16,6 +16,8 @@ require (
|
||||||
github.com/google/uuid v1.1.2 // indirect
|
github.com/google/uuid v1.1.2 // indirect
|
||||||
github.com/hashicorp/go-hclog v0.15.0
|
github.com/hashicorp/go-hclog v0.15.0
|
||||||
github.com/hashicorp/raft v1.2.0
|
github.com/hashicorp/raft v1.2.0
|
||||||
|
github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc
|
||||||
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
go.etcd.io/etcd v3.3.25+incompatible
|
go.etcd.io/etcd v3.3.25+incompatible
|
||||||
go.uber.org/zap v1.16.0
|
go.uber.org/zap v1.16.0
|
||||||
|
|
|
||||||
14
go.sum
14
go.sum
|
|
@ -82,6 +82,14 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc h1:m7rJJJeXrYCFpsxXYapkDW53wJCDmf9bsIXUg0HoeQY=
|
||||||
|
github.com/mdlayher/arp v0.0.0-20191213142603-f72070a231fc/go.mod h1:eOj1DDj3NAZ6yv+WafaKzY37MFZ58TdfIhQ+8nQbiis=
|
||||||
|
github.com/mdlayher/ethernet v0.0.0-20190313224307-5b5fc417d966/go.mod h1:5s5p/sMJ6sNsFl6uCh85lkFGV8kLuIYJCRJLavVJwvg=
|
||||||
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE=
|
||||||
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||||
|
github.com/mdlayher/raw v0.0.0-20190313224157-43dbcdd7739d/go.mod h1:r1fbeITl2xL/zLbVnNHFyOzQJTgr/3fpf1lJX/cjzR8=
|
||||||
|
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18 h1:zwOa3e/13D6veNIz6zzuqrd3eZEMF0dzD0AQWKcYSs4=
|
||||||
|
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
|
@ -125,7 +133,10 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
|
||||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
|
@ -135,8 +146,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -41,14 +42,20 @@ func Validate(c *Config) error {
|
||||||
if len(c.VirtualIPs) == 0 {
|
if len(c.VirtualIPs) == 0 {
|
||||||
return errors.New("missing virtualIPs config")
|
return errors.New("missing virtualIPs config")
|
||||||
}
|
}
|
||||||
if c.LeaderHook != "" {
|
for _, vip := range c.VirtualIPs {
|
||||||
if !filepath.IsAbs(c.LeaderHook) {
|
_, err := netlink.ParseAddr(vip)
|
||||||
return errors.New("leaderHook path must be absolute")
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse CIDR virtualIP '%s': %w", vip, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.FollowerHook != "" {
|
if len(c.LeaderHook) > 0 {
|
||||||
if !filepath.IsAbs(c.FollowerHook) {
|
if !filepath.IsAbs(c.LeaderHook[0]) {
|
||||||
return errors.New("followerHook path must be absolute")
|
return errors.New("leaderHook executable path must be absolute")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(c.FollowerHook) > 0 {
|
||||||
|
if !filepath.IsAbs(c.FollowerHook[0]) {
|
||||||
|
return errors.New("followerHook executable path must be absolute")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
raft := c.Cluster.Raft
|
raft := c.Cluster.Raft
|
||||||
|
|
@ -116,8 +123,8 @@ type Config struct {
|
||||||
VirtualIPs []string `yaml:"virtualIPs"`
|
VirtualIPs []string `yaml:"virtualIPs"`
|
||||||
Interface string `yaml:"interface,omitempty"`
|
Interface string `yaml:"interface,omitempty"`
|
||||||
Label string `yaml:"label,omitempty"`
|
Label string `yaml:"label,omitempty"`
|
||||||
LeaderHook string `yaml:"leaderHook,omitempty"`
|
LeaderHook []string `yaml:"leaderHook,omitempty"`
|
||||||
FollowerHook string `yaml:"followerHook,omitempty"`
|
FollowerHook []string `yaml:"followerHook,omitempty"`
|
||||||
Cluster Cluster `yaml:"cluster"`
|
Cluster Cluster `yaml:"cluster"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ func NewVIPController(cfg *config.Config) (callbacks cluster.Callbacks, err erro
|
||||||
callbacks = cluster.Callbacks{
|
callbacks = cluster.Callbacks{
|
||||||
Leader: func(ctx context.Context, cc cluster.CallbackContext) {
|
Leader: func(ctx context.Context, cc cluster.CallbackContext) {
|
||||||
t := time.NewTicker(time.Second * 10)
|
t := time.NewTicker(time.Second * 10)
|
||||||
if cfg.LeaderHook != "" {
|
if len(cfg.LeaderHook) > 0 {
|
||||||
go func() {
|
go func() {
|
||||||
err := exec.CommandContext(ctx, cfg.LeaderHook).Run()
|
err := exec.CommandContext(ctx, cfg.LeaderHook[0], cfg.LeaderHook[1:]...).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cc.Error(err, "error running hook", "leaderHook", cfg.LeaderHook)
|
cc.Error(err, "error running hook", "leaderHook", cfg.LeaderHook)
|
||||||
}
|
}
|
||||||
|
|
@ -42,9 +42,9 @@ func NewVIPController(cfg *config.Config) (callbacks cluster.Callbacks, err erro
|
||||||
},
|
},
|
||||||
Follower: func(ctx context.Context, cc cluster.CallbackContext) {
|
Follower: func(ctx context.Context, cc cluster.CallbackContext) {
|
||||||
t := time.NewTicker(time.Second * 10)
|
t := time.NewTicker(time.Second * 10)
|
||||||
if cfg.FollowerHook != "" {
|
if len(cfg.FollowerHook) > 0 {
|
||||||
go func() {
|
go func() {
|
||||||
err := exec.CommandContext(ctx, cfg.FollowerHook).Run()
|
err := exec.CommandContext(ctx, cfg.FollowerHook[0], cfg.FollowerHook[1:]...).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cc.Error(err, "error running hook", "followerHook", cfg.FollowerHook)
|
cc.Error(err, "error running hook", "followerHook", cfg.FollowerHook)
|
||||||
}
|
}
|
||||||
|
|
@ -52,8 +52,7 @@ func NewVIPController(cfg *config.Config) (callbacks cluster.Callbacks, err erro
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
cc.Info("following", "id", cc.ID())
|
cc.Info("following", "id", cc.ID())
|
||||||
//TODO
|
deleteIPs(cc, n, cfg.VirtualIPs)
|
||||||
//deleteIPs(cc, n, cfg.VirtualIPs)
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
t.Stop()
|
t.Stop()
|
||||||
|
|
|
||||||
|
|
@ -1,159 +1,30 @@
|
||||||
// +build linux
|
|
||||||
|
|
||||||
// These syscalls are only supported on Linux, so this uses a build directive during compilation. Other OS's will use the arp_unsupported.go and receive an error
|
|
||||||
|
|
||||||
package vip
|
package vip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
"github.com/mdlayher/arp"
|
||||||
|
"github.com/mdlayher/ethernet"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
func sendARP(ip net.IP, iface *net.Interface) error {
|
||||||
opARPRequest = 1
|
c, err := arp.Dial(iface)
|
||||||
opARPReply = 2
|
|
||||||
hwLen = 6
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ethernetBroadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
|
||||||
// arpRequest is used to flip between garp request or garp reply
|
|
||||||
arpRequest = true
|
|
||||||
)
|
|
||||||
|
|
||||||
func htons(p uint16) uint16 {
|
|
||||||
var b [2]byte
|
|
||||||
binary.BigEndian.PutUint16(b[:], p)
|
|
||||||
return *(*uint16)(unsafe.Pointer(&b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// arpHeader specifies the header for an ARP message.
|
|
||||||
type arpHeader struct {
|
|
||||||
hardwareType uint16
|
|
||||||
protocolType uint16
|
|
||||||
hardwareAddressLength uint8
|
|
||||||
protocolAddressLength uint8
|
|
||||||
opcode uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
// arpMessage represents an ARP message.
|
|
||||||
type arpMessage struct {
|
|
||||||
arpHeader
|
|
||||||
senderHardwareAddress []byte
|
|
||||||
senderProtocolAddress []byte
|
|
||||||
targetHardwareAddress []byte
|
|
||||||
targetProtocolAddress []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// bytes returns the wire representation of the ARP message.
|
|
||||||
func (m *arpMessage) bytes() ([]byte, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
if err := binary.Write(buf, binary.BigEndian, m.arpHeader); err != nil {
|
|
||||||
return nil, fmt.Errorf("binary write failed: %v", err)
|
|
||||||
}
|
|
||||||
buf.Write(m.senderHardwareAddress)
|
|
||||||
buf.Write(m.senderProtocolAddress)
|
|
||||||
buf.Write(m.targetHardwareAddress)
|
|
||||||
buf.Write(m.targetProtocolAddress)
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// gratuitousARP return a gARP request or gARP reply alternatively
|
|
||||||
// because different devices may support either one of them
|
|
||||||
func gratuitousARP(ip net.IP, mac net.HardwareAddr) (*arpMessage, error) {
|
|
||||||
if ip.To4() == nil {
|
|
||||||
return nil, fmt.Errorf("%q is not an IPv4 address", ip)
|
|
||||||
}
|
|
||||||
if len(mac) != hwLen {
|
|
||||||
return nil, fmt.Errorf("%q is not an Ethernet MAC address", mac)
|
|
||||||
}
|
|
||||||
|
|
||||||
m := &arpMessage{
|
|
||||||
arpHeader: arpHeader{
|
|
||||||
1, // Ethernet
|
|
||||||
0x0800, // IPv4
|
|
||||||
hwLen, // 48-bit MAC Address
|
|
||||||
net.IPv4len, // 32-bit IPv4 Address
|
|
||||||
opARPReply, // ARP Reply
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc5944#section-4.6
|
|
||||||
// In either case, the ARP Sender Hardware Address is
|
|
||||||
// set to the link-layer address to which this cache entry should be
|
|
||||||
// updated.
|
|
||||||
m.senderHardwareAddress = mac
|
|
||||||
|
|
||||||
// When using an ARP Reply packet, the Target Hardware
|
|
||||||
// Address is also set to the link-layer address to which this cache
|
|
||||||
// entry should be updated (this field is not used in an ARP Request
|
|
||||||
// packet).
|
|
||||||
m.targetHardwareAddress = mac
|
|
||||||
|
|
||||||
// In either case, the ARP Sender Protocol Address and
|
|
||||||
// ARP Target Protocol Address are both set to the IP address of the
|
|
||||||
// cache entry to be updated,
|
|
||||||
m.senderProtocolAddress = ip.To4()
|
|
||||||
m.targetProtocolAddress = ip.To4()
|
|
||||||
|
|
||||||
// send arpRequest and arpReply alternatively
|
|
||||||
arpRequest = !arpRequest
|
|
||||||
if arpRequest {
|
|
||||||
m.arpHeader.opcode = opARPRequest
|
|
||||||
|
|
||||||
// this field is not used in an ARP Request packet
|
|
||||||
m.targetHardwareAddress = ethernetBroadcast
|
|
||||||
}
|
|
||||||
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendARP sends the given ARP message via the specified interface.
|
|
||||||
func sendARP(iface *net.Interface, m *arpMessage) error {
|
|
||||||
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, int(htons(syscall.ETH_P_ARP)))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get raw socket: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
defer syscall.Close(fd)
|
for _, op := range []arp.Operation{arp.OperationRequest, arp.OperationReply} {
|
||||||
|
pkt, err := arp.NewPacket(op, iface.HardwareAddr, ip, ethernet.Broadcast, ip)
|
||||||
if err := syscall.BindToDevice(fd, iface.Name); err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to bind to device: %v", err)
|
return fmt.Errorf("assembling %q gratuitous packet for %q: %s", op, ip, err)
|
||||||
|
}
|
||||||
|
if err = c.WriteTo(pkt, ethernet.Broadcast); err != nil {
|
||||||
|
return fmt.Errorf("writing %q gratuitous packet for %q: %s", op, ip, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ll := syscall.SockaddrLinklayer{
|
|
||||||
Protocol: htons(syscall.ETH_P_ARP),
|
|
||||||
Ifindex: iface.Index,
|
|
||||||
Pkttype: 0, // syscall.PACKET_HOST
|
|
||||||
Hatype: m.hardwareType,
|
|
||||||
Halen: m.hardwareAddressLength,
|
|
||||||
}
|
|
||||||
target := ethernetBroadcast
|
|
||||||
for i := 0; i < len(target); i++ {
|
|
||||||
ll.Addr[i] = target[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := m.bytes()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to convert ARP message: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syscall.Bind(fd, &ll); err != nil {
|
|
||||||
return fmt.Errorf("failed to bind: %v", err)
|
|
||||||
}
|
|
||||||
if err := syscall.Sendto(fd, b, 0, &ll); err != nil {
|
|
||||||
return fmt.Errorf("failed to send: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ARPSendGratuitous sends a gratuitous ARP message via the specified interface.
|
|
||||||
func ARPSendGratuitous(cidr, iface string) error {
|
func ARPSendGratuitous(cidr, iface string) error {
|
||||||
i, err := net.InterfaceByName(iface)
|
i, err := net.InterfaceByName(iface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -163,11 +34,5 @@ func ARPSendGratuitous(cidr, iface string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse cidr: %s", cidr)
|
return fmt.Errorf("failed to parse cidr: %s", cidr)
|
||||||
}
|
}
|
||||||
|
return sendARP(ip, i)
|
||||||
//log.Infof("Broadcasting ARP update for %s (%s) via %s", address, iface.HardwareAddr, iface.Name)
|
|
||||||
m, err := gratuitousARP(ip, i.HardwareAddr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return sendARP(i, m)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ virtualIPs:
|
||||||
- ""
|
- ""
|
||||||
interface: ""
|
interface: ""
|
||||||
label: ""
|
label: ""
|
||||||
leaderHook: ""
|
leaderHook:
|
||||||
followerHook: ""
|
- ""
|
||||||
|
followerHook:
|
||||||
|
- ""
|
||||||
cluster:
|
cluster:
|
||||||
raft:
|
raft:
|
||||||
dir: ""
|
dir: ""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue