Pull request: * all: move internal Go packages to internal/
Merge in DNS/adguard-home from 2234-move-to-internal to master Squashed commit of the following: commit d26a288cabeac86f9483fab307677b1027c78524 Author: Eugene Burkov <e.burkov@adguard.com> Date: Fri Oct 30 12:44:18 2020 +0300 * all: move internal Go packages to internal/ Closes #2234.
This commit is contained in:
144
internal/dhcpd/nclient4/conn_unix.go
Normal file
144
internal/dhcpd/nclient4/conn_unix.go
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright 2018 the u-root Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
// +build go1.12
|
||||
|
||||
package nclient4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/mdlayher/ethernet"
|
||||
"github.com/mdlayher/raw"
|
||||
"github.com/u-root/u-root/pkg/uio"
|
||||
)
|
||||
|
||||
var (
|
||||
// BroadcastMac is the broadcast MAC address.
|
||||
//
|
||||
// Any UDP packet sent to this address is broadcast on the subnet.
|
||||
BroadcastMac = net.HardwareAddr([]byte{255, 255, 255, 255, 255, 255})
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrUDPAddrIsRequired is an error used when a passed argument is not of type "*net.UDPAddr".
|
||||
ErrUDPAddrIsRequired = errors.New("must supply UDPAddr")
|
||||
)
|
||||
|
||||
// NewRawUDPConn returns a UDP connection bound to the interface and port
|
||||
// given based on a raw packet socket. All packets are broadcasted.
|
||||
//
|
||||
// The interface can be completely unconfigured.
|
||||
func NewRawUDPConn(iface string, port int) (net.PacketConn, error) {
|
||||
ifc, err := net.InterfaceByName(iface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawConn, err := raw.ListenPacket(ifc, uint16(ethernet.EtherTypeIPv4), &raw.Config{LinuxSockDGRAM: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewBroadcastUDPConn(rawConn, &net.UDPAddr{Port: port}), nil
|
||||
}
|
||||
|
||||
// BroadcastRawUDPConn uses a raw socket to send UDP packets to the broadcast
|
||||
// MAC address.
|
||||
type BroadcastRawUDPConn struct {
|
||||
// PacketConn is a raw DGRAM socket.
|
||||
net.PacketConn
|
||||
|
||||
// boundAddr is the address this RawUDPConn is "bound" to.
|
||||
//
|
||||
// Calls to ReadFrom will only return packets destined to this address.
|
||||
boundAddr *net.UDPAddr
|
||||
}
|
||||
|
||||
// NewBroadcastUDPConn returns a PacketConn that marshals and unmarshals UDP
|
||||
// packets, sending them to the broadcast MAC at on rawPacketConn.
|
||||
//
|
||||
// Calls to ReadFrom will only return packets destined to boundAddr.
|
||||
func NewBroadcastUDPConn(rawPacketConn net.PacketConn, boundAddr *net.UDPAddr) net.PacketConn {
|
||||
return &BroadcastRawUDPConn{
|
||||
PacketConn: rawPacketConn,
|
||||
boundAddr: boundAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func udpMatch(addr *net.UDPAddr, bound *net.UDPAddr) bool {
|
||||
if bound == nil {
|
||||
return true
|
||||
}
|
||||
if bound.IP != nil && !bound.IP.Equal(addr.IP) {
|
||||
return false
|
||||
}
|
||||
return bound.Port == addr.Port
|
||||
}
|
||||
|
||||
// ReadFrom implements net.PacketConn.ReadFrom.
|
||||
//
|
||||
// ReadFrom reads raw IP packets and will try to match them against
|
||||
// upc.boundAddr. Any matching packets are returned via the given buffer.
|
||||
func (upc *BroadcastRawUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
ipHdrMaxLen := IPv4MaximumHeaderSize
|
||||
udpHdrLen := UDPMinimumSize
|
||||
|
||||
for {
|
||||
pkt := make([]byte, ipHdrMaxLen+udpHdrLen+len(b))
|
||||
n, _, err := upc.PacketConn.ReadFrom(pkt)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
return 0, nil, io.EOF
|
||||
}
|
||||
pkt = pkt[:n]
|
||||
buf := uio.NewBigEndianBuffer(pkt)
|
||||
|
||||
// To read the header length, access data directly.
|
||||
ipHdr := IPv4(buf.Data())
|
||||
ipHdr = IPv4(buf.Consume(int(ipHdr.HeaderLength())))
|
||||
|
||||
if ipHdr.TransportProtocol() != UDPProtocolNumber {
|
||||
continue
|
||||
}
|
||||
udpHdr := UDP(buf.Consume(udpHdrLen))
|
||||
|
||||
addr := &net.UDPAddr{
|
||||
IP: ipHdr.DestinationAddress(),
|
||||
Port: int(udpHdr.DestinationPort()),
|
||||
}
|
||||
if !udpMatch(addr, upc.boundAddr) {
|
||||
continue
|
||||
}
|
||||
srcAddr := &net.UDPAddr{
|
||||
IP: ipHdr.SourceAddress(),
|
||||
Port: int(udpHdr.SourcePort()),
|
||||
}
|
||||
// Extra padding after end of IP packet should be ignored,
|
||||
// if not dhcp option parsing will fail.
|
||||
dhcpLen := int(ipHdr.PayloadLength()) - udpHdrLen
|
||||
return copy(b, buf.Consume(dhcpLen)), srcAddr, nil
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTo implements net.PacketConn.WriteTo and broadcasts all packets at the
|
||||
// raw socket level.
|
||||
//
|
||||
// WriteTo wraps the given packet in the appropriate UDP and IP header before
|
||||
// sending it on the packet conn.
|
||||
func (upc *BroadcastRawUDPConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
udpAddr, ok := addr.(*net.UDPAddr)
|
||||
if !ok {
|
||||
return 0, ErrUDPAddrIsRequired
|
||||
}
|
||||
|
||||
// Using the boundAddr is not quite right here, but it works.
|
||||
packet := udp4pkt(b, udpAddr, upc.boundAddr)
|
||||
|
||||
// Broadcasting is not always right, but hell, what the ARP do I know.
|
||||
return upc.PacketConn.WriteTo(packet, &raw.Addr{HardwareAddr: BroadcastMac})
|
||||
}
|
||||
Reference in New Issue
Block a user