diff --git a/dhcp/conn.go b/dhcp/conn.go index dbdf5bf..dfb6a72 100644 --- a/dhcp/conn.go +++ b/dhcp/conn.go @@ -16,6 +16,7 @@ package dhcp import ( "errors" + "io" "net" "time" @@ -23,10 +24,55 @@ import ( ) // 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) { if platformConn != nil { c, err := platformConn(addr) @@ -90,8 +136,8 @@ func (c *portableConn) SendDHCP(pkt *Packet, intf *net.Interface) error { return err } - switch pkt.TxType() { - case TxBroadcast, TxHardwareAddr: + switch pkt.txType() { + case txBroadcast, txHardwareAddr: cm := ipv4.ControlMessage{ IfIndex: intf.Index, } @@ -101,7 +147,7 @@ func (c *portableConn) SendDHCP(pkt *Packet, intf *net.Interface) error { } _, err = c.conn.WriteTo(b, &cm, &addr) return err - case TxRelayAddr: + case txRelayAddr: // Send to the server port, not the client port. addr := net.UDPAddr{ IP: pkt.RelayAddr, @@ -109,7 +155,7 @@ func (c *portableConn) SendDHCP(pkt *Packet, intf *net.Interface) error { } _, err = c.conn.WriteTo(b, nil, &addr) return err - case TxClientAddr: + case txClientAddr: addr := net.UDPAddr{ IP: pkt.ClientAddr, Port: dhcpClientPort, diff --git a/dhcp/conn_linux.go b/dhcp/conn_linux.go index 8816ec7..900f057 100644 --- a/dhcp/conn_linux.go +++ b/dhcp/conn_linux.go @@ -153,19 +153,19 @@ func (c *linuxConn) SendDHCP(pkt *Packet, intf *net.Interface) error { Protocol: 17, } - switch pkt.TxType() { - case TxBroadcast, TxHardwareAddr: + switch pkt.txType() { + case txBroadcast, txHardwareAddr: hdr.Dst = net.IPv4bcast cm := ipv4.ControlMessage{ IfIndex: intf.Index, } return c.conn.WriteTo(&hdr, raw, &cm) - case TxRelayAddr: + case txRelayAddr: // Send to the server port, not the client port. binary.BigEndian.PutUint16(raw[2:4], 67) hdr.Dst = pkt.RelayAddr return c.conn.WriteTo(&hdr, raw, nil) - case TxClientAddr: + case txClientAddr: hdr.Dst = pkt.ClientAddr return c.conn.WriteTo(&hdr, raw, nil) default: diff --git a/dhcp/options.go b/dhcp/options.go index 3e128e7..de639f9 100644 --- a/dhcp/options.go +++ b/dhcp/options.go @@ -68,22 +68,15 @@ func (o Options) Unmarshal(bs []byte) error { // Marshal returns the wire encoding of o. func (o Options) Marshal() ([]byte, error) { 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 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 { - 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. diff --git a/dhcp/packet.go b/dhcp/packet.go index d23ce73..2297bae 100644 --- a/dhcp/packet.go +++ b/dhcp/packet.go @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package dhcp implements parsing and serialization of DHCP packets. package dhcp import ( @@ -83,23 +82,22 @@ type Packet struct { Options Options } -// TxType determines how the Packet should be sent on the wire, based -// on its field values. +// decides how to send Packet on the wire, based on its field values. // // This implements the transmission decision process in section 4.1 of // RFC 2131. -func (p *Packet) TxType() TxType { +func (p *Packet) txType() txType { switch { case p.RelayAddr != nil && p.RelayAddr.IsGlobalUnicast(): - return TxRelayAddr + return txRelayAddr case p.Type == MsgNack: - return TxBroadcast + return txBroadcast case p.ClientAddr != nil && (p.ClientAddr.IsGlobalUnicast() || p.ClientAddr.IsLoopback()): - return TxClientAddr + return txClientAddr case p.Broadcast: - return TxBroadcast + return txBroadcast default: - return TxHardwareAddr + return txHardwareAddr } } @@ -227,9 +225,13 @@ func (p *Packet) Marshal() ([]byte, error) { } ret.Write(magic) - if err := opts.MarshalTo(ret); err != nil { + leftover, err := opts.marshalLimited(ret, 0, false) + if err != nil { 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 } diff --git a/dhcp/server.go b/dhcp/server.go deleted file mode 100644 index 500b15f..0000000 --- a/dhcp/server.go +++ /dev/null @@ -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 -}