From f061a783a7125ea1381a95973c43b940d4920515 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 28 Aug 2016 16:16:47 -0700 Subject: [PATCH] dhcp4: Don't use the non-binding DHCP Conn silently on linux. pixiecore: Plumb NewSnooperConn into Server as an advanced option. pixiecore/cli: Plumb DHCPNoBind to the CLI. Now, by default, Pixiecore will bind() to the DHCP server port in a way that shows up in `netstat` by default. If you want to enable the "coexist with my existing DHCP server" mode, you need to explicitly pass --dhcp-no-bind. --- dhcp4/conn.go | 8 -------- dhcp4/conn_linux.go | 12 ++++++++++-- dhcp4/conn_unsupported.go | 27 +++++++++++++++++++++++++++ pixiecore/cli/cli.go | 18 ++++++++++++------ pixiecore/pixiecore.go | 13 ++++++++++++- 5 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 dhcp4/conn_unsupported.go diff --git a/dhcp4/conn.go b/dhcp4/conn.go index 34d90cf..a68e08a 100644 --- a/dhcp4/conn.go +++ b/dhcp4/conn.go @@ -26,7 +26,6 @@ import ( // defined as a var so tests can override it. var ( dhcpClientPort = 68 - platformConn func(string) (conn, error) ) // txType describes how a Packet should be sent on the wire. @@ -68,13 +67,6 @@ type Conn struct { // NewConn creates a Conn bound to the given UDP ip:port. func NewConn(addr string) (*Conn, error) { - if platformConn != nil { - c, err := platformConn(addr) - if err == nil { - return &Conn{c}, nil - } - } - // Always try falling back to the portable implementation c, err := newPortableConn(addr) if err != nil { return nil, err diff --git a/dhcp4/conn_linux.go b/dhcp4/conn_linux.go index 6ac402d..1ec97e2 100644 --- a/dhcp4/conn_linux.go +++ b/dhcp4/conn_linux.go @@ -36,8 +36,16 @@ type linuxConn struct { conn *ipv4.RawConn } -func init() { - platformConn = newLinuxConn +// NewSnooperConn creates a Conn that listens on the given UDP ip:port. +// +// Unlike NewConn, NewSnooperConn does not bind to the ip:port, +// enabling the Conn to coexist with other services on the machine. +func NewSnooperConn(addr string) (*Conn, error) { + c, err := newLinuxConn(addr) + if err != nil { + return nil, err + } + return &Conn{c}, nil } func newLinuxConn(addr string) (conn, error) { diff --git a/dhcp4/conn_unsupported.go b/dhcp4/conn_unsupported.go new file mode 100644 index 0000000..a402f33 --- /dev/null +++ b/dhcp4/conn_unsupported.go @@ -0,0 +1,27 @@ +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//+build !linux + +package dhcp4 + +import "errors" + +// NewSnooperConn creates a Conn that listens on the given UDP ip:port. +// +// Unlike NewConn, NewSnooperConn does not bind to the ip:port, +// enabling the Conn to coexist with other services on the machine. +func NewSnooperConn(addr string) (*Conn, error) { + return nil, errors.New("snooper Conns not supported on this OS") +} diff --git a/pixiecore/cli/cli.go b/pixiecore/cli/cli.go index 5c19500..5a47a3b 100644 --- a/pixiecore/cli/cli.go +++ b/pixiecore/cli/cli.go @@ -73,9 +73,10 @@ func serverConfigFlags(cmd *cobra.Command) { cmd.Flags().BoolP("log-timestamps", "t", false, "Add a timestamp to each log line") cmd.Flags().IPP("listen-addr", "l", net.IPv4zero, "IPv4 address to listen on") cmd.Flags().IntP("port", "p", 80, "Port to listen on for HTTP") - cmd.Flags().String("ipxe-bios", "", "path to an iPXE binary for BIOS/UNDI") - cmd.Flags().String("ipxe-efi32", "", "path to an iPXE binary for 32-bit UEFI") - cmd.Flags().String("ipxe-efi64", "", "path to an iPXE binary for 64-bit UEFI") + cmd.Flags().Bool("dhcp-no-bind", false, "Handle DHCP traffic without binding to the DHCP server port") + cmd.Flags().String("ipxe-bios", "", "Path to an iPXE binary for BIOS/UNDI") + cmd.Flags().String("ipxe-efi32", "", "Path to an iPXE binary for 32-bit UEFI") + cmd.Flags().String("ipxe-efi64", "", "Path to an iPXE binary for 64-bit UEFI") } func mustFile(path string) []byte { @@ -104,6 +105,10 @@ func serverFromFlags(cmd *cobra.Command) *pixiecore.Server { if err != nil { fatalf("Error reading flag: %s", err) } + dhcpNoBind, err := cmd.Flags().GetBool("dhcp-no-bind") + if err != nil { + fatalf("Error reading flag: %s", err) + } ipxeBios, err := cmd.Flags().GetString("ipxe-bios") if err != nil { fatalf("Error reading flag: %s", err) @@ -125,9 +130,10 @@ func serverFromFlags(cmd *cobra.Command) *pixiecore.Server { } ret := &pixiecore.Server{ - Ipxe: map[pixiecore.Firmware][]byte{}, - Log: logWithStdFmt, - HTTPPort: httpPort, + Ipxe: map[pixiecore.Firmware][]byte{}, + Log: logWithStdFmt, + HTTPPort: httpPort, + DHCPNoBind: dhcpNoBind, } for fwtype, bs := range Ipxe { ret.Ipxe[fwtype] = bs diff --git a/pixiecore/pixiecore.go b/pixiecore/pixiecore.go index 7587a7a..510da8b 100644 --- a/pixiecore/pixiecore.go +++ b/pixiecore/pixiecore.go @@ -154,6 +154,12 @@ type Server struct { TFTPPort int PXEPort int + // Listen for DHCP traffic without binding to the DHCP port. This + // enables coexistence of Pixiecore with another DHCP server. + // + // Currently only supported on Linux. + DHCPNoBind bool + errs chan error } @@ -173,7 +179,12 @@ func (s *Server) Serve() error { s.HTTPPort = portHTTP } - dhcp, err := dhcp4.NewConn(fmt.Sprintf("%s:%d", s.Address, s.DHCPPort)) + newDHCP := dhcp4.NewConn + if s.DHCPNoBind { + newDHCP = dhcp4.NewSnooperConn + } + + dhcp, err := newDHCP(fmt.Sprintf("%s:%d", s.Address, s.DHCPPort)) if err != nil { return err }