mirror of
https://github.com/danderson/netboot.git
synced 2025-08-07 15:17:15 +02:00
gofmt -s all the things again.
This commit is contained in:
parent
bcaa633b65
commit
7de0228ec0
@ -1,18 +1,18 @@
|
||||
package dhcp6
|
||||
|
||||
import (
|
||||
"net"
|
||||
"golang.org/x/net/ipv6"
|
||||
"fmt"
|
||||
"golang.org/x/net/ipv6"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Conn is dhcpv6-specific socket
|
||||
type Conn struct {
|
||||
conn *ipv6.PacketConn
|
||||
group net.IP
|
||||
ifi *net.Interface
|
||||
conn *ipv6.PacketConn
|
||||
group net.IP
|
||||
ifi *net.Interface
|
||||
listenAddress string
|
||||
listenPort string
|
||||
listenPort string
|
||||
}
|
||||
|
||||
// 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")
|
||||
c, err := net.ListenPacket("udp6", "[::]:" + port)
|
||||
c, err := net.ListenPacket("udp6", "[::]:"+port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -33,17 +33,17 @@ func NewConn(addr, port string) (*Conn, error) {
|
||||
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()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Conn{
|
||||
conn: pc,
|
||||
group: group,
|
||||
ifi: ifi,
|
||||
conn: pc,
|
||||
group: group,
|
||||
ifi: ifi,
|
||||
listenAddress: addr,
|
||||
listenPort: port,
|
||||
listenPort: port,
|
||||
}, 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
|
||||
func (c *Conn) SendDHCP(dst net.IP, p []byte) error {
|
||||
dstAddr := &net.UDPAddr{
|
||||
IP: dst,
|
||||
IP: dst,
|
||||
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 nil
|
||||
@ -122,4 +123,4 @@ func (c *Conn) SendDHCP(dst net.IP, p []byte) error {
|
||||
// SourceHardwareAddress returns hardware address of the interface used by Conn
|
||||
func (c *Conn) SourceHardwareAddress() net.HardwareAddr {
|
||||
return c.ifi.HardwareAddr
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +1,58 @@
|
||||
package dhcp6
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"bytes"
|
||||
"net"
|
||||
)
|
||||
|
||||
// DHCPv6 option IDs
|
||||
const (
|
||||
// Client ID Option
|
||||
OptClientID uint16 = 1
|
||||
OptClientID uint16 = 1
|
||||
// Server ID Option
|
||||
OptServerID = 2
|
||||
OptServerID = 2
|
||||
// Identity Association for Non-temporary Addresses Option
|
||||
OptIaNa = 3
|
||||
OptIaNa = 3
|
||||
// Identity Association for Temporary Addresses Option
|
||||
OptIaTa = 4
|
||||
OptIaTa = 4
|
||||
// IA Address Option
|
||||
OptIaAddr = 5
|
||||
OptIaAddr = 5
|
||||
// Option Request Option
|
||||
OptOro = 6
|
||||
OptOro = 6
|
||||
// Preference Option
|
||||
OptPreference = 7
|
||||
OptPreference = 7
|
||||
// Elapsed Time Option
|
||||
OptElapsedTime = 8
|
||||
OptElapsedTime = 8
|
||||
// Relay Message Option
|
||||
OptRelayMessage = 9
|
||||
OptRelayMessage = 9
|
||||
// Authentication Option
|
||||
OptAuth = 11
|
||||
OptAuth = 11
|
||||
// Server Unicast Option
|
||||
OptUnicast = 12
|
||||
OptUnicast = 12
|
||||
// Status Code Option
|
||||
OptStatusCode = 13
|
||||
OptStatusCode = 13
|
||||
// Rapid Commit Option
|
||||
OptRapidCommit = 14
|
||||
OptRapidCommit = 14
|
||||
// User Class Option
|
||||
OptUserClass = 15
|
||||
OptUserClass = 15
|
||||
// Vendor Class Option
|
||||
OptVendorClass = 16
|
||||
OptVendorClass = 16
|
||||
// Vendor-specific Information Option
|
||||
OptVendorOpts = 17
|
||||
OptVendorOpts = 17
|
||||
// Interface-Id Option
|
||||
OptInterfaceID = 18
|
||||
OptInterfaceID = 18
|
||||
// Reconfigure Message Option
|
||||
OptReconfMsg = 19
|
||||
OptReconfMsg = 19
|
||||
// Reconfigure Accept Option
|
||||
OptReconfAccept = 20
|
||||
OptReconfAccept = 20
|
||||
// Recursive DNS name servers Option
|
||||
OptRecursiveDNS = 23
|
||||
OptRecursiveDNS = 23
|
||||
// Boot File URL Option
|
||||
OptBootfileURL = 59
|
||||
OptBootfileURL = 59
|
||||
// Boot File Parameters Option
|
||||
OptBootfileParam = 60
|
||||
OptBootfileParam = 60
|
||||
// Client Architecture Type Option
|
||||
OptClientArchType = 61
|
||||
)
|
||||
@ -66,7 +66,7 @@ type Option struct {
|
||||
|
||||
// MakeOption creates an Option with given ID and value
|
||||
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
|
||||
@ -80,7 +80,7 @@ func UnmarshalOptions(bs []byte) (Options, error) {
|
||||
if err != nil {
|
||||
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:]
|
||||
}
|
||||
return ret, nil
|
||||
@ -95,7 +95,7 @@ func UnmarshalOption(bs []byte) (*Option, error) {
|
||||
// parse server_id
|
||||
//parse ipaddr
|
||||
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)
|
||||
}
|
||||
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 &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
|
||||
func (o Options) HumanReadable() []string {
|
||||
ret := make([]string, 0, len(o))
|
||||
for _, multipleOptions := range(o) {
|
||||
for _, option := range(multipleOptions) {
|
||||
for _, multipleOptions := range o {
|
||||
for _, option := range multipleOptions {
|
||||
switch option.ID {
|
||||
case 3:
|
||||
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]))
|
||||
id := uint16(binary.BigEndian.Uint16(iaOptions[0:2]))
|
||||
|
||||
|
||||
switch id {
|
||||
case OptIaAddr:
|
||||
ip := make(net.IP, 16)
|
||||
@ -157,7 +156,8 @@ func (o Options) humanReadableIaNa(opt Option) []string {
|
||||
|
||||
// Add adds an option to Options
|
||||
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] = append(o[option.ID], option)
|
||||
@ -168,7 +168,7 @@ func (o Options) Add(option *Option) {
|
||||
// (an IA Address Option or a Status Option)
|
||||
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaOption *Option) *Option {
|
||||
serializedIaOption, _ := iaOption.Marshal()
|
||||
value := make([]byte, 12 + len(serializedIaOption))
|
||||
value := make([]byte, 12+len(serializedIaOption))
|
||||
copy(value[0:], iaid[0:4])
|
||||
binary.BigEndian.PutUint32(value[4:], t1)
|
||||
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
|
||||
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)
|
||||
copy(value[2:], []byte(message))
|
||||
return MakeOption(OptStatusCode, value)
|
||||
@ -206,8 +206,8 @@ func MakeDNSServersOption(addresses []net.IP) *Option {
|
||||
// Marshal serializes Options
|
||||
func (o Options) Marshal() ([]byte, error) {
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, 1446))
|
||||
for _, multipleOptions := range(o) {
|
||||
for _, o := range (multipleOptions) {
|
||||
for _, multipleOptions := range o {
|
||||
for _, o := range multipleOptions {
|
||||
serialized, err := o.Marshal()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error serializing option value: %s", err)
|
||||
@ -222,7 +222,7 @@ func (o Options) Marshal() ([]byte, error) {
|
||||
|
||||
// Marshal serializes the Option
|
||||
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)
|
||||
if err != nil {
|
||||
@ -243,7 +243,8 @@ func (o *Option) Marshal() ([]byte, error) {
|
||||
func (o Options) UnmarshalOptionRequestOption() map[uint16]bool {
|
||||
ret := make(map[uint16]bool)
|
||||
|
||||
_, present := o[OptOro]; if !present {
|
||||
_, present := o[OptOro]
|
||||
if !present {
|
||||
return ret
|
||||
}
|
||||
|
||||
@ -315,8 +316,8 @@ func (o Options) IaNaIDs() [][]byte {
|
||||
options, exists := o[OptIaNa]
|
||||
ret := make([][]byte, 0)
|
||||
if exists {
|
||||
for _, option := range(options) {
|
||||
ret = append(ret, option.Value[0:4])
|
||||
for _, option := range options {
|
||||
ret = append(ret, option.Value[0:4])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@ -340,4 +341,3 @@ func (o Options) BootFileURL() []byte {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
package dhcp6
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMarshalOption(t *testing.T) {
|
||||
@ -85,8 +85,8 @@ func TestMakeStatusOption(t *testing.T) {
|
||||
if noAddrOption.ID != OptStatusCode {
|
||||
t.Fatalf("Expected option id %d, got %d", OptStatusCode, noAddrOption.ID)
|
||||
}
|
||||
if noAddrOption.Length != uint16(2 + len(expectedMessage)) {
|
||||
t.Fatalf("Expected option length of %d, got %d", 2 + len(expectedMessage), noAddrOption.Length)
|
||||
if noAddrOption.Length != uint16(2+len(expectedMessage)) {
|
||||
t.Fatalf("Expected option length of %d, got %d", 2+len(expectedMessage), noAddrOption.Length)
|
||||
}
|
||||
if binary.BigEndian.Uint16(noAddrOption.Value[0:2]) != expectedStatusCode {
|
||||
t.Fatalf("Expected status code 2, got %d", binary.BigEndian.Uint16(noAddrOption.Value[0:2]))
|
||||
|
@ -1,8 +1,8 @@
|
||||
package dhcp6
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
ret := make([]byte, len(marshalledOptions) + 4, len(marshalledOptions) + 4)
|
||||
ret := make([]byte, len(marshalledOptions)+4, len(marshalledOptions)+4)
|
||||
ret[0] = byte(p.Type)
|
||||
copy(ret[1:], p.TransactionID[:])
|
||||
copy(ret[4:], marshalledOptions)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package dhcp6
|
||||
|
||||
import (
|
||||
"hash/fnv"
|
||||
"encoding/binary"
|
||||
"hash/fnv"
|
||||
"net"
|
||||
)
|
||||
|
||||
@ -38,8 +38,8 @@ func (b *PacketBuilder) BuildResponse(in *Packet, serverDUID []byte, configurati
|
||||
}
|
||||
associations, err := addresses.ReserveAddresses(in.Options.ClientID(), in.Options.IaNaIDs())
|
||||
return b.makeMsgReply(in.TransactionID, serverDUID, in.Options.ClientID(),
|
||||
in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIDs()), bootFileURL,
|
||||
configuration.GetRecursiveDNS(), err), err
|
||||
in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIDs()), bootFileURL,
|
||||
configuration.GetRecursiveDNS(), err), err
|
||||
case MsgInformationRequest:
|
||||
bootFileURL, err := configuration.GetBootURL(b.extractLLAddressOrID(in.Options.ClientID()), in.Options.ClientArchType())
|
||||
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 {
|
||||
retOptions := make(Options)
|
||||
retOptions.Add(MakeOption(OptClientID, clientID))
|
||||
for _, association := range(associations) {
|
||||
for _, association := range associations {
|
||||
retOptions.Add(MakeIaNaOption(association.InterfaceID, b.calculateT1(), b.calculateT2(),
|
||||
MakeIaAddrOption(association.IPAddress, b.PreferredLifetime, b.ValidLifetime)))
|
||||
}
|
||||
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
||||
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
|
||||
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(OptBootfileURL, bootFileURL))
|
||||
if preference != nil {
|
||||
retOptions.Add(MakeOption(OptPreference, preference))}
|
||||
if len(dnsServers) > 0 { retOptions.Add(MakeDNSServersOption(dnsServers)) }
|
||||
retOptions.Add(MakeOption(OptPreference, preference))
|
||||
}
|
||||
if len(dnsServers) > 0 {
|
||||
retOptions.Add(MakeDNSServersOption(dnsServers))
|
||||
}
|
||||
|
||||
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 {
|
||||
retOptions := make(Options)
|
||||
retOptions.Add(MakeOption(OptClientID, clientID))
|
||||
for _, association := range(associations) {
|
||||
for _, association := range associations {
|
||||
retOptions.Add(MakeIaNaOption(association.InterfaceID, b.calculateT1(), b.calculateT2(),
|
||||
MakeIaAddrOption(association.IPAddress, b.PreferredLifetime, b.ValidLifetime)))
|
||||
}
|
||||
for _, ia := range(iasWithoutAddresses) {
|
||||
for _, ia := range iasWithoutAddresses {
|
||||
retOptions.Add(MakeIaNaOption(ia, b.calculateT1(), b.calculateT2(),
|
||||
MakeStatusOption(2, err.Error())))
|
||||
}
|
||||
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
||||
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
|
||||
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(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}
|
||||
}
|
||||
@ -102,11 +107,13 @@ func (b *PacketBuilder) makeMsgInformationRequestReply(transactionID [3]byte, se
|
||||
retOptions := make(Options)
|
||||
retOptions.Add(MakeOption(OptClientID, clientID))
|
||||
retOptions.Add(MakeOption(OptServerID, serverDUID))
|
||||
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
|
||||
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(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}
|
||||
}
|
||||
@ -136,7 +143,7 @@ func (b *PacketBuilder) calculateT1() uint32 {
|
||||
}
|
||||
|
||||
func (b *PacketBuilder) calculateT2() uint32 {
|
||||
return (b.PreferredLifetime * 4)/5
|
||||
return (b.PreferredLifetime * 4) / 5
|
||||
}
|
||||
|
||||
func (b *PacketBuilder) extractLLAddressOrID(optClientID []byte) []byte {
|
||||
@ -155,12 +162,13 @@ func iasWithoutAddesses(availableAssociations []*IdentityAssociation, allIAs [][
|
||||
ret := make([][]byte, 0)
|
||||
iasWithAddresses := make(map[uint64]bool)
|
||||
|
||||
for _, association := range(availableAssociations) {
|
||||
for _, association := range availableAssociations {
|
||||
iasWithAddresses[calculateIAIDHash(association.InterfaceID)] = true
|
||||
}
|
||||
|
||||
for _, ia := range(allIAs) {
|
||||
_, exists := iasWithAddresses[calculateIAIDHash(ia)]; if !exists {
|
||||
for _, ia := range allIAs {
|
||||
_, exists := iasWithAddresses[calculateIAIDHash(ia)]
|
||||
if !exists {
|
||||
ret = append(ret, ia)
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package dhcp6
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMakeMsgAdvertise(t *testing.T) {
|
||||
@ -86,7 +86,8 @@ func TestMakeMsgAdvertiseShouldSkipDnsServersIfNoneConfigured(t *testing.T) {
|
||||
msg := builder.makeMsgAdvertise(transactionID, expectedServerID, expectedClientID, 0x11,
|
||||
[]*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")
|
||||
}
|
||||
}
|
||||
@ -168,7 +169,8 @@ func TestMakeNoAddrsAvailable(t *testing.T) {
|
||||
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")
|
||||
}
|
||||
statusCodeOption := msg.Options[OptStatusCode][0].Value
|
||||
@ -258,7 +260,8 @@ func TestMakeMsgReplyShouldSkipDnsServersIfNoneWereConfigured(t *testing.T) {
|
||||
msg := builder.makeMsgReply(transactionID, expectedServerID, expectedClientID, 0x11,
|
||||
[]*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")
|
||||
}
|
||||
}
|
||||
@ -413,7 +416,8 @@ func TestMakeMsgInformationRequestReplyShouldSkipDnsServersIfNoneWereConfigured(
|
||||
msg := builder.makeMsgInformationRequestReply(transactionID, expectedServerID, expectedClientID, 0x11,
|
||||
expectedBootFileURL, []net.IP{})
|
||||
|
||||
_, exists := msg.Options[OptRecursiveDNS]; if exists {
|
||||
_, exists := msg.Options[OptRecursiveDNS]
|
||||
if exists {
|
||||
t.Fatalf("Dns servers option shouldn't be present")
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package dhcp6
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShouldDiscardSolicitWithoutBootfileUrlOption(t *testing.T) {
|
||||
@ -93,10 +93,9 @@ func TestShouldDiscardRequestWithWrongServerId(t *testing.T) {
|
||||
|
||||
func MakeOptionRequestOptions(options []uint16) *Option {
|
||||
value := make([]byte, len(options)*2)
|
||||
for i, option := range(options) {
|
||||
for i, option := range options {
|
||||
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
|
||||
|
||||
import (
|
||||
"net"
|
||||
"math/rand"
|
||||
"time"
|
||||
"math/big"
|
||||
"hash/fnv"
|
||||
"sync"
|
||||
"fmt"
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"hash/fnv"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type associationExpiration struct {
|
||||
expiresAt time.Time
|
||||
ia *dhcp6.IdentityAssociation
|
||||
ia *dhcp6.IdentityAssociation
|
||||
}
|
||||
|
||||
type fifo struct {q []interface{}}
|
||||
type fifo struct{ q []interface{} }
|
||||
|
||||
func newFifo() fifo {
|
||||
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))
|
||||
rng := rand.New(rand.NewSource(p.timeNow().UnixNano()))
|
||||
|
||||
for _, interfaceID := range (interfaceIDs) {
|
||||
for _, interfaceID := range interfaceIDs {
|
||||
clientIDHash := p.calculateIAIDHash(clientID, interfaceID)
|
||||
association, exists := p.identityAssociations[clientIDHash];
|
||||
association, exists := p.identityAssociations[clientIDHash]
|
||||
|
||||
if exists {
|
||||
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
|
||||
hostOffset := rng.Uint64() % p.poolSize
|
||||
newIP := big.NewInt(0).Add(p.poolStartAddress, big.NewInt(0).SetUint64(hostOffset))
|
||||
_, exists := p.usedIps[newIP.Uint64()];
|
||||
_, exists := p.usedIps[newIP.Uint64()]
|
||||
if !exists {
|
||||
timeNow := p.timeNow()
|
||||
association := &dhcp6.IdentityAssociation{ClientID: clientID,
|
||||
InterfaceID: interfaceID,
|
||||
IPAddress: newIP.Bytes(),
|
||||
CreatedAt: timeNow}
|
||||
IPAddress: newIP.Bytes(),
|
||||
CreatedAt: timeNow}
|
||||
p.identityAssociations[clientIDHash] = association
|
||||
p.usedIps[newIP.Uint64()] = struct{}{}
|
||||
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
|
||||
func (p *RandomAddressPool) ReleaseAddresses(clientID []byte, interfaceIDs [][]byte) {
|
||||
func (p *RandomAddressPool) ReleaseAddresses(clientID []byte, interfaceIDs [][]byte) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
for _, interfaceID := range(interfaceIDs) {
|
||||
for _, interfaceID := range interfaceIDs {
|
||||
association, exists := p.identityAssociations[p.calculateIAIDHash(clientID, interfaceID)]
|
||||
if !exists {
|
||||
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.
|
||||
func (p *RandomAddressPool) expireIdentityAssociations() {
|
||||
for {
|
||||
if p.identityAssociationExpirations.Size() < 1 { break }
|
||||
if p.identityAssociationExpirations.Size() < 1 {
|
||||
break
|
||||
}
|
||||
expiration := p.identityAssociationExpirations.Peek().(*associationExpiration)
|
||||
if p.timeNow().Before(expiration.expiresAt) { break }
|
||||
if p.timeNow().Before(expiration.expiresAt) {
|
||||
break
|
||||
}
|
||||
p.identityAssociationExpirations.Shift()
|
||||
delete(p.identityAssociations, p.calculateIAIDHash(expiration.ia.ClientID, expiration.ia.InterfaceID))
|
||||
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 {
|
||||
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 {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package pool
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -22,26 +22,26 @@ func TestReserveAddress(t *testing.T) {
|
||||
if len(ias) != 2 {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
if ias[0].CreatedAt != expectedTime {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
if ias[1].CreatedAt != expectedTime {
|
||||
@ -80,7 +80,8 @@ func TestReserveAddressKeepsTrackOfUsedAddresses(t *testing.T) {
|
||||
pool.timeNow = func() time.Time { return expectedTime }
|
||||
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")
|
||||
}
|
||||
}
|
||||
@ -139,7 +140,8 @@ func TestReleaseAddress(t *testing.T) {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package pixiecore
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
"strings"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const X86_HTTP_CLIENT = 0x10
|
||||
@ -23,7 +23,7 @@ type StaticBootConfiguration struct {
|
||||
|
||||
// MakeStaticBootConfiguration creates a new StaticBootConfiguration with provided values
|
||||
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}
|
||||
if usePreference {
|
||||
ret.Preference = make([]byte, 1)
|
||||
@ -63,7 +63,7 @@ type APIBootConfiguration struct {
|
||||
|
||||
// MakeAPIBootConfiguration creates a new APIBootConfiguration initialized with provided values
|
||||
func MakeAPIBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool,
|
||||
dnsServerAddresses []net.IP) *APIBootConfiguration {
|
||||
dnsServerAddresses []net.IP) *APIBootConfiguration {
|
||||
if !strings.HasSuffix(url, "/") {
|
||||
url += "/"
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"go.universe.tf/netboot/dhcp6/pool"
|
||||
"go.universe.tf/netboot/pixiecore"
|
||||
"net"
|
||||
"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
|
||||
@ -35,7 +35,9 @@ var bootIPv6Cmd = &cobra.Command{
|
||||
if err != nil {
|
||||
s.Debug = logWithStdFmt
|
||||
}
|
||||
if debug { s.Debug = logWithStdFmt }
|
||||
if debug {
|
||||
s.Debug = logWithStdFmt
|
||||
}
|
||||
|
||||
if addr == "" {
|
||||
fatalf("Please specify address to bind to")
|
||||
@ -79,7 +81,7 @@ var bootIPv6Cmd = &cobra.Command{
|
||||
fatalf("Error reading flag: %s", err)
|
||||
}
|
||||
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())
|
||||
},
|
||||
|
@ -1,14 +1,14 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"go.universe.tf/netboot/dhcp6/pool"
|
||||
"time"
|
||||
"go.universe.tf/netboot/pixiecore"
|
||||
"net"
|
||||
"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
|
||||
@ -36,7 +36,9 @@ var ipv6ApiCmd = &cobra.Command{
|
||||
if err != nil {
|
||||
s.Debug = logWithStdFmt
|
||||
}
|
||||
if debug { s.Debug = logWithStdFmt }
|
||||
if debug {
|
||||
s.Debug = logWithStdFmt
|
||||
}
|
||||
|
||||
if addr == "" {
|
||||
fatalf("Please specify address to bind to")
|
||||
@ -76,7 +78,7 @@ var ipv6ApiCmd = &cobra.Command{
|
||||
fatalf("Error reading flag: %s", err)
|
||||
}
|
||||
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())
|
||||
},
|
||||
@ -98,4 +100,3 @@ func init() {
|
||||
rootCmd.AddCommand(ipv6ApiCmd)
|
||||
serverv6APIConfigFlags(ipv6ApiCmd)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package pixiecore
|
||||
|
||||
import (
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"fmt"
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
)
|
||||
|
||||
func (s *ServerV6) serveDHCP(conn *dhcp6.Conn) error {
|
||||
|
@ -1,25 +1,25 @@
|
||||
package pixiecore
|
||||
|
||||
import (
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"fmt"
|
||||
"time"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ServerV6 struct {
|
||||
Address string
|
||||
Port string
|
||||
Duid []byte
|
||||
Address string
|
||||
Port string
|
||||
Duid []byte
|
||||
|
||||
BootConfig dhcp6.BootConfiguration
|
||||
PacketBuilder *dhcp6.PacketBuilder
|
||||
AddressPool dhcp6.AddressPool
|
||||
BootConfig dhcp6.BootConfiguration
|
||||
PacketBuilder *dhcp6.PacketBuilder
|
||||
AddressPool dhcp6.AddressPool
|
||||
|
||||
errs chan error
|
||||
|
||||
Log func(subsystem, msg string)
|
||||
Log 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) {
|
||||
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[2:], []byte{0, 1}) //hw type ethernet, x0001
|
||||
@ -94,4 +94,4 @@ func (s *ServerV6) SetDUID(addr net.HardwareAddr) {
|
||||
copy(duid[8:], addr)
|
||||
|
||||
s.Duid = duid
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user