Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bind interface fix #310

Merged
merged 11 commits into from
Aug 14, 2019
2 changes: 1 addition & 1 deletion dhcpv4/nclient4/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func serveAndClient(ctx context.Context, responses [][]*dhcpv4.DHCPv4, opts ...C
}

h := &handler{responses: responses}
s, err := server4.NewServer(nil, h.handle, server4.WithConn(serverConn))
s, err := server4.NewServer("", nil, h.handle, server4.WithConn(serverConn))
if err != nil {
panic(err)
}
Expand Down
38 changes: 0 additions & 38 deletions dhcpv4/nclient4/conn_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ import (
"fmt"
"io"
"net"
"os"

"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/mdlayher/ethernet"
"github.com/mdlayher/raw"
"github.com/u-root/u-root/pkg/uio"
"golang.org/x/sys/unix"
)

var (
Expand All @@ -26,41 +23,6 @@ var (
BroadcastMac = net.HardwareAddr([]byte{255, 255, 255, 255, 255, 255})
)

// NewIPv4UDPConn returns a UDP connection bound to both the interface and port
// given based on a IPv4 DGRAM socket. The UDP connection allows broadcasting.
//
// The interface must already be configured.
func NewIPv4UDPConn(iface string, port int) (net.PacketConn, error) {
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
if err != nil {
return nil, fmt.Errorf("cannot get a UDP socket: %v", err)
}
f := os.NewFile(uintptr(fd), "")
// net.FilePacketConn dups the FD, so we have to close this in any case.
defer f.Close()

// Allow broadcasting.
if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_BROADCAST, 1); err != nil {
return nil, fmt.Errorf("cannot set broadcasting on socket: %v", err)
}
// Allow reusing the addr to aid debugging.
if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
return nil, fmt.Errorf("cannot set reuseaddr on socket: %v", err)
}
if len(iface) != 0 {
// Bind directly to the interface.
if err := dhcpv4.BindToInterface(fd, iface); err != nil {
return nil, fmt.Errorf("cannot bind to interface %s: %v", iface, err)
}
}
// Bind to the port.
if err := unix.Bind(fd, &unix.SockaddrInet4{Port: port}); err != nil {
return nil, fmt.Errorf("cannot bind to port %d: %v", port, err)
}

return net.FilePacketConn(f)
}

// NewRawUDPConn returns a UDP connection bound to the interface and port
// given based on a raw packet socket. All packets are broadcasted.
//
Expand Down
45 changes: 45 additions & 0 deletions dhcpv4/server4/conn_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package server4
pmazzini marked this conversation as resolved.
Show resolved Hide resolved

import (
"fmt"
"net"
"os"

"github.com/insomniacslk/dhcp/dhcpv4"
"golang.org/x/sys/unix"
)

// NewIPv4UDPConn returns a UDP connection bound to both the interface and port
// given based on a IPv4 DGRAM socket. The UDP connection allows broadcasting.
//
// The interface must already be configured.
func NewIPv4UDPConn(iface string, port int) (net.PacketConn, error) {
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
if err != nil {
return nil, fmt.Errorf("cannot get a UDP socket: %v", err)
}
f := os.NewFile(uintptr(fd), "")
// net.FilePacketConn dups the FD, so we have to close this in any case.
defer f.Close()

// Allow broadcasting.
if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_BROADCAST, 1); err != nil {
return nil, fmt.Errorf("cannot set broadcasting on socket: %v", err)
}
// Allow reusing the addr to aid debugging.
if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
return nil, fmt.Errorf("cannot set reuseaddr on socket: %v", err)
}
if len(iface) != 0 {
// Bind directly to the interface.
if err := dhcpv4.BindToInterface(fd, iface); err != nil {
return nil, fmt.Errorf("cannot bind to interface %s: %v", iface, err)
}
}
// Bind to the port.
if err := unix.Bind(fd, &unix.SockaddrInet4{Port: port}); err != nil {
return nil, fmt.Errorf("cannot bind to port %d: %v", port, err)
}

return net.FilePacketConn(f)
}
4 changes: 2 additions & 2 deletions dhcpv4/server4/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func WithConn(c net.PacketConn) ServerOpt {
}

// NewServer initializes and returns a new Server object
func NewServer(addr *net.UDPAddr, handler Handler, opt ...ServerOpt) (*Server, error) {
func NewServer(ifname string, addr *net.UDPAddr, handler Handler, opt ...ServerOpt) (*Server, error) {
s := &Server{
Handler: handler,
}
Expand All @@ -133,7 +133,7 @@ func NewServer(addr *net.UDPAddr, handler Handler, opt ...ServerOpt) (*Server, e
}
if s.conn == nil {
var err error
conn, err := net.ListenUDP("udp4", addr)
conn, err := NewIPv4UDPConn(ifname, addr.Port)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions dhcpv4/server4/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ func setUpClientAndServer(t *testing.T, iface net.Interface, handler Handler) (*
IP: loAddr,
Port: randPort(),
}
s, err := NewServer(&saddr, handler)
s, err := NewServer(iface.Name, &saddr, handler)
pmazzini marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
t.Fatal(err)
}
go func() {
_ = s.Serve()
}()

clientConn, err := nclient4.NewIPv4UDPConn("", caddr.Port)
clientConn, err := dhcpv4.NewIPv4UDPConn("", caddr.Port)
pmazzini marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
t.Fatal(err)
}
Expand Down