dhcp: tighten up the exported interface by removing some cruft.

Notably, some of the helpers for implementing Conns are internal now.
This commit is contained in:
David Anderson 2016-05-14 23:44:54 -07:00
parent 45dd5dfe4d
commit ae696d0c3d
5 changed files with 73 additions and 96 deletions

View File

@ -16,6 +16,7 @@ package dhcp
import ( import (
"errors" "errors"
"io"
"net" "net"
"time" "time"
@ -23,10 +24,55 @@ import (
) )
// defined as a var so tests can override it. // defined as a var so tests can override it.
var dhcpClientPort = 68 var (
dhcpClientPort = 68
platformConn func(string) (Conn, error)
)
var platformConn func(string) (Conn, error) // txType describes how a Packet should be sent on the wire.
type txType int
// The various transmission strategies described in RFC 2131. "MUST",
// "MUST NOT", "SHOULD" and "MAY" are as specified in RFC 2119.
const (
// Packet MUST be broadcast.
txBroadcast txType = iota
// Packet MUST be unicasted to port 67 of RelayAddr
txRelayAddr
// Packet MUST be unicasted to port 68 of ClientAddr
txClientAddr
// Packet SHOULD be unicasted to port 68 of YourAddr, with the
// link-layer destination explicitly set to HardwareAddr. You MUST
// NOT rely on ARP resolution to discover the link-layer
// destination address.
//
// Conn implementations that cannot explicitly set the link-layer
// destination address MAY instead broadcast the packet.
txHardwareAddr
)
// Conn is a DHCP-oriented packet socket.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
io.Closer
// RecvDHCP reads a Packet from the connection. It returns the
// packet and the interface it was received on, which may be nil
// if interface information cannot be obtained.
RecvDHCP() (pkt *Packet, intf *net.Interface, err error)
// SendDHCP sends pkt. The precise transmission mechanism depends
// on pkt.txType(). intf should be the net.Interface returned by
// RecvDHCP if responding to a DHCP client, or the interface for
// which configuration is desired if acting as a client.
SendDHCP(pkt *Packet, intf *net.Interface) error
// SetReadDeadline sets the deadline for future Read calls.
// If the deadline is reached, Read will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
}
// 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 { if platformConn != nil {
c, err := platformConn(addr) c, err := platformConn(addr)
@ -90,8 +136,8 @@ func (c *portableConn) SendDHCP(pkt *Packet, intf *net.Interface) error {
return err return err
} }
switch pkt.TxType() { switch pkt.txType() {
case TxBroadcast, TxHardwareAddr: case txBroadcast, txHardwareAddr:
cm := ipv4.ControlMessage{ cm := ipv4.ControlMessage{
IfIndex: intf.Index, IfIndex: intf.Index,
} }
@ -101,7 +147,7 @@ func (c *portableConn) SendDHCP(pkt *Packet, intf *net.Interface) error {
} }
_, err = c.conn.WriteTo(b, &cm, &addr) _, err = c.conn.WriteTo(b, &cm, &addr)
return err return err
case TxRelayAddr: case txRelayAddr:
// Send to the server port, not the client port. // Send to the server port, not the client port.
addr := net.UDPAddr{ addr := net.UDPAddr{
IP: pkt.RelayAddr, IP: pkt.RelayAddr,
@ -109,7 +155,7 @@ func (c *portableConn) SendDHCP(pkt *Packet, intf *net.Interface) error {
} }
_, err = c.conn.WriteTo(b, nil, &addr) _, err = c.conn.WriteTo(b, nil, &addr)
return err return err
case TxClientAddr: case txClientAddr:
addr := net.UDPAddr{ addr := net.UDPAddr{
IP: pkt.ClientAddr, IP: pkt.ClientAddr,
Port: dhcpClientPort, Port: dhcpClientPort,

View File

@ -153,19 +153,19 @@ func (c *linuxConn) SendDHCP(pkt *Packet, intf *net.Interface) error {
Protocol: 17, Protocol: 17,
} }
switch pkt.TxType() { switch pkt.txType() {
case TxBroadcast, TxHardwareAddr: case txBroadcast, txHardwareAddr:
hdr.Dst = net.IPv4bcast hdr.Dst = net.IPv4bcast
cm := ipv4.ControlMessage{ cm := ipv4.ControlMessage{
IfIndex: intf.Index, IfIndex: intf.Index,
} }
return c.conn.WriteTo(&hdr, raw, &cm) return c.conn.WriteTo(&hdr, raw, &cm)
case TxRelayAddr: case txRelayAddr:
// Send to the server port, not the client port. // Send to the server port, not the client port.
binary.BigEndian.PutUint16(raw[2:4], 67) binary.BigEndian.PutUint16(raw[2:4], 67)
hdr.Dst = pkt.RelayAddr hdr.Dst = pkt.RelayAddr
return c.conn.WriteTo(&hdr, raw, nil) return c.conn.WriteTo(&hdr, raw, nil)
case TxClientAddr: case txClientAddr:
hdr.Dst = pkt.ClientAddr hdr.Dst = pkt.ClientAddr
return c.conn.WriteTo(&hdr, raw, nil) return c.conn.WriteTo(&hdr, raw, nil)
default: default:

View File

@ -68,22 +68,15 @@ func (o Options) Unmarshal(bs []byte) error {
// Marshal returns the wire encoding of o. // Marshal returns the wire encoding of o.
func (o Options) Marshal() ([]byte, error) { func (o Options) Marshal() ([]byte, error) {
var ret bytes.Buffer var ret bytes.Buffer
if err := o.MarshalTo(&ret); err != nil { opts, err := o.marshalLimited(&ret, 0, false)
if err != nil {
return nil, err return nil, err
} }
return ret.Bytes(), nil
}
// MarshalTo serializes o into w.
func (o Options) MarshalTo(w io.Writer) error {
opts, err := o.marshalLimited(w, 0, false)
if err != nil {
return err
}
if len(opts) > 0 { if len(opts) > 0 {
return errors.New("some options not written, but no limit was given (please file a bug)") return nil, errors.New("some options not written, but no limit was given (please file a bug)")
} }
return nil
return ret.Bytes(), nil
} }
// Copy returns a shallow copy of o. // Copy returns a shallow copy of o.

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// Package dhcp implements parsing and serialization of DHCP packets.
package dhcp package dhcp
import ( import (
@ -83,23 +82,22 @@ type Packet struct {
Options Options Options Options
} }
// TxType determines how the Packet should be sent on the wire, based // decides how to send Packet on the wire, based on its field values.
// on its field values.
// //
// This implements the transmission decision process in section 4.1 of // This implements the transmission decision process in section 4.1 of
// RFC 2131. // RFC 2131.
func (p *Packet) TxType() TxType { func (p *Packet) txType() txType {
switch { switch {
case p.RelayAddr != nil && p.RelayAddr.IsGlobalUnicast(): case p.RelayAddr != nil && p.RelayAddr.IsGlobalUnicast():
return TxRelayAddr return txRelayAddr
case p.Type == MsgNack: case p.Type == MsgNack:
return TxBroadcast return txBroadcast
case p.ClientAddr != nil && (p.ClientAddr.IsGlobalUnicast() || p.ClientAddr.IsLoopback()): case p.ClientAddr != nil && (p.ClientAddr.IsGlobalUnicast() || p.ClientAddr.IsLoopback()):
return TxClientAddr return txClientAddr
case p.Broadcast: case p.Broadcast:
return TxBroadcast return txBroadcast
default: default:
return TxHardwareAddr return txHardwareAddr
} }
} }
@ -227,9 +225,13 @@ func (p *Packet) Marshal() ([]byte, error) {
} }
ret.Write(magic) ret.Write(magic)
if err := opts.MarshalTo(ret); err != nil { leftover, err := opts.marshalLimited(ret, 0, false)
if err != nil {
return nil, err return nil, err
} }
if len(leftover) > 0 {
return nil, errors.New("some options not written, but no limit was given (please file a bug)")
}
return ret.Bytes(), nil return ret.Bytes(), nil
} }

View File

@ -1,64 +0,0 @@
// 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.
package dhcp // import "go.universe.tf/netboot/dhcp"
import (
"io"
"net"
"time"
)
// TxType describes how a Packet should be sent on the wire.
type TxType int
// The various transmission strategies described in RFC 2131. "MUST",
// "MUST NOT", "SHOULD" and "MAY" are as specified in RFC 2119.
const (
// Packet MUST be broadcast.
TxBroadcast TxType = iota
// Packet MUST be unicasted to port 67 of RelayAddr
TxRelayAddr
// Packet MUST be unicasted to port 68 of ClientAddr
TxClientAddr
// Packet SHOULD be unicasted to port 68 of YourAddr, with the
// link-layer destination explicitly set to HardwareAddr. You MUST
// NOT rely on ARP resolution to discover the link-layer
// destination address.
//
// Conn implementations that cannot explicitly set the link-layer
// destination address MAY instead broadcast the packet.
TxHardwareAddr
)
// Conn is a DHCP-oriented packet socket.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
io.Closer
// RecvDHCP reads a Packet from the connection. It returns the
// packet and the interface it was received on, which may be nil
// if interface information cannot be obtained.
RecvDHCP() (pkt *Packet, intf *net.Interface, err error)
// SendDHCP sends pkt. The precise transmission mechanism depends
// on pkt.TxType(). intf should be the net.Interface returned by
// RecvDHCP if responding to a DHCP client, or the interface for
// which configuration is desired if acting as a client.
SendDHCP(pkt *Packet, intf *net.Interface) error
// SetReadDeadline sets the deadline for future Read calls.
// If the deadline is reached, Read will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
}