mirror of
https://github.com/danderson/netboot.git
synced 2025-08-10 08:37:10 +02:00
gofmt -s all the things again.
This commit is contained in:
parent
bcaa633b65
commit
7de0228ec0
@ -1,18 +1,18 @@
|
|||||||
package dhcp6
|
package dhcp6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"golang.org/x/net/ipv6"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/net/ipv6"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conn is dhcpv6-specific socket
|
// Conn is dhcpv6-specific socket
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
conn *ipv6.PacketConn
|
conn *ipv6.PacketConn
|
||||||
group net.IP
|
group net.IP
|
||||||
ifi *net.Interface
|
ifi *net.Interface
|
||||||
listenAddress string
|
listenAddress string
|
||||||
listenPort string
|
listenPort string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConn creates a new Conn bound to specified address and port
|
// NewConn creates a new Conn bound to specified address and port
|
||||||
@ -23,7 +23,7 @@ func NewConn(addr, port string) (*Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group := net.ParseIP("ff02::1:2")
|
group := net.ParseIP("ff02::1:2")
|
||||||
c, err := net.ListenPacket("udp6", "[::]:" + port)
|
c, err := net.ListenPacket("udp6", "[::]:"+port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -33,17 +33,17 @@ func NewConn(addr, port string) (*Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pc.SetControlMessage(ipv6.FlagSrc | ipv6.FlagDst, true); err != nil {
|
if err := pc.SetControlMessage(ipv6.FlagSrc|ipv6.FlagDst, true); err != nil {
|
||||||
pc.Close()
|
pc.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Conn{
|
return &Conn{
|
||||||
conn: pc,
|
conn: pc,
|
||||||
group: group,
|
group: group,
|
||||||
ifi: ifi,
|
ifi: ifi,
|
||||||
listenAddress: addr,
|
listenAddress: addr,
|
||||||
listenPort: port,
|
listenPort: port,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,10 +110,11 @@ func (c *Conn) RecvDHCP() (*Packet, net.IP, error) {
|
|||||||
// SendDHCP sends a dhcp packet to the specified ip address using Conn
|
// SendDHCP sends a dhcp packet to the specified ip address using Conn
|
||||||
func (c *Conn) SendDHCP(dst net.IP, p []byte) error {
|
func (c *Conn) SendDHCP(dst net.IP, p []byte) error {
|
||||||
dstAddr := &net.UDPAddr{
|
dstAddr := &net.UDPAddr{
|
||||||
IP: dst,
|
IP: dst,
|
||||||
Port: 546,
|
Port: 546,
|
||||||
}
|
}
|
||||||
_, err := c.conn.WriteTo(p, nil, dstAddr); if err != nil {
|
_, err := c.conn.WriteTo(p, nil, dstAddr)
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("Error sending a reply to %s: %s", dst.String(), err)
|
return fmt.Errorf("Error sending a reply to %s: %s", dst.String(), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,58 +1,58 @@
|
|||||||
package dhcp6
|
package dhcp6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"bytes"
|
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DHCPv6 option IDs
|
// DHCPv6 option IDs
|
||||||
const (
|
const (
|
||||||
// Client ID Option
|
// Client ID Option
|
||||||
OptClientID uint16 = 1
|
OptClientID uint16 = 1
|
||||||
// Server ID Option
|
// Server ID Option
|
||||||
OptServerID = 2
|
OptServerID = 2
|
||||||
// Identity Association for Non-temporary Addresses Option
|
// Identity Association for Non-temporary Addresses Option
|
||||||
OptIaNa = 3
|
OptIaNa = 3
|
||||||
// Identity Association for Temporary Addresses Option
|
// Identity Association for Temporary Addresses Option
|
||||||
OptIaTa = 4
|
OptIaTa = 4
|
||||||
// IA Address Option
|
// IA Address Option
|
||||||
OptIaAddr = 5
|
OptIaAddr = 5
|
||||||
// Option Request Option
|
// Option Request Option
|
||||||
OptOro = 6
|
OptOro = 6
|
||||||
// Preference Option
|
// Preference Option
|
||||||
OptPreference = 7
|
OptPreference = 7
|
||||||
// Elapsed Time Option
|
// Elapsed Time Option
|
||||||
OptElapsedTime = 8
|
OptElapsedTime = 8
|
||||||
// Relay Message Option
|
// Relay Message Option
|
||||||
OptRelayMessage = 9
|
OptRelayMessage = 9
|
||||||
// Authentication Option
|
// Authentication Option
|
||||||
OptAuth = 11
|
OptAuth = 11
|
||||||
// Server Unicast Option
|
// Server Unicast Option
|
||||||
OptUnicast = 12
|
OptUnicast = 12
|
||||||
// Status Code Option
|
// Status Code Option
|
||||||
OptStatusCode = 13
|
OptStatusCode = 13
|
||||||
// Rapid Commit Option
|
// Rapid Commit Option
|
||||||
OptRapidCommit = 14
|
OptRapidCommit = 14
|
||||||
// User Class Option
|
// User Class Option
|
||||||
OptUserClass = 15
|
OptUserClass = 15
|
||||||
// Vendor Class Option
|
// Vendor Class Option
|
||||||
OptVendorClass = 16
|
OptVendorClass = 16
|
||||||
// Vendor-specific Information Option
|
// Vendor-specific Information Option
|
||||||
OptVendorOpts = 17
|
OptVendorOpts = 17
|
||||||
// Interface-Id Option
|
// Interface-Id Option
|
||||||
OptInterfaceID = 18
|
OptInterfaceID = 18
|
||||||
// Reconfigure Message Option
|
// Reconfigure Message Option
|
||||||
OptReconfMsg = 19
|
OptReconfMsg = 19
|
||||||
// Reconfigure Accept Option
|
// Reconfigure Accept Option
|
||||||
OptReconfAccept = 20
|
OptReconfAccept = 20
|
||||||
// Recursive DNS name servers Option
|
// Recursive DNS name servers Option
|
||||||
OptRecursiveDNS = 23
|
OptRecursiveDNS = 23
|
||||||
// Boot File URL Option
|
// Boot File URL Option
|
||||||
OptBootfileURL = 59
|
OptBootfileURL = 59
|
||||||
// Boot File Parameters Option
|
// Boot File Parameters Option
|
||||||
OptBootfileParam = 60
|
OptBootfileParam = 60
|
||||||
// Client Architecture Type Option
|
// Client Architecture Type Option
|
||||||
OptClientArchType = 61
|
OptClientArchType = 61
|
||||||
)
|
)
|
||||||
@ -66,7 +66,7 @@ type Option struct {
|
|||||||
|
|
||||||
// MakeOption creates an Option with given ID and value
|
// MakeOption creates an Option with given ID and value
|
||||||
func MakeOption(id uint16, value []byte) *Option {
|
func MakeOption(id uint16, value []byte) *Option {
|
||||||
return &Option{ ID: id, Length: uint16(len(value)), Value: value}
|
return &Option{ID: id, Length: uint16(len(value)), Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options contains all options of a DHCPv6 packet
|
// Options contains all options of a DHCPv6 packet
|
||||||
@ -80,7 +80,7 @@ func UnmarshalOptions(bs []byte) (Options, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ret[o.ID] = append(ret[o.ID], &Option{ ID: o.ID, Length: o.Length, Value: bs[4 : 4+o.Length]})
|
ret[o.ID] = append(ret[o.ID], &Option{ID: o.ID, Length: o.Length, Value: bs[4 : 4+o.Length]})
|
||||||
bs = bs[4+o.Length:]
|
bs = bs[4+o.Length:]
|
||||||
}
|
}
|
||||||
return ret, nil
|
return ret, nil
|
||||||
@ -95,7 +95,7 @@ func UnmarshalOption(bs []byte) (*Option, error) {
|
|||||||
// parse server_id
|
// parse server_id
|
||||||
//parse ipaddr
|
//parse ipaddr
|
||||||
case OptOro:
|
case OptOro:
|
||||||
if optionLength% 2 != 0 {
|
if optionLength%2 != 0 {
|
||||||
return nil, fmt.Errorf("OptionID request for options (6) length should be even number of bytes: %d", optionLength)
|
return nil, fmt.Errorf("OptionID request for options (6) length should be even number of bytes: %d", optionLength)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -104,14 +104,14 @@ func UnmarshalOption(bs []byte) (*Option, error) {
|
|||||||
return nil, fmt.Errorf("option %d claims to have %d bytes of payload, but only has %d bytes", optionID, optionLength, len(bs[4:]))
|
return nil, fmt.Errorf("option %d claims to have %d bytes of payload, but only has %d bytes", optionID, optionLength, len(bs[4:]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Option{ ID: optionID, Length: optionLength, Value: bs[4 : 4+optionLength]}, nil
|
return &Option{ID: optionID, Length: optionLength, Value: bs[4 : 4+optionLength]}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HumanReadable presents DHCPv6 options in a human-readable form
|
// HumanReadable presents DHCPv6 options in a human-readable form
|
||||||
func (o Options) HumanReadable() []string {
|
func (o Options) HumanReadable() []string {
|
||||||
ret := make([]string, 0, len(o))
|
ret := make([]string, 0, len(o))
|
||||||
for _, multipleOptions := range(o) {
|
for _, multipleOptions := range o {
|
||||||
for _, option := range(multipleOptions) {
|
for _, option := range multipleOptions {
|
||||||
switch option.ID {
|
switch option.ID {
|
||||||
case 3:
|
case 3:
|
||||||
ret = append(ret, o.humanReadableIaNa(*option)...)
|
ret = append(ret, o.humanReadableIaNa(*option)...)
|
||||||
@ -137,7 +137,6 @@ func (o Options) humanReadableIaNa(opt Option) []string {
|
|||||||
l := uint16(binary.BigEndian.Uint16(iaOptions[2:4]))
|
l := uint16(binary.BigEndian.Uint16(iaOptions[2:4]))
|
||||||
id := uint16(binary.BigEndian.Uint16(iaOptions[0:2]))
|
id := uint16(binary.BigEndian.Uint16(iaOptions[0:2]))
|
||||||
|
|
||||||
|
|
||||||
switch id {
|
switch id {
|
||||||
case OptIaAddr:
|
case OptIaAddr:
|
||||||
ip := make(net.IP, 16)
|
ip := make(net.IP, 16)
|
||||||
@ -157,7 +156,8 @@ func (o Options) humanReadableIaNa(opt Option) []string {
|
|||||||
|
|
||||||
// Add adds an option to Options
|
// Add adds an option to Options
|
||||||
func (o Options) Add(option *Option) {
|
func (o Options) Add(option *Option) {
|
||||||
_, present := o[option.ID]; if !present {
|
_, present := o[option.ID]
|
||||||
|
if !present {
|
||||||
o[option.ID] = make([]*Option, 0)
|
o[option.ID] = make([]*Option, 0)
|
||||||
}
|
}
|
||||||
o[option.ID] = append(o[option.ID], option)
|
o[option.ID] = append(o[option.ID], option)
|
||||||
@ -168,7 +168,7 @@ func (o Options) Add(option *Option) {
|
|||||||
// (an IA Address Option or a Status Option)
|
// (an IA Address Option or a Status Option)
|
||||||
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaOption *Option) *Option {
|
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaOption *Option) *Option {
|
||||||
serializedIaOption, _ := iaOption.Marshal()
|
serializedIaOption, _ := iaOption.Marshal()
|
||||||
value := make([]byte, 12 + len(serializedIaOption))
|
value := make([]byte, 12+len(serializedIaOption))
|
||||||
copy(value[0:], iaid[0:4])
|
copy(value[0:], iaid[0:4])
|
||||||
binary.BigEndian.PutUint32(value[4:], t1)
|
binary.BigEndian.PutUint32(value[4:], t1)
|
||||||
binary.BigEndian.PutUint32(value[8:], t2)
|
binary.BigEndian.PutUint32(value[8:], t2)
|
||||||
@ -188,7 +188,7 @@ func MakeIaAddrOption(addr net.IP, preferredLifetime, validLifetime uint32) *Opt
|
|||||||
|
|
||||||
// MakeStatusOption creates a Status Option with given status code and message
|
// MakeStatusOption creates a Status Option with given status code and message
|
||||||
func MakeStatusOption(statusCode uint16, message string) *Option {
|
func MakeStatusOption(statusCode uint16, message string) *Option {
|
||||||
value := make([]byte, 2 + len(message))
|
value := make([]byte, 2+len(message))
|
||||||
binary.BigEndian.PutUint16(value[0:], statusCode)
|
binary.BigEndian.PutUint16(value[0:], statusCode)
|
||||||
copy(value[2:], []byte(message))
|
copy(value[2:], []byte(message))
|
||||||
return MakeOption(OptStatusCode, value)
|
return MakeOption(OptStatusCode, value)
|
||||||
@ -206,8 +206,8 @@ func MakeDNSServersOption(addresses []net.IP) *Option {
|
|||||||
// Marshal serializes Options
|
// Marshal serializes Options
|
||||||
func (o Options) Marshal() ([]byte, error) {
|
func (o Options) Marshal() ([]byte, error) {
|
||||||
buffer := bytes.NewBuffer(make([]byte, 0, 1446))
|
buffer := bytes.NewBuffer(make([]byte, 0, 1446))
|
||||||
for _, multipleOptions := range(o) {
|
for _, multipleOptions := range o {
|
||||||
for _, o := range (multipleOptions) {
|
for _, o := range multipleOptions {
|
||||||
serialized, err := o.Marshal()
|
serialized, err := o.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error serializing option value: %s", err)
|
return nil, fmt.Errorf("Error serializing option value: %s", err)
|
||||||
@ -222,7 +222,7 @@ func (o Options) Marshal() ([]byte, error) {
|
|||||||
|
|
||||||
// Marshal serializes the Option
|
// Marshal serializes the Option
|
||||||
func (o *Option) Marshal() ([]byte, error) {
|
func (o *Option) Marshal() ([]byte, error) {
|
||||||
buffer := bytes.NewBuffer(make([]byte, 0, o.Length + 2))
|
buffer := bytes.NewBuffer(make([]byte, 0, o.Length+2))
|
||||||
|
|
||||||
err := binary.Write(buffer, binary.BigEndian, o.ID)
|
err := binary.Write(buffer, binary.BigEndian, o.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -243,7 +243,8 @@ func (o *Option) Marshal() ([]byte, error) {
|
|||||||
func (o Options) UnmarshalOptionRequestOption() map[uint16]bool {
|
func (o Options) UnmarshalOptionRequestOption() map[uint16]bool {
|
||||||
ret := make(map[uint16]bool)
|
ret := make(map[uint16]bool)
|
||||||
|
|
||||||
_, present := o[OptOro]; if !present {
|
_, present := o[OptOro]
|
||||||
|
if !present {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,8 +316,8 @@ func (o Options) IaNaIDs() [][]byte {
|
|||||||
options, exists := o[OptIaNa]
|
options, exists := o[OptIaNa]
|
||||||
ret := make([][]byte, 0)
|
ret := make([][]byte, 0)
|
||||||
if exists {
|
if exists {
|
||||||
for _, option := range(options) {
|
for _, option := range options {
|
||||||
ret = append(ret, option.Value[0:4])
|
ret = append(ret, option.Value[0:4])
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@ -340,4 +341,3 @@ func (o Options) BootFileURL() []byte {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package dhcp6
|
package dhcp6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net"
|
"net"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMarshalOption(t *testing.T) {
|
func TestMarshalOption(t *testing.T) {
|
||||||
@ -85,8 +85,8 @@ func TestMakeStatusOption(t *testing.T) {
|
|||||||
if noAddrOption.ID != OptStatusCode {
|
if noAddrOption.ID != OptStatusCode {
|
||||||
t.Fatalf("Expected option id %d, got %d", OptStatusCode, noAddrOption.ID)
|
t.Fatalf("Expected option id %d, got %d", OptStatusCode, noAddrOption.ID)
|
||||||
}
|
}
|
||||||
if noAddrOption.Length != uint16(2 + len(expectedMessage)) {
|
if noAddrOption.Length != uint16(2+len(expectedMessage)) {
|
||||||
t.Fatalf("Expected option length of %d, got %d", 2 + len(expectedMessage), noAddrOption.Length)
|
t.Fatalf("Expected option length of %d, got %d", 2+len(expectedMessage), noAddrOption.Length)
|
||||||
}
|
}
|
||||||
if binary.BigEndian.Uint16(noAddrOption.Value[0:2]) != expectedStatusCode {
|
if binary.BigEndian.Uint16(noAddrOption.Value[0:2]) != expectedStatusCode {
|
||||||
t.Fatalf("Expected status code 2, got %d", binary.BigEndian.Uint16(noAddrOption.Value[0:2]))
|
t.Fatalf("Expected status code 2, got %d", binary.BigEndian.Uint16(noAddrOption.Value[0:2]))
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package dhcp6
|
package dhcp6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MessageType contains ID identifying DHCP message type. See RFC 3315
|
// MessageType contains ID identifying DHCP message type. See RFC 3315
|
||||||
@ -50,7 +50,7 @@ func (p *Packet) Marshal() ([]byte, error) {
|
|||||||
return nil, fmt.Errorf("packet has malformed options section: %s", err)
|
return nil, fmt.Errorf("packet has malformed options section: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := make([]byte, len(marshalledOptions) + 4, len(marshalledOptions) + 4)
|
ret := make([]byte, len(marshalledOptions)+4, len(marshalledOptions)+4)
|
||||||
ret[0] = byte(p.Type)
|
ret[0] = byte(p.Type)
|
||||||
copy(ret[1:], p.TransactionID[:])
|
copy(ret[1:], p.TransactionID[:])
|
||||||
copy(ret[4:], marshalledOptions)
|
copy(ret[4:], marshalledOptions)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package dhcp6
|
package dhcp6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"hash/fnv"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"hash/fnv"
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ func (b *PacketBuilder) BuildResponse(in *Packet, serverDUID []byte, configurati
|
|||||||
}
|
}
|
||||||
associations, err := addresses.ReserveAddresses(in.Options.ClientID(), in.Options.IaNaIDs())
|
associations, err := addresses.ReserveAddresses(in.Options.ClientID(), in.Options.IaNaIDs())
|
||||||
return b.makeMsgReply(in.TransactionID, serverDUID, in.Options.ClientID(),
|
return b.makeMsgReply(in.TransactionID, serverDUID, in.Options.ClientID(),
|
||||||
in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIDs()), bootFileURL,
|
in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIDs()), bootFileURL,
|
||||||
configuration.GetRecursiveDNS(), err), err
|
configuration.GetRecursiveDNS(), err), err
|
||||||
case MsgInformationRequest:
|
case MsgInformationRequest:
|
||||||
bootFileURL, err := configuration.GetBootURL(b.extractLLAddressOrID(in.Options.ClientID()), in.Options.ClientArchType())
|
bootFileURL, err := configuration.GetBootURL(b.extractLLAddressOrID(in.Options.ClientID()), in.Options.ClientArchType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -59,18 +59,21 @@ func (b *PacketBuilder) makeMsgAdvertise(transactionID [3]byte, serverDUID, clie
|
|||||||
associations []*IdentityAssociation, bootFileURL, preference []byte, dnsServers []net.IP) *Packet {
|
associations []*IdentityAssociation, bootFileURL, preference []byte, dnsServers []net.IP) *Packet {
|
||||||
retOptions := make(Options)
|
retOptions := make(Options)
|
||||||
retOptions.Add(MakeOption(OptClientID, clientID))
|
retOptions.Add(MakeOption(OptClientID, clientID))
|
||||||
for _, association := range(associations) {
|
for _, association := range associations {
|
||||||
retOptions.Add(MakeIaNaOption(association.InterfaceID, b.calculateT1(), b.calculateT2(),
|
retOptions.Add(MakeIaNaOption(association.InterfaceID, b.calculateT1(), b.calculateT2(),
|
||||||
MakeIaAddrOption(association.IPAddress, b.PreferredLifetime, b.ValidLifetime)))
|
MakeIaAddrOption(association.IPAddress, b.PreferredLifetime, b.ValidLifetime)))
|
||||||
}
|
}
|
||||||
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
||||||
if 0x10 == clientArchType { // HTTPClient
|
if 0x10 == clientArchType { // HTTPClient
|
||||||
retOptions.Add(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
retOptions.Add(MakeOption(OptVendorClass, []byte{0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
||||||
}
|
}
|
||||||
retOptions.Add(MakeOption(OptBootfileURL, bootFileURL))
|
retOptions.Add(MakeOption(OptBootfileURL, bootFileURL))
|
||||||
if preference != nil {
|
if preference != nil {
|
||||||
retOptions.Add(MakeOption(OptPreference, preference))}
|
retOptions.Add(MakeOption(OptPreference, preference))
|
||||||
if len(dnsServers) > 0 { retOptions.Add(MakeDNSServersOption(dnsServers)) }
|
}
|
||||||
|
if len(dnsServers) > 0 {
|
||||||
|
retOptions.Add(MakeDNSServersOption(dnsServers))
|
||||||
|
}
|
||||||
|
|
||||||
return &Packet{Type: MsgAdvertise, TransactionID: transactionID, Options: retOptions}
|
return &Packet{Type: MsgAdvertise, TransactionID: transactionID, Options: retOptions}
|
||||||
}
|
}
|
||||||
@ -79,20 +82,22 @@ func (b *PacketBuilder) makeMsgReply(transactionID [3]byte, serverDUID, clientID
|
|||||||
associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileURL []byte, dnsServers []net.IP, err error) *Packet {
|
associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileURL []byte, dnsServers []net.IP, err error) *Packet {
|
||||||
retOptions := make(Options)
|
retOptions := make(Options)
|
||||||
retOptions.Add(MakeOption(OptClientID, clientID))
|
retOptions.Add(MakeOption(OptClientID, clientID))
|
||||||
for _, association := range(associations) {
|
for _, association := range associations {
|
||||||
retOptions.Add(MakeIaNaOption(association.InterfaceID, b.calculateT1(), b.calculateT2(),
|
retOptions.Add(MakeIaNaOption(association.InterfaceID, b.calculateT1(), b.calculateT2(),
|
||||||
MakeIaAddrOption(association.IPAddress, b.PreferredLifetime, b.ValidLifetime)))
|
MakeIaAddrOption(association.IPAddress, b.PreferredLifetime, b.ValidLifetime)))
|
||||||
}
|
}
|
||||||
for _, ia := range(iasWithoutAddresses) {
|
for _, ia := range iasWithoutAddresses {
|
||||||
retOptions.Add(MakeIaNaOption(ia, b.calculateT1(), b.calculateT2(),
|
retOptions.Add(MakeIaNaOption(ia, b.calculateT1(), b.calculateT2(),
|
||||||
MakeStatusOption(2, err.Error())))
|
MakeStatusOption(2, err.Error())))
|
||||||
}
|
}
|
||||||
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
||||||
if 0x10 == clientArchType { // HTTPClient
|
if 0x10 == clientArchType { // HTTPClient
|
||||||
retOptions.Add(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
retOptions.Add(MakeOption(OptVendorClass, []byte{0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
||||||
}
|
}
|
||||||
retOptions.Add(MakeOption(OptBootfileURL, bootFileURL))
|
retOptions.Add(MakeOption(OptBootfileURL, bootFileURL))
|
||||||
if len(dnsServers) > 0 { retOptions.Add(MakeDNSServersOption(dnsServers)) }
|
if len(dnsServers) > 0 {
|
||||||
|
retOptions.Add(MakeDNSServersOption(dnsServers))
|
||||||
|
}
|
||||||
|
|
||||||
return &Packet{Type: MsgReply, TransactionID: transactionID, Options: retOptions}
|
return &Packet{Type: MsgReply, TransactionID: transactionID, Options: retOptions}
|
||||||
}
|
}
|
||||||
@ -102,11 +107,13 @@ func (b *PacketBuilder) makeMsgInformationRequestReply(transactionID [3]byte, se
|
|||||||
retOptions := make(Options)
|
retOptions := make(Options)
|
||||||
retOptions.Add(MakeOption(OptClientID, clientID))
|
retOptions.Add(MakeOption(OptClientID, clientID))
|
||||||
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
||||||
if 0x10 == clientArchType { // HTTPClient
|
if 0x10 == clientArchType { // HTTPClient
|
||||||
retOptions.Add(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
retOptions.Add(MakeOption(OptVendorClass, []byte{0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
||||||
}
|
}
|
||||||
retOptions.Add(MakeOption(OptBootfileURL, bootFileURL))
|
retOptions.Add(MakeOption(OptBootfileURL, bootFileURL))
|
||||||
if len(dnsServers) > 0 { retOptions.Add(MakeDNSServersOption(dnsServers)) }
|
if len(dnsServers) > 0 {
|
||||||
|
retOptions.Add(MakeDNSServersOption(dnsServers))
|
||||||
|
}
|
||||||
|
|
||||||
return &Packet{Type: MsgReply, TransactionID: transactionID, Options: retOptions}
|
return &Packet{Type: MsgReply, TransactionID: transactionID, Options: retOptions}
|
||||||
}
|
}
|
||||||
@ -136,7 +143,7 @@ func (b *PacketBuilder) calculateT1() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *PacketBuilder) calculateT2() uint32 {
|
func (b *PacketBuilder) calculateT2() uint32 {
|
||||||
return (b.PreferredLifetime * 4)/5
|
return (b.PreferredLifetime * 4) / 5
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *PacketBuilder) extractLLAddressOrID(optClientID []byte) []byte {
|
func (b *PacketBuilder) extractLLAddressOrID(optClientID []byte) []byte {
|
||||||
@ -155,12 +162,13 @@ func iasWithoutAddesses(availableAssociations []*IdentityAssociation, allIAs [][
|
|||||||
ret := make([][]byte, 0)
|
ret := make([][]byte, 0)
|
||||||
iasWithAddresses := make(map[uint64]bool)
|
iasWithAddresses := make(map[uint64]bool)
|
||||||
|
|
||||||
for _, association := range(availableAssociations) {
|
for _, association := range availableAssociations {
|
||||||
iasWithAddresses[calculateIAIDHash(association.InterfaceID)] = true
|
iasWithAddresses[calculateIAIDHash(association.InterfaceID)] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ia := range(allIAs) {
|
for _, ia := range allIAs {
|
||||||
_, exists := iasWithAddresses[calculateIAIDHash(ia)]; if !exists {
|
_, exists := iasWithAddresses[calculateIAIDHash(ia)]
|
||||||
|
if !exists {
|
||||||
ret = append(ret, ia)
|
ret = append(ret, ia)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package dhcp6
|
package dhcp6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMakeMsgAdvertise(t *testing.T) {
|
func TestMakeMsgAdvertise(t *testing.T) {
|
||||||
@ -86,7 +86,8 @@ func TestMakeMsgAdvertiseShouldSkipDnsServersIfNoneConfigured(t *testing.T) {
|
|||||||
msg := builder.makeMsgAdvertise(transactionID, expectedServerID, expectedClientID, 0x11,
|
msg := builder.makeMsgAdvertise(transactionID, expectedServerID, expectedClientID, 0x11,
|
||||||
[]*IdentityAssociation{identityAssociation}, expectedBootFileURL, nil, []net.IP{})
|
[]*IdentityAssociation{identityAssociation}, expectedBootFileURL, nil, []net.IP{})
|
||||||
|
|
||||||
_, exists := msg.Options[OptRecursiveDNS]; if exists {
|
_, exists := msg.Options[OptRecursiveDNS]
|
||||||
|
if exists {
|
||||||
t.Fatalf("DNS servers option should not be set")
|
t.Fatalf("DNS servers option should not be set")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +169,8 @@ func TestMakeNoAddrsAvailable(t *testing.T) {
|
|||||||
t.Fatalf("Expected server id %v, got %v", expectedClientID, serverIDOption)
|
t.Fatalf("Expected server id %v, got %v", expectedClientID, serverIDOption)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, exists := msg.Options[OptStatusCode]; if !exists {
|
_, exists := msg.Options[OptStatusCode]
|
||||||
|
if !exists {
|
||||||
t.Fatalf("Expected status code option to be present")
|
t.Fatalf("Expected status code option to be present")
|
||||||
}
|
}
|
||||||
statusCodeOption := msg.Options[OptStatusCode][0].Value
|
statusCodeOption := msg.Options[OptStatusCode][0].Value
|
||||||
@ -258,7 +260,8 @@ func TestMakeMsgReplyShouldSkipDnsServersIfNoneWereConfigured(t *testing.T) {
|
|||||||
msg := builder.makeMsgReply(transactionID, expectedServerID, expectedClientID, 0x11,
|
msg := builder.makeMsgReply(transactionID, expectedServerID, expectedClientID, 0x11,
|
||||||
[]*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileURL, []net.IP{}, nil)
|
[]*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileURL, []net.IP{}, nil)
|
||||||
|
|
||||||
_, exists := msg.Options[OptRecursiveDNS]; if exists {
|
_, exists := msg.Options[OptRecursiveDNS]
|
||||||
|
if exists {
|
||||||
t.Fatalf("Dns servers option shouldn't be present")
|
t.Fatalf("Dns servers option shouldn't be present")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,7 +416,8 @@ func TestMakeMsgInformationRequestReplyShouldSkipDnsServersIfNoneWereConfigured(
|
|||||||
msg := builder.makeMsgInformationRequestReply(transactionID, expectedServerID, expectedClientID, 0x11,
|
msg := builder.makeMsgInformationRequestReply(transactionID, expectedServerID, expectedClientID, 0x11,
|
||||||
expectedBootFileURL, []net.IP{})
|
expectedBootFileURL, []net.IP{})
|
||||||
|
|
||||||
_, exists := msg.Options[OptRecursiveDNS]; if exists {
|
_, exists := msg.Options[OptRecursiveDNS]
|
||||||
|
if exists {
|
||||||
t.Fatalf("Dns servers option shouldn't be present")
|
t.Fatalf("Dns servers option shouldn't be present")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package dhcp6
|
package dhcp6
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestShouldDiscardSolicitWithoutBootfileUrlOption(t *testing.T) {
|
func TestShouldDiscardSolicitWithoutBootfileUrlOption(t *testing.T) {
|
||||||
@ -93,10 +93,9 @@ func TestShouldDiscardRequestWithWrongServerId(t *testing.T) {
|
|||||||
|
|
||||||
func MakeOptionRequestOptions(options []uint16) *Option {
|
func MakeOptionRequestOptions(options []uint16) *Option {
|
||||||
value := make([]byte, len(options)*2)
|
value := make([]byte, len(options)*2)
|
||||||
for i, option := range(options) {
|
for i, option := range options {
|
||||||
binary.BigEndian.PutUint16(value[i*2:], option)
|
binary.BigEndian.PutUint16(value[i*2:], option)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Option{ID: OptOro, Length: uint16(len(options)*2), Value: value}
|
return &Option{ID: OptOro, Length: uint16(len(options) * 2), Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package pool
|
package pool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
"math/big"
|
|
||||||
"hash/fnv"
|
|
||||||
"sync"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.universe.tf/netboot/dhcp6"
|
"go.universe.tf/netboot/dhcp6"
|
||||||
|
"hash/fnv"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type associationExpiration struct {
|
type associationExpiration struct {
|
||||||
expiresAt time.Time
|
expiresAt time.Time
|
||||||
ia *dhcp6.IdentityAssociation
|
ia *dhcp6.IdentityAssociation
|
||||||
}
|
}
|
||||||
|
|
||||||
type fifo struct {q []interface{}}
|
type fifo struct{ q []interface{} }
|
||||||
|
|
||||||
func newFifo() fifo {
|
func newFifo() fifo {
|
||||||
return fifo{q: make([]interface{}, 0, 1000)}
|
return fifo{q: make([]interface{}, 0, 1000)}
|
||||||
@ -80,9 +80,9 @@ func (p *RandomAddressPool) ReserveAddresses(clientID []byte, interfaceIDs [][]b
|
|||||||
ret := make([]*dhcp6.IdentityAssociation, 0, len(interfaceIDs))
|
ret := make([]*dhcp6.IdentityAssociation, 0, len(interfaceIDs))
|
||||||
rng := rand.New(rand.NewSource(p.timeNow().UnixNano()))
|
rng := rand.New(rand.NewSource(p.timeNow().UnixNano()))
|
||||||
|
|
||||||
for _, interfaceID := range (interfaceIDs) {
|
for _, interfaceID := range interfaceIDs {
|
||||||
clientIDHash := p.calculateIAIDHash(clientID, interfaceID)
|
clientIDHash := p.calculateIAIDHash(clientID, interfaceID)
|
||||||
association, exists := p.identityAssociations[clientIDHash];
|
association, exists := p.identityAssociations[clientIDHash]
|
||||||
|
|
||||||
if exists {
|
if exists {
|
||||||
ret = append(ret, association)
|
ret = append(ret, association)
|
||||||
@ -96,13 +96,13 @@ func (p *RandomAddressPool) ReserveAddresses(clientID []byte, interfaceIDs [][]b
|
|||||||
// we assume that ip addresses adhere to high 64 bits for net and subnet ids, low 64 bits are for host id rule
|
// we assume that ip addresses adhere to high 64 bits for net and subnet ids, low 64 bits are for host id rule
|
||||||
hostOffset := rng.Uint64() % p.poolSize
|
hostOffset := rng.Uint64() % p.poolSize
|
||||||
newIP := big.NewInt(0).Add(p.poolStartAddress, big.NewInt(0).SetUint64(hostOffset))
|
newIP := big.NewInt(0).Add(p.poolStartAddress, big.NewInt(0).SetUint64(hostOffset))
|
||||||
_, exists := p.usedIps[newIP.Uint64()];
|
_, exists := p.usedIps[newIP.Uint64()]
|
||||||
if !exists {
|
if !exists {
|
||||||
timeNow := p.timeNow()
|
timeNow := p.timeNow()
|
||||||
association := &dhcp6.IdentityAssociation{ClientID: clientID,
|
association := &dhcp6.IdentityAssociation{ClientID: clientID,
|
||||||
InterfaceID: interfaceID,
|
InterfaceID: interfaceID,
|
||||||
IPAddress: newIP.Bytes(),
|
IPAddress: newIP.Bytes(),
|
||||||
CreatedAt: timeNow}
|
CreatedAt: timeNow}
|
||||||
p.identityAssociations[clientIDHash] = association
|
p.identityAssociations[clientIDHash] = association
|
||||||
p.usedIps[newIP.Uint64()] = struct{}{}
|
p.usedIps[newIP.Uint64()] = struct{}{}
|
||||||
p.identityAssociationExpirations.Push(&associationExpiration{expiresAt: p.calculateAssociationExpiration(timeNow), ia: association})
|
p.identityAssociationExpirations.Push(&associationExpiration{expiresAt: p.calculateAssociationExpiration(timeNow), ia: association})
|
||||||
@ -116,11 +116,11 @@ func (p *RandomAddressPool) ReserveAddresses(clientID []byte, interfaceIDs [][]b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReleaseAddresses returns IP addresses associated with ClientID and interfaceIDs back into the address pool
|
// ReleaseAddresses returns IP addresses associated with ClientID and interfaceIDs back into the address pool
|
||||||
func (p *RandomAddressPool) ReleaseAddresses(clientID []byte, interfaceIDs [][]byte) {
|
func (p *RandomAddressPool) ReleaseAddresses(clientID []byte, interfaceIDs [][]byte) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
for _, interfaceID := range(interfaceIDs) {
|
for _, interfaceID := range interfaceIDs {
|
||||||
association, exists := p.identityAssociations[p.calculateIAIDHash(clientID, interfaceID)]
|
association, exists := p.identityAssociations[p.calculateIAIDHash(clientID, interfaceID)]
|
||||||
if !exists {
|
if !exists {
|
||||||
continue
|
continue
|
||||||
@ -134,9 +134,13 @@ func (p *RandomAddressPool) ReleaseAddresses(clientID []byte, interfaceIDs [][]
|
|||||||
// back into the address pool. Note it should be called from under the RandomAddressPool.lock.
|
// back into the address pool. Note it should be called from under the RandomAddressPool.lock.
|
||||||
func (p *RandomAddressPool) expireIdentityAssociations() {
|
func (p *RandomAddressPool) expireIdentityAssociations() {
|
||||||
for {
|
for {
|
||||||
if p.identityAssociationExpirations.Size() < 1 { break }
|
if p.identityAssociationExpirations.Size() < 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
expiration := p.identityAssociationExpirations.Peek().(*associationExpiration)
|
expiration := p.identityAssociationExpirations.Peek().(*associationExpiration)
|
||||||
if p.timeNow().Before(expiration.expiresAt) { break }
|
if p.timeNow().Before(expiration.expiresAt) {
|
||||||
|
break
|
||||||
|
}
|
||||||
p.identityAssociationExpirations.Shift()
|
p.identityAssociationExpirations.Shift()
|
||||||
delete(p.identityAssociations, p.calculateIAIDHash(expiration.ia.ClientID, expiration.ia.InterfaceID))
|
delete(p.identityAssociations, p.calculateIAIDHash(expiration.ia.ClientID, expiration.ia.InterfaceID))
|
||||||
delete(p.usedIps, big.NewInt(0).SetBytes(expiration.ia.IPAddress).Uint64())
|
delete(p.usedIps, big.NewInt(0).SetBytes(expiration.ia.IPAddress).Uint64())
|
||||||
@ -144,7 +148,7 @@ func (p *RandomAddressPool) expireIdentityAssociations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *RandomAddressPool) calculateAssociationExpiration(now time.Time) time.Time {
|
func (p *RandomAddressPool) calculateAssociationExpiration(now time.Time) time.Time {
|
||||||
return now.Add(time.Duration(p.validLifetime)*time.Second)
|
return now.Add(time.Duration(p.validLifetime) * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RandomAddressPool) calculateIAIDHash(clientID, interfaceID []byte) uint64 {
|
func (p *RandomAddressPool) calculateIAIDHash(clientID, interfaceID []byte) uint64 {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package pool
|
package pool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"net"
|
"net"
|
||||||
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,26 +22,26 @@ func TestReserveAddress(t *testing.T) {
|
|||||||
if len(ias) != 2 {
|
if len(ias) != 2 {
|
||||||
t.Fatalf("Expected 2 identity associations but received %d", len(ias))
|
t.Fatalf("Expected 2 identity associations but received %d", len(ias))
|
||||||
}
|
}
|
||||||
if string(ias[0].IPAddress) != string(expectedIP1) && string(ias[0].IPAddress) != string(expectedIP2) {
|
if string(ias[0].IPAddress) != string(expectedIP1) && string(ias[0].IPAddress) != string(expectedIP2) {
|
||||||
t.Fatalf("Unexpected ip address: %v", ias[0].IPAddress)
|
t.Fatalf("Unexpected ip address: %v", ias[0].IPAddress)
|
||||||
}
|
}
|
||||||
if string(ias[0].ClientID) != string(expectedClientID) {
|
if string(ias[0].ClientID) != string(expectedClientID) {
|
||||||
t.Fatalf("Expected Client id: %v, but got: %v", expectedClientID, ias[0].ClientID)
|
t.Fatalf("Expected Client id: %v, but got: %v", expectedClientID, ias[0].ClientID)
|
||||||
}
|
}
|
||||||
if string(ias[0].InterfaceID) != string(expectedIAID1) {
|
if string(ias[0].InterfaceID) != string(expectedIAID1) {
|
||||||
t.Fatalf("Expected interface id: %v, but got: %v", expectedIAID1, ias[0].InterfaceID)
|
t.Fatalf("Expected interface id: %v, but got: %v", expectedIAID1, ias[0].InterfaceID)
|
||||||
}
|
}
|
||||||
if ias[0].CreatedAt != expectedTime {
|
if ias[0].CreatedAt != expectedTime {
|
||||||
t.Fatalf("Expected creation time: %v, but got: %v", expectedTime, ias[0].CreatedAt)
|
t.Fatalf("Expected creation time: %v, but got: %v", expectedTime, ias[0].CreatedAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if string(ias[1].IPAddress) != string(expectedIP1) && string(ias[1].IPAddress) != string(expectedIP2) {
|
if string(ias[1].IPAddress) != string(expectedIP1) && string(ias[1].IPAddress) != string(expectedIP2) {
|
||||||
t.Fatalf("Unexpected ip address: %v", ias[0].IPAddress)
|
t.Fatalf("Unexpected ip address: %v", ias[0].IPAddress)
|
||||||
}
|
}
|
||||||
if string(ias[1].ClientID) != string(expectedClientID) {
|
if string(ias[1].ClientID) != string(expectedClientID) {
|
||||||
t.Fatalf("Expected Client id: %v, but got: %v", expectedClientID, ias[1].ClientID)
|
t.Fatalf("Expected Client id: %v, but got: %v", expectedClientID, ias[1].ClientID)
|
||||||
}
|
}
|
||||||
if string(ias[1].InterfaceID) != string(expectedIAID2) {
|
if string(ias[1].InterfaceID) != string(expectedIAID2) {
|
||||||
t.Fatalf("Expected interface id: %v, but got: %v", expectedIAID2, ias[1].InterfaceID)
|
t.Fatalf("Expected interface id: %v, but got: %v", expectedIAID2, ias[1].InterfaceID)
|
||||||
}
|
}
|
||||||
if ias[1].CreatedAt != expectedTime {
|
if ias[1].CreatedAt != expectedTime {
|
||||||
@ -80,7 +80,8 @@ func TestReserveAddressKeepsTrackOfUsedAddresses(t *testing.T) {
|
|||||||
pool.timeNow = func() time.Time { return expectedTime }
|
pool.timeNow = func() time.Time { return expectedTime }
|
||||||
pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID})
|
pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID})
|
||||||
|
|
||||||
_, exists := pool.usedIps[0x01]; if !exists {
|
_, exists := pool.usedIps[0x01]
|
||||||
|
if !exists {
|
||||||
t.Fatal("'2001:db8:f00f:cafe::1' should be marked as in use")
|
t.Fatal("'2001:db8:f00f:cafe::1' should be marked as in use")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +140,8 @@ func TestReleaseAddress(t *testing.T) {
|
|||||||
|
|
||||||
pool.ReleaseAddresses(expectedClientID, [][]byte{expectedIAID})
|
pool.ReleaseAddresses(expectedClientID, [][]byte{expectedIAID})
|
||||||
|
|
||||||
_, exists := pool.identityAssociations[pool.calculateIAIDHash(expectedClientID, expectedIAID)]; if exists {
|
_, exists := pool.identityAssociations[pool.calculateIAIDHash(expectedClientID, expectedIAID)]
|
||||||
|
if exists {
|
||||||
t.Fatalf("identity association for %v should've been removed, but is still available", a[0].IPAddress)
|
t.Fatalf("identity association for %v should've been removed, but is still available", a[0].IPAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package pixiecore
|
package pixiecore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
"strings"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const X86_HTTP_CLIENT = 0x10
|
const X86_HTTP_CLIENT = 0x10
|
||||||
@ -23,7 +23,7 @@ type StaticBootConfiguration struct {
|
|||||||
|
|
||||||
// MakeStaticBootConfiguration creates a new StaticBootConfiguration with provided values
|
// MakeStaticBootConfiguration creates a new StaticBootConfiguration with provided values
|
||||||
func MakeStaticBootConfiguration(httpBootURL, ipxeBootURL string, preference uint8, usePreference bool,
|
func MakeStaticBootConfiguration(httpBootURL, ipxeBootURL string, preference uint8, usePreference bool,
|
||||||
dnsServerAddresses []net.IP) *StaticBootConfiguration {
|
dnsServerAddresses []net.IP) *StaticBootConfiguration {
|
||||||
ret := &StaticBootConfiguration{HTTPBootURL: []byte(httpBootURL), IPxeBootURL: []byte(ipxeBootURL), UsePreference: usePreference}
|
ret := &StaticBootConfiguration{HTTPBootURL: []byte(httpBootURL), IPxeBootURL: []byte(ipxeBootURL), UsePreference: usePreference}
|
||||||
if usePreference {
|
if usePreference {
|
||||||
ret.Preference = make([]byte, 1)
|
ret.Preference = make([]byte, 1)
|
||||||
@ -63,7 +63,7 @@ type APIBootConfiguration struct {
|
|||||||
|
|
||||||
// MakeAPIBootConfiguration creates a new APIBootConfiguration initialized with provided values
|
// MakeAPIBootConfiguration creates a new APIBootConfiguration initialized with provided values
|
||||||
func MakeAPIBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool,
|
func MakeAPIBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool,
|
||||||
dnsServerAddresses []net.IP) *APIBootConfiguration {
|
dnsServerAddresses []net.IP) *APIBootConfiguration {
|
||||||
if !strings.HasSuffix(url, "/") {
|
if !strings.HasSuffix(url, "/") {
|
||||||
url += "/"
|
url += "/"
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
"go.universe.tf/netboot/dhcp6"
|
"go.universe.tf/netboot/dhcp6"
|
||||||
"go.universe.tf/netboot/dhcp6/pool"
|
"go.universe.tf/netboot/dhcp6/pool"
|
||||||
|
"go.universe.tf/netboot/pixiecore"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"go.universe.tf/netboot/pixiecore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// pixiecore bootipv6 --listen-addr=2001:db8:f00f:cafe::4/64 --httpboot-url=http://[2001:db8:f00f:cafe::4]/bootx64.efi --ipxe-url=http://[2001:db8:f00f:cafe::4]/script.ipxe
|
// pixiecore bootipv6 --listen-addr=2001:db8:f00f:cafe::4/64 --httpboot-url=http://[2001:db8:f00f:cafe::4]/bootx64.efi --ipxe-url=http://[2001:db8:f00f:cafe::4]/script.ipxe
|
||||||
@ -35,7 +35,9 @@ var bootIPv6Cmd = &cobra.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
s.Debug = logWithStdFmt
|
s.Debug = logWithStdFmt
|
||||||
}
|
}
|
||||||
if debug { s.Debug = logWithStdFmt }
|
if debug {
|
||||||
|
s.Debug = logWithStdFmt
|
||||||
|
}
|
||||||
|
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
fatalf("Please specify address to bind to")
|
fatalf("Please specify address to bind to")
|
||||||
@ -79,7 +81,7 @@ var bootIPv6Cmd = &cobra.Command{
|
|||||||
fatalf("Error reading flag: %s", err)
|
fatalf("Error reading flag: %s", err)
|
||||||
}
|
}
|
||||||
s.AddressPool = pool.NewRandomAddressPool(net.ParseIP(addressPoolStart), addressPoolSize, addressPoolValidLifetime)
|
s.AddressPool = pool.NewRandomAddressPool(net.ParseIP(addressPoolStart), addressPoolSize, addressPoolValidLifetime)
|
||||||
s.PacketBuilder = dhcp6.MakePacketBuilder(addressPoolValidLifetime - addressPoolValidLifetime*3/100, addressPoolValidLifetime)
|
s.PacketBuilder = dhcp6.MakePacketBuilder(addressPoolValidLifetime-addressPoolValidLifetime*3/100, addressPoolValidLifetime)
|
||||||
|
|
||||||
fmt.Println(s.Serve())
|
fmt.Println(s.Serve())
|
||||||
},
|
},
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
"go.universe.tf/netboot/dhcp6"
|
"go.universe.tf/netboot/dhcp6"
|
||||||
"go.universe.tf/netboot/dhcp6/pool"
|
"go.universe.tf/netboot/dhcp6/pool"
|
||||||
"time"
|
"go.universe.tf/netboot/pixiecore"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"go.universe.tf/netboot/pixiecore"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pixiecore ipv6api --listen-addr=2001:db8:f00f:cafe::4 --api-request-url=http://[2001:db8:f00f:cafe::4]:8888
|
// pixiecore ipv6api --listen-addr=2001:db8:f00f:cafe::4 --api-request-url=http://[2001:db8:f00f:cafe::4]:8888
|
||||||
@ -36,7 +36,9 @@ var ipv6ApiCmd = &cobra.Command{
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
s.Debug = logWithStdFmt
|
s.Debug = logWithStdFmt
|
||||||
}
|
}
|
||||||
if debug { s.Debug = logWithStdFmt }
|
if debug {
|
||||||
|
s.Debug = logWithStdFmt
|
||||||
|
}
|
||||||
|
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
fatalf("Please specify address to bind to")
|
fatalf("Please specify address to bind to")
|
||||||
@ -76,7 +78,7 @@ var ipv6ApiCmd = &cobra.Command{
|
|||||||
fatalf("Error reading flag: %s", err)
|
fatalf("Error reading flag: %s", err)
|
||||||
}
|
}
|
||||||
s.AddressPool = pool.NewRandomAddressPool(net.ParseIP(addressPoolStart), addressPoolSize, addressPoolValidLifetime)
|
s.AddressPool = pool.NewRandomAddressPool(net.ParseIP(addressPoolStart), addressPoolSize, addressPoolValidLifetime)
|
||||||
s.PacketBuilder = dhcp6.MakePacketBuilder(addressPoolValidLifetime - addressPoolValidLifetime*3/100, addressPoolValidLifetime)
|
s.PacketBuilder = dhcp6.MakePacketBuilder(addressPoolValidLifetime-addressPoolValidLifetime*3/100, addressPoolValidLifetime)
|
||||||
|
|
||||||
fmt.Println(s.Serve())
|
fmt.Println(s.Serve())
|
||||||
},
|
},
|
||||||
@ -98,4 +100,3 @@ func init() {
|
|||||||
rootCmd.AddCommand(ipv6ApiCmd)
|
rootCmd.AddCommand(ipv6ApiCmd)
|
||||||
serverv6APIConfigFlags(ipv6ApiCmd)
|
serverv6APIConfigFlags(ipv6ApiCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package pixiecore
|
package pixiecore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.universe.tf/netboot/dhcp6"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go.universe.tf/netboot/dhcp6"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *ServerV6) serveDHCP(conn *dhcp6.Conn) error {
|
func (s *ServerV6) serveDHCP(conn *dhcp6.Conn) error {
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
package pixiecore
|
package pixiecore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.universe.tf/netboot/dhcp6"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"go.universe.tf/netboot/dhcp6"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerV6 struct {
|
type ServerV6 struct {
|
||||||
Address string
|
Address string
|
||||||
Port string
|
Port string
|
||||||
Duid []byte
|
Duid []byte
|
||||||
|
|
||||||
BootConfig dhcp6.BootConfiguration
|
BootConfig dhcp6.BootConfiguration
|
||||||
PacketBuilder *dhcp6.PacketBuilder
|
PacketBuilder *dhcp6.PacketBuilder
|
||||||
AddressPool dhcp6.AddressPool
|
AddressPool dhcp6.AddressPool
|
||||||
|
|
||||||
errs chan error
|
errs chan error
|
||||||
|
|
||||||
Log func(subsystem, msg string)
|
Log func(subsystem, msg string)
|
||||||
Debug func(subsystem, msg string)
|
Debug func(subsystem, msg string)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ func (s *ServerV6) debug(subsystem, format string, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServerV6) SetDUID(addr net.HardwareAddr) {
|
func (s *ServerV6) SetDUID(addr net.HardwareAddr) {
|
||||||
duid := make([]byte, len(addr) + 8) // see rfc3315, section 9.2, DUID-LT
|
duid := make([]byte, len(addr)+8) // see rfc3315, section 9.2, DUID-LT
|
||||||
|
|
||||||
copy(duid[0:], []byte{0, 1}) //fixed, x0001
|
copy(duid[0:], []byte{0, 1}) //fixed, x0001
|
||||||
copy(duid[2:], []byte{0, 1}) //hw type ethernet, x0001
|
copy(duid[2:], []byte{0, 1}) //hw type ethernet, x0001
|
||||||
|
Loading…
Reference in New Issue
Block a user