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.
This commit is contained in:
David Anderson 2016-08-28 16:16:47 -07:00
parent 7bde0dde1b
commit f061a783a7
5 changed files with 61 additions and 17 deletions

View File

@ -26,7 +26,6 @@ import (
// defined as a var so tests can override it. // defined as a var so tests can override it.
var ( var (
dhcpClientPort = 68 dhcpClientPort = 68
platformConn func(string) (conn, error)
) )
// txType describes how a Packet should be sent on the wire. // 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. // NewConn creates a Conn bound to the given UDP ip:port.
func NewConn(addr string) (*Conn, error) { 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) c, err := newPortableConn(addr)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -36,8 +36,16 @@ type linuxConn struct {
conn *ipv4.RawConn conn *ipv4.RawConn
} }
func init() { // NewSnooperConn creates a Conn that listens on the given UDP ip:port.
platformConn = newLinuxConn //
// 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) { func newLinuxConn(addr string) (conn, error) {

27
dhcp4/conn_unsupported.go Normal file
View File

@ -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")
}

View File

@ -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().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().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().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().Bool("dhcp-no-bind", false, "Handle DHCP traffic without binding to the DHCP server port")
cmd.Flags().String("ipxe-efi32", "", "path to an iPXE binary for 32-bit UEFI") cmd.Flags().String("ipxe-bios", "", "Path to an iPXE binary for BIOS/UNDI")
cmd.Flags().String("ipxe-efi64", "", "path to an iPXE binary for 64-bit UEFI") 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 { func mustFile(path string) []byte {
@ -104,6 +105,10 @@ func serverFromFlags(cmd *cobra.Command) *pixiecore.Server {
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) 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") ipxeBios, err := cmd.Flags().GetString("ipxe-bios")
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
@ -128,6 +133,7 @@ func serverFromFlags(cmd *cobra.Command) *pixiecore.Server {
Ipxe: map[pixiecore.Firmware][]byte{}, Ipxe: map[pixiecore.Firmware][]byte{},
Log: logWithStdFmt, Log: logWithStdFmt,
HTTPPort: httpPort, HTTPPort: httpPort,
DHCPNoBind: dhcpNoBind,
} }
for fwtype, bs := range Ipxe { for fwtype, bs := range Ipxe {
ret.Ipxe[fwtype] = bs ret.Ipxe[fwtype] = bs

View File

@ -154,6 +154,12 @@ type Server struct {
TFTPPort int TFTPPort int
PXEPort 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 errs chan error
} }
@ -173,7 +179,12 @@ func (s *Server) Serve() error {
s.HTTPPort = portHTTP 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 { if err != nil {
return err return err
} }