From d0b7a0c5d1ccdbc1f3c4c09922f92870de3bf86e Mon Sep 17 00:00:00 2001 From: wanyaoqi Date: Mon, 1 Jul 2019 14:05:33 +0800 Subject: [PATCH] fix dhcp build on OSX --- pkg/util/dhcp/conn.go | 145 +----------------------------- pkg/util/dhcp/conn_linux.go | 138 ++++++++++++++++++++++++++++ pkg/util/dhcp/conn_unsupported.go | 10 ++- pkg/util/dhcp/server.go | 2 +- 4 files changed, 150 insertions(+), 145 deletions(-) diff --git a/pkg/util/dhcp/conn.go b/pkg/util/dhcp/conn.go index b65c96e7db..cb39314da9 100644 --- a/pkg/util/dhcp/conn.go +++ b/pkg/util/dhcp/conn.go @@ -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 } diff --git a/pkg/util/dhcp/conn_linux.go b/pkg/util/dhcp/conn_linux.go index e6e0e7ffce..cacd971263 100644 --- a/pkg/util/dhcp/conn_linux.go +++ b/pkg/util/dhcp/conn_linux.go @@ -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 diff --git a/pkg/util/dhcp/conn_unsupported.go b/pkg/util/dhcp/conn_unsupported.go index 327c1e8b24..962f6e734f 100644 --- a/pkg/util/dhcp/conn_unsupported.go +++ b/pkg/util/dhcp/conn_unsupported.go @@ -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") +} diff --git a/pkg/util/dhcp/server.go b/pkg/util/dhcp/server.go index 091ed193b6..1d56d577e7 100644 --- a/pkg/util/dhcp/server.go +++ b/pkg/util/dhcp/server.go @@ -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 }