initial commit
This commit is contained in:
commit
7715fcf373
37 changed files with 2957 additions and 0 deletions
173
pkg/vip/arp_linux.go.bak
Normal file
173
pkg/vip/arp_linux.go.bak
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// +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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
opARPRequest = 1
|
||||
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 {
|
||||
return fmt.Errorf("failed to get raw socket: %v", err)
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
if err := syscall.BindToDevice(fd, iface.Name); err != nil {
|
||||
return fmt.Errorf("failed to bind to device: %v", 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
|
||||
}
|
||||
|
||||
// ARPSendGratuitous sends a gratuitous ARP message via the specified interface.
|
||||
func ARPSendGratuitous(cidr, iface string) error {
|
||||
i, err := net.InterfaceByName(iface)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get interface %q: %v", iface, err)
|
||||
}
|
||||
ip, _, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse cidr: %s", cidr)
|
||||
}
|
||||
|
||||
//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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue