vendor: add github.com/d2g
This commit is contained in:
147
vendor/github.com/d2g/dhcp4client/pktsock_linux.go
generated
vendored
Normal file
147
vendor/github.com/d2g/dhcp4client/pktsock_linux.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
package dhcp4client
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
minIPHdrLen = 20
|
||||
maxIPHdrLen = 60
|
||||
udpHdrLen = 8
|
||||
ip4Ver = 0x40
|
||||
ttl = 16
|
||||
srcPort = 68
|
||||
dstPort = 67
|
||||
)
|
||||
|
||||
var (
|
||||
bcastMAC = []byte{255, 255, 255, 255, 255, 255}
|
||||
)
|
||||
|
||||
// abstracts AF_PACKET
|
||||
type packetSock struct {
|
||||
fd int
|
||||
ifindex int
|
||||
}
|
||||
|
||||
func NewPacketSock(ifindex int) (*packetSock, error) {
|
||||
fd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_DGRAM, int(swap16(unix.ETH_P_IP)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addr := unix.SockaddrLinklayer{
|
||||
Ifindex: ifindex,
|
||||
Protocol: swap16(unix.ETH_P_IP),
|
||||
}
|
||||
|
||||
if err = unix.Bind(fd, &addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &packetSock{
|
||||
fd: fd,
|
||||
ifindex: ifindex,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (pc *packetSock) Close() error {
|
||||
return unix.Close(pc.fd)
|
||||
}
|
||||
|
||||
func (pc *packetSock) Write(packet []byte) error {
|
||||
lladdr := unix.SockaddrLinklayer{
|
||||
Ifindex: pc.ifindex,
|
||||
Protocol: swap16(unix.ETH_P_IP),
|
||||
Halen: uint8(len(bcastMAC)),
|
||||
}
|
||||
copy(lladdr.Addr[:], bcastMAC)
|
||||
|
||||
pkt := make([]byte, minIPHdrLen+udpHdrLen+len(packet))
|
||||
|
||||
fillIPHdr(pkt[0:minIPHdrLen], udpHdrLen+uint16(len(packet)))
|
||||
fillUDPHdr(pkt[minIPHdrLen:minIPHdrLen+udpHdrLen], uint16(len(packet)))
|
||||
|
||||
// payload
|
||||
copy(pkt[minIPHdrLen+udpHdrLen:len(pkt)], packet)
|
||||
|
||||
return unix.Sendto(pc.fd, pkt, 0, &lladdr)
|
||||
}
|
||||
|
||||
func (pc *packetSock) ReadFrom() ([]byte, net.IP, error) {
|
||||
pkt := make([]byte, maxIPHdrLen+udpHdrLen+MaxDHCPLen)
|
||||
n, _, err := unix.Recvfrom(pc.fd, pkt, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// IP hdr len
|
||||
ihl := int(pkt[0]&0x0F) * 4
|
||||
// Source IP address
|
||||
src := net.IP(pkt[12:16])
|
||||
|
||||
return pkt[ihl+udpHdrLen : n], src, nil
|
||||
}
|
||||
|
||||
func (pc *packetSock) SetReadTimeout(t time.Duration) error {
|
||||
|
||||
tv := unix.NsecToTimeval(t.Nanoseconds())
|
||||
return unix.SetsockoptTimeval(pc.fd, unix.SOL_SOCKET, unix.SO_RCVTIMEO, &tv)
|
||||
}
|
||||
|
||||
// compute's 1's complement checksum
|
||||
func chksum(p []byte, csum []byte) {
|
||||
cklen := len(p)
|
||||
s := uint32(0)
|
||||
for i := 0; i < (cklen - 1); i += 2 {
|
||||
s += uint32(p[i+1])<<8 | uint32(p[i])
|
||||
}
|
||||
if cklen&1 == 1 {
|
||||
s += uint32(p[cklen-1])
|
||||
}
|
||||
s = (s >> 16) + (s & 0xffff)
|
||||
s = s + (s >> 16)
|
||||
s = ^s
|
||||
|
||||
csum[0] = uint8(s & 0xff)
|
||||
csum[1] = uint8(s >> 8)
|
||||
}
|
||||
|
||||
func fillIPHdr(hdr []byte, payloadLen uint16) {
|
||||
// version + IHL
|
||||
hdr[0] = ip4Ver | (minIPHdrLen / 4)
|
||||
// total length
|
||||
binary.BigEndian.PutUint16(hdr[2:4], uint16(len(hdr))+payloadLen)
|
||||
// identification
|
||||
if _, err := rand.Read(hdr[4:5]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// TTL
|
||||
hdr[8] = 16
|
||||
// Protocol
|
||||
hdr[9] = unix.IPPROTO_UDP
|
||||
// dst IP
|
||||
copy(hdr[16:20], net.IPv4bcast.To4())
|
||||
// compute IP hdr checksum
|
||||
chksum(hdr[0:len(hdr)], hdr[10:12])
|
||||
}
|
||||
|
||||
func fillUDPHdr(hdr []byte, payloadLen uint16) {
|
||||
// src port
|
||||
binary.BigEndian.PutUint16(hdr[0:2], srcPort)
|
||||
// dest port
|
||||
binary.BigEndian.PutUint16(hdr[2:4], dstPort)
|
||||
// length
|
||||
binary.BigEndian.PutUint16(hdr[4:6], udpHdrLen+payloadLen)
|
||||
}
|
||||
|
||||
func swap16(x uint16) uint16 {
|
||||
var b [2]byte
|
||||
binary.BigEndian.PutUint16(b[:], x)
|
||||
return binary.LittleEndian.Uint16(b[:])
|
||||
}
|
Reference in New Issue
Block a user