fix dhcp build on OSX

This commit is contained in:
wanyaoqi
2019-07-01 14:05:33 +08:00
parent 5c8273992b
commit d0b7a0c5d1
4 changed files with 150 additions and 145 deletions
+2 -143
View File
@@ -38,12 +38,8 @@ import (
"syscall"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/mdlayher/raw"
"golang.org/x/net/bpf"
"golang.org/x/net/ipv4"
"golang.org/x/sys/unix"
)
// defined as a var so tests can override it.
@@ -89,8 +85,8 @@ type Conn struct {
ifIndex int
}
func NewRawSocketConn(iface string, filter []bpf.RawInstruction) (*Conn, error) {
conn, err := newRawSocketConn(iface, filter)
func NewRawSocketConn(iface string, filter []bpf.RawInstruction, dhcpServerPort uint16) (*Conn, error) {
conn, err := newRawSocketConn(iface, filter, dhcpServerPort)
if err != nil {
return nil, err
}
@@ -302,13 +298,6 @@ func (c *portableConn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}
type rawSocketConn struct {
conn *raw.Conn
iface *net.Interface
ip net.IP
}
func interfaceToIPv4Addr(ifi *net.Interface) (net.IP, error) {
if ifi == nil {
return net.IPv4zero, nil
@@ -332,136 +321,6 @@ func interfaceToIPv4Addr(ifi *net.Interface) (net.IP, error) {
return nil, errors.New("no such network interface")
}
func newRawSocketConn(iface string, filter []bpf.RawInstruction) (conn, error) {
ifi, err := net.InterfaceByName(iface)
if err != nil {
return nil, fmt.Errorf("interface by name: %v", err)
}
ip, err := interfaceToIPv4Addr(ifi)
if err != nil {
return nil, err
}
// unix.ETH_P_ALL
conn, err := raw.ListenPacket(ifi, unix.ETH_P_ALL, &raw.Config{
NoCumulativeStats: true,
Filter: filter,
})
return &rawSocketConn{conn, ifi, ip}, nil
}
func (s *rawSocketConn) Close() error {
return s.conn.Close()
}
func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
// read packet
n, addr, err := s.conn.ReadFrom(b)
if err != nil {
return nil, nil, nil, 0, fmt.Errorf("Read from errror: %s", err)
}
b = b[:n]
srcMac, err := net.ParseMAC(addr.String())
if err != nil {
return nil, nil, nil, 0, fmt.Errorf("Parse mac error: %s", err)
}
p := gopacket.NewPacket(b, layers.LayerTypeEthernet, gopacket.Default)
if p.ErrorLayer() != nil {
return nil, nil, nil, 0, fmt.Errorf("Failed to decode packet: %v", p.ErrorLayer().Error())
}
var srcIp net.IP
ipLayer := p.Layer(layers.LayerTypeIPv4)
if ipLayer != nil {
ip4 := ipLayer.(*layers.IPv4)
srcIp = ip4.SrcIP
} else {
return nil, nil, nil, 0, fmt.Errorf("Fetch ip layer failed")
}
var srcPort uint16
udpLayer := p.Layer(layers.LayerTypeUDP)
if udpLayer != nil {
udpInfo := udpLayer.(*layers.UDP)
srcPort = uint16(udpInfo.SrcPort)
} else {
return nil, nil, nil, 0, fmt.Errorf("Fetch upd layer failed")
}
dhcpLayer := p.Layer(layers.LayerTypeDHCPv4)
if dhcpLayer != nil {
dhcp4 := dhcpLayer.(*layers.DHCPv4)
sbf := gopacket.NewSerializeBuffer()
if err := dhcp4.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
return nil, nil, nil, 0, fmt.Errorf("Serialize dhcp packet error %s", err)
}
return sbf.Bytes(), &net.UDPAddr{srcIp, int(srcPort), ""}, srcMac, 0, nil
} else {
return nil, nil, nil, 0, fmt.Errorf("Fetch dhcp layer failed")
}
}
func (s *rawSocketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr, ifidx int) error {
var dhcp = new(layers.DHCPv4)
if err := dhcp.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
return fmt.Errorf("Decode dhcp bytes error %s", err)
}
var eth = &layers.Ethernet{
EthernetType: layers.EthernetTypeIPv4,
SrcMAC: s.iface.HardwareAddr,
DstMAC: destMac,
}
var ip = &layers.IPv4{
Version: 4,
TTL: 64,
SrcIP: s.ip,
DstIP: addr.IP,
Protocol: layers.IPProtocolUDP,
}
var (
srcPort layers.UDPPort
dstPort = layers.UDPPort(addr.Port)
)
if dstPort == 67 {
srcPort = 68
} else {
srcPort = 67
}
var udp = &layers.UDP{
SrcPort: srcPort,
DstPort: dstPort,
}
udp.SetNetworkLayerForChecksum(ip)
var (
buf = gopacket.NewSerializeBuffer()
opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
)
if err := gopacket.SerializeLayers(buf, opts, eth, ip, udp, dhcp); err != nil {
return fmt.Errorf("SerializeLayers error: %s", err)
}
// s.conn.SetWriteDeadline(time.Now().Add(DefaultWriteTimeout)) // 2 second
if _, err := s.conn.WriteTo(buf.Bytes(), &raw.Addr{HardwareAddr: destMac}); err != nil {
return fmt.Errorf("Send dhcp packet error %s", err)
}
return nil
}
func (s *rawSocketConn) SetReadDeadline(t time.Time) error {
return s.conn.SetReadDeadline(t)
}
func (s *rawSocketConn) SetWriteDeadline(t time.Time) error {
return s.conn.SetWriteDeadline(t)
}
type socketConn struct {
sock int
}
+138
View File
@@ -38,10 +38,148 @@ import (
"net"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/mdlayher/raw"
"golang.org/x/net/bpf"
"golang.org/x/net/ipv4"
"golang.org/x/sys/unix"
)
type rawSocketConn struct {
conn *raw.Conn
iface *net.Interface
ip net.IP
dhcpServerPort uint16
}
func newRawSocketConn(iface string, filter []bpf.RawInstruction, dhcpServerPort uint16) (conn, error) {
ifi, err := net.InterfaceByName(iface)
if err != nil {
return nil, fmt.Errorf("interface by name: %v", err)
}
ip, err := interfaceToIPv4Addr(ifi)
if err != nil {
return nil, err
}
// unix.ETH_P_ALL
conn, err := raw.ListenPacket(ifi, unix.ETH_P_ALL, &raw.Config{
NoCumulativeStats: true,
Filter: filter,
})
return &rawSocketConn{conn, ifi, ip, dhcpServerPort}, nil
}
func (s *rawSocketConn) Close() error {
return s.conn.Close()
}
func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
// read packet
n, addr, err := s.conn.ReadFrom(b)
if err != nil {
return nil, nil, nil, 0, fmt.Errorf("Read from errror: %s", err)
}
b = b[:n]
srcMac, err := net.ParseMAC(addr.String())
if err != nil {
return nil, nil, nil, 0, fmt.Errorf("Parse mac error: %s", err)
}
p := gopacket.NewPacket(b, layers.LayerTypeEthernet, gopacket.Default)
if p.ErrorLayer() != nil {
return nil, nil, nil, 0, fmt.Errorf("Failed to decode packet: %v", p.ErrorLayer().Error())
}
var srcIp net.IP
ipLayer := p.Layer(layers.LayerTypeIPv4)
if ipLayer != nil {
ip4 := ipLayer.(*layers.IPv4)
srcIp = ip4.SrcIP
} else {
return nil, nil, nil, 0, fmt.Errorf("Fetch ip layer failed")
}
var srcPort uint16
udpLayer := p.Layer(layers.LayerTypeUDP)
if udpLayer != nil {
udpInfo := udpLayer.(*layers.UDP)
srcPort = uint16(udpInfo.SrcPort)
} else {
return nil, nil, nil, 0, fmt.Errorf("Fetch upd layer failed")
}
dhcpLayer := p.Layer(layers.LayerTypeDHCPv4)
if dhcpLayer != nil {
dhcp4 := dhcpLayer.(*layers.DHCPv4)
sbf := gopacket.NewSerializeBuffer()
if err := dhcp4.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
return nil, nil, nil, 0, fmt.Errorf("Serialize dhcp packet error %s", err)
}
return sbf.Bytes(), &net.UDPAddr{srcIp, int(srcPort), ""}, srcMac, 0, nil
} else {
return nil, nil, nil, 0, fmt.Errorf("Fetch dhcp layer failed")
}
}
func (s *rawSocketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr, ifidx int) error {
var dhcp = new(layers.DHCPv4)
if err := dhcp.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
return fmt.Errorf("Decode dhcp bytes error %s", err)
}
var eth = &layers.Ethernet{
EthernetType: layers.EthernetTypeIPv4,
SrcMAC: s.iface.HardwareAddr,
DstMAC: destMac,
}
var ip = &layers.IPv4{
Version: 4,
TTL: 64,
SrcIP: s.ip,
DstIP: addr.IP,
Protocol: layers.IPProtocolUDP,
}
var (
srcPort = layers.UDPPort(s.dhcpServerPort)
dstPort = layers.UDPPort(addr.Port)
)
var udp = &layers.UDP{
SrcPort: srcPort,
DstPort: dstPort,
}
udp.SetNetworkLayerForChecksum(ip)
var (
buf = gopacket.NewSerializeBuffer()
opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
)
if err := gopacket.SerializeLayers(buf, opts, eth, ip, udp, dhcp); err != nil {
return fmt.Errorf("SerializeLayers error: %s", err)
}
// s.conn.SetWriteDeadline(time.Now().Add(DefaultWriteTimeout)) // 2 second
if _, err := s.conn.WriteTo(buf.Bytes(), &raw.Addr{HardwareAddr: destMac}); err != nil {
return fmt.Errorf("Send dhcp packet error %s", err)
}
return nil
}
func (s *rawSocketConn) SetReadDeadline(t time.Time) error {
return s.conn.SetReadDeadline(t)
}
func (s *rawSocketConn) SetWriteDeadline(t time.Time) error {
return s.conn.SetWriteDeadline(t)
}
type linuxConn struct {
port uint16
conn *ipv4.RawConn
+9 -1
View File
@@ -31,7 +31,11 @@
package dhcp
import "errors"
import (
"errors"
"golang.org/x/net/bpf"
)
// NewSnooperConn creates a Conn that listens on the given UDP ip:port.
//
@@ -40,3 +44,7 @@ import "errors"
func NewSnooperConn(addr string) (*Conn, error) {
return nil, errors.New("snooper Conns not supported on this OS")
}
func newRawSocketConn(iface string, filter []bpf.RawInstruction, dhcpServerPort uint16) (conn, error) {
return nil, errors.New("raw socket Conns not supported on this OS")
}
+1 -1
View File
@@ -77,7 +77,7 @@ func NewDHCPServer2(iface string, dhcpServerPort, dhcpRelayPort uint16) (*DHCPSe
{0x6, 0, 0, 0x00040000},
{0x6, 0, 0, 0x00000000},
}
conn, err := NewRawSocketConn(iface, bpf)
conn, err := NewRawSocketConn(iface, bpf, dhcpServerPort)
if err != nil {
return nil, nil, err
}