fixing coding-style related issues

This commit is contained in:
Dmitri Dolguikh 2017-11-01 11:31:59 -07:00 committed by Dave Anderson
parent 11a8e61c10
commit 8725ede99b
13 changed files with 525 additions and 524 deletions

View File

@ -6,13 +6,13 @@ import (
) )
type IdentityAssociation struct { type IdentityAssociation struct {
IpAddress net.IP IPAddress net.IP
ClientId []byte ClientID []byte
InterfaceId []byte InterfaceID []byte
CreatedAt time.Time CreatedAt time.Time
} }
type AddressPool interface { type AddressPool interface {
ReserveAddresses(clientId []byte, interfaceIds [][]byte) ([]*IdentityAssociation, error) ReserveAddresses(clientID []byte, interfaceIds [][]byte) ([]*IdentityAssociation, error)
ReleaseAddresses(clientId []byte, interfaceIds [][]byte) ReleaseAddresses(clientID []byte, interfaceIds [][]byte)
} }

View File

@ -11,75 +11,75 @@ import (
) )
type BootConfiguration interface { type BootConfiguration interface {
GetBootUrl(id []byte, clientArchType uint16) ([]byte, error) GetBootURL(id []byte, clientArchType uint16) ([]byte, error)
GetPreference() []byte GetPreference() []byte
GetRecursiveDns() []net.IP GetRecursiveDNS() []net.IP
} }
type StaticBootConfiguration struct { type StaticBootConfiguration struct {
HttpBootUrl []byte HTTPBootURL []byte
IPxeBootUrl []byte IPxeBootURL []byte
RecursiveDns []net.IP RecursiveDNS []net.IP
Preference []byte Preference []byte
UsePreference bool UsePreference bool
} }
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)
ret.Preference[0] = byte(preference) ret.Preference[0] = byte(preference)
} }
ret.RecursiveDns = dnsServerAddresses ret.RecursiveDNS = dnsServerAddresses
return ret return ret
} }
func (bc *StaticBootConfiguration) GetBootUrl(id []byte, clientArchType uint16) ([]byte, error) { func (bc *StaticBootConfiguration) GetBootURL(id []byte, clientArchType uint16) ([]byte, error) {
if 0x10 == clientArchType { if 0x10 == clientArchType {
return bc.HttpBootUrl, nil return bc.HTTPBootURL, nil
} }
return bc.IPxeBootUrl, nil return bc.IPxeBootURL, nil
} }
func (bc *StaticBootConfiguration) GetPreference() []byte { func (bc *StaticBootConfiguration) GetPreference() []byte {
return bc.Preference return bc.Preference
} }
func (bc *StaticBootConfiguration) GetRecursiveDns() []net.IP { func (bc *StaticBootConfiguration) GetRecursiveDNS() []net.IP {
return bc.RecursiveDns return bc.RecursiveDNS
} }
type ApiBootConfiguration struct { type APIBootConfiguration struct {
client *http.Client Client *http.Client
urlPrefix string URLPrefix string
RecursiveDns []net.IP RecursiveDNS []net.IP
Preference []byte Preference []byte
UsePreference bool UsePreference bool
} }
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 += "/"
} }
ret := &ApiBootConfiguration{ ret := &APIBootConfiguration{
client: &http.Client{Timeout: timeout}, Client: &http.Client{Timeout: timeout},
urlPrefix: url + "v1", URLPrefix: url + "v1",
UsePreference: usePreference, UsePreference: usePreference,
} }
if usePreference { if usePreference {
ret.Preference = make([]byte, 1) ret.Preference = make([]byte, 1)
ret.Preference[0] = byte(preference) ret.Preference[0] = byte(preference)
} }
ret.RecursiveDns = dnsServerAddresses ret.RecursiveDNS = dnsServerAddresses
return ret return ret
} }
func (bc *ApiBootConfiguration) GetBootUrl(id []byte, clientArchType uint16) ([]byte, error) { func (bc *APIBootConfiguration) GetBootURL(id []byte, clientArchType uint16) ([]byte, error) {
reqURL := fmt.Sprintf("%s/boot/%x/%d", bc.urlPrefix, id, clientArchType) reqURL := fmt.Sprintf("%s/boot/%x/%d", bc.URLPrefix, id, clientArchType)
resp, err := bc.client.Get(reqURL) resp, err := bc.Client.Get(reqURL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -96,13 +96,13 @@ func (bc *ApiBootConfiguration) GetBootUrl(id []byte, clientArchType uint16) ([]
return []byte(url), nil return []byte(url), nil
} }
func (bc *ApiBootConfiguration) makeURLAbsolute(urlStr string) (string, error) { func (bc *APIBootConfiguration) makeURLAbsolute(urlStr string) (string, error) {
u, err := url.Parse(urlStr) u, err := url.Parse(urlStr)
if err != nil { if err != nil {
return "", fmt.Errorf("%q is not an URL", urlStr) return "", fmt.Errorf("%q is not an URL", urlStr)
} }
if !u.IsAbs() { if !u.IsAbs() {
base, err := url.Parse(bc.urlPrefix) base, err := url.Parse(bc.URLPrefix)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -111,10 +111,10 @@ func (bc *ApiBootConfiguration) makeURLAbsolute(urlStr string) (string, error) {
return u.String(), nil return u.String(), nil
} }
func (bc *ApiBootConfiguration) GetPreference() []byte { func (bc *APIBootConfiguration) GetPreference() []byte {
return bc.Preference return bc.Preference
} }
func (bc *ApiBootConfiguration) GetRecursiveDns() []net.IP { func (bc *APIBootConfiguration) GetRecursiveDNS() []net.IP {
return bc.RecursiveDns return bc.RecursiveDNS
} }

View File

@ -8,55 +8,55 @@ import (
) )
const ( const (
OptClientId uint16 = 1 // IPMask OptClientID uint16 = 1 // IPMask
OptServerId = 2 // int32 OptServerID = 2 // int32
OptIaNa = 3 // IPs OptIaNa = 3 // IPs
OptIaTa = 4 // IPs OptIaTa = 4 // IPs
OptIaAddr = 5 // string OptIaAddr = 5 // string
OptOro = 6 // uint16 OptOro = 6 // uint16
OptPreference = 7 // string OptPreference = 7 // string
OptElapsedTime = 8 // IP OptElapsedTime = 8 // IP
OptRelayMessage = 9 // IP OptRelayMessage = 9 // IP
OptAuth = 11 // []byte OptAuth = 11 // []byte
OptUnicast = 12 // IP OptUnicast = 12 // IP
OptStatusCode = 13 // uint32 OptStatusCode = 13 // uint32
OptRapidCommit = 14 // byte OptRapidCommit = 14 // byte
OptUserClass = 15 // IP OptUserClass = 15 // IP
OptVendorClass = 16 // []byte OptVendorClass = 16 // []byte
OptVendorOpts = 17 // string OptVendorOpts = 17 // string
OptInterfaceId = 18 // uint16 OptInterfaceID = 18 // uint16
OptReconfMsg = 19 // uint32 OptReconfMsg = 19 // uint32
OptReconfAccept = 20 // uint32 OptReconfAccept = 20 // uint32
OptRecursiveDns = 23 // []byte OptRecursiveDNS = 23 // []byte
OptBootfileUrl = 59 OptBootfileURL = 59
OptBootfileParam = 60 //[][]byte OptBootfileParam = 60 //[][]byte
OptClientArchType = 61 //[][]byte, sent by the client OptClientArchType = 61 //[][]byte, sent by the Client
// 24? Domain search list // 24? Domain search list
) )
type Option struct { type Option struct {
Id uint16 ID uint16
Length uint16 Length uint16
Value []byte Value []byte
} }
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}
} }
type Options map[uint16][]*Option type Options map[uint16][]*Option
func MakeOptions(bs []byte) (Options, error) { func MakeOptions(bs []byte) (Options, error) {
to_ret := make(Options) ret := make(Options)
for len(bs) > 0 { for len(bs) > 0 {
o, err := UnmarshalOption(bs) o, err := UnmarshalOption(bs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
to_ret[o.Id] = append(to_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 to_ret, nil return ret, nil
} }
func UnmarshalOption(bs []byte) (*Option, error) { func UnmarshalOption(bs []byte) (*Option, error) {
@ -76,18 +76,18 @@ 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
} }
func (o Options) HumanReadable() []string { func (o Options) HumanReadable() []string {
to_ret := make([]string, 0, len(o)) to_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:
to_ret = append(to_ret, o.HumanReadableIaNa(*option)...) to_ret = append(to_ret, o.HumanReadableIaNa(*option)...)
default: default:
to_ret = append(to_ret, fmt.Sprintf("Option: %d | %d | %d | %s\n", option.Id, option.Length, option.Value, option.Value)) to_ret = append(to_ret, fmt.Sprintf("Option: %d | %d | %d | %s\n", option.ID, option.Length, option.Value, option.Value))
} }
} }
} }
@ -127,10 +127,10 @@ func (o Options) HumanReadableIaNa(opt Option) []string {
} }
func (o Options) AddOption(option *Option) { func (o Options) AddOption(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)
} }
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaOption *Option) *Option { func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaOption *Option) *Option {
@ -163,7 +163,7 @@ func MakeDNSServersOption(addresses []net.IP) *Option {
for i, dnsAddress := range addresses { for i, dnsAddress := range addresses {
copy(value[i*16:], dnsAddress) copy(value[i*16:], dnsAddress)
} }
return MakeOption(OptRecursiveDns, value) return MakeOption(OptRecursiveDNS, value)
} }
func (o Options) Marshal() ([]byte, error) { func (o Options) Marshal() ([]byte, error) {
@ -185,7 +185,7 @@ func (o Options) Marshal() ([]byte, error) {
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 {
return nil, fmt.Errorf("Error serializing option id: %s", err) return nil, fmt.Errorf("Error serializing option id: %s", err)
} }
@ -201,32 +201,32 @@ func (o *Option) Marshal() ([]byte, error) {
} }
func (o Options) UnmarshalOptionRequestOption() map[uint16]bool { func (o Options) UnmarshalOptionRequestOption() map[uint16]bool {
to_ret := make(map[uint16]bool) ret := make(map[uint16]bool)
_, present := o[OptOro]; if !present { _, present := o[OptOro]; if !present {
return to_ret return ret
} }
oro_content := o[OptOro][0].Value value := o[OptOro][0].Value
for i := 0; i < int(o[OptOro][0].Length)/2; i++ { for i := 0; i < int(o[OptOro][0].Length)/2; i++ {
to_ret[uint16(binary.BigEndian.Uint16(oro_content[i*2:(i+1)*2]))] = true ret[uint16(binary.BigEndian.Uint16(value[i*2:(i+1)*2]))] = true
} }
return to_ret return ret
} }
func (o Options) HasBootFileUrlOption() bool { func (o Options) HasBootFileURLOption() bool {
requested_options := o.UnmarshalOptionRequestOption() requestedOptions := o.UnmarshalOptionRequestOption()
_, present := requested_options[OptBootfileUrl] _, present := requestedOptions[OptBootfileURL]
return present return present
} }
func (o Options) HasClientId() bool { func (o Options) HasClientID() bool {
_, present := o[OptClientId] _, present := o[OptClientID]
return present return present
} }
func (o Options) HasServerId() bool { func (o Options) HasServerID() bool {
_, present := o[OptServerId] _, present := o[OptServerID]
return present return present
} }
@ -245,23 +245,23 @@ func (o Options) HasClientArchType() bool {
return present return present
} }
func (o Options) ClientId() []byte { func (o Options) ClientID() []byte {
opt, exists := o[OptClientId] opt, exists := o[OptClientID]
if exists { if exists {
return opt[0].Value return opt[0].Value
} }
return nil return nil
} }
func (o Options) ServerId() []byte { func (o Options) ServerID() []byte {
opt, exists := o[OptServerId] opt, exists := o[OptServerID]
if exists { if exists {
return opt[0].Value return opt[0].Value
} }
return nil return nil
} }
func (o Options) IaNaIds() [][]byte { 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 {
@ -281,8 +281,8 @@ func (o Options) ClientArchType() uint16 {
return 0 return 0
} }
func (o Options) BootfileUrl() []byte { func (o Options) BootFileURL() []byte {
opt, exists := o[OptBootfileUrl] opt, exists := o[OptBootfileURL]
if exists { if exists {
return opt[0].Value return opt[0].Value
} }

View File

@ -7,39 +7,39 @@ import (
) )
func TestMarshalOption(t *testing.T) { func TestMarshalOption(t *testing.T) {
expectedUrl := []byte("http://blah") expectedURL := []byte("http://blah")
expectedLength := uint16(len(expectedUrl)) expectedLength := uint16(len(expectedURL))
opt := &Option{Id: OptBootfileUrl, Length: expectedLength, Value: expectedUrl} opt := &Option{ID: OptBootfileURL, Length: expectedLength, Value: expectedURL}
marshalled, err := opt.Marshal() marshalled, err := opt.Marshal()
if err != nil { if err != nil {
t.Fatalf("Unexpected marshalling failure.") t.Fatalf("Unexpected marshalling failure.")
} }
if id := uint16(binary.BigEndian.Uint16(marshalled[0:2])); id != OptBootfileUrl { if id := uint16(binary.BigEndian.Uint16(marshalled[0:2])); id != OptBootfileURL {
t.Fatalf("Expected optionId %d, got: %d", OptBootfileUrl, id) t.Fatalf("Expected optionId %d, got: %d", OptBootfileURL, id)
} }
if l := uint16(binary.BigEndian.Uint16(marshalled[2:4])); l != expectedLength { if l := uint16(binary.BigEndian.Uint16(marshalled[2:4])); l != expectedLength {
t.Fatalf("Expected length of %d, got: %d", expectedLength, l) t.Fatalf("Expected length of %d, got: %d", expectedLength, l)
} }
if url := marshalled[4:]; string(url) != string(expectedUrl) { if url := marshalled[4:]; string(url) != string(expectedURL) {
t.Fatalf("Expected %s, got %s", expectedUrl, url) t.Fatalf("Expected %s, got %s", expectedURL, url)
} }
} }
func TestMakeIaAddrOption(t *testing.T) { func TestMakeIaAddrOption(t *testing.T) {
expectedIp := net.ParseIP("2001:db8:f00f:cafe::99") expectedIP := net.ParseIP("2001:db8:f00f:cafe::99")
var expectedPreferredLifetime, expectedValidLifetime uint32 = 27000, 43200 var expectedPreferredLifetime, expectedValidLifetime uint32 = 27000, 43200
iaAddrOption := MakeIaAddrOption(expectedIp, expectedPreferredLifetime, expectedValidLifetime) iaAddrOption := MakeIaAddrOption(expectedIP, expectedPreferredLifetime, expectedValidLifetime)
if iaAddrOption.Id != OptIaAddr { if iaAddrOption.ID != OptIaAddr {
t.Fatalf("Expected option id %d, got %d", OptIaAddr, iaAddrOption.Id) t.Fatalf("Expected option id %d, got %d", OptIaAddr, iaAddrOption.ID)
} }
if iaAddrOption.Length != 24 { if iaAddrOption.Length != 24 {
t.Fatalf("Expected length 24 bytes, got %d", iaAddrOption.Length) t.Fatalf("Expected length 24 bytes, got %d", iaAddrOption.Length)
} }
if string(iaAddrOption.Value[0:16]) != string(expectedIp) { if string(iaAddrOption.Value[0:16]) != string(expectedIP) {
t.Fatalf("Expected address %v, got %v", expectedIp, iaAddrOption.Value[0:16]) t.Fatalf("Expected address %v, got %v", expectedIP, iaAddrOption.Value[0:16])
} }
if preferredLifetime := uint32(binary.BigEndian.Uint32(iaAddrOption.Value[16:20])); preferredLifetime != expectedPreferredLifetime { if preferredLifetime := uint32(binary.BigEndian.Uint32(iaAddrOption.Value[16:20])); preferredLifetime != expectedPreferredLifetime {
t.Fatalf("Expected preferred lifetime of %d, got %d", expectedPreferredLifetime, preferredLifetime) t.Fatalf("Expected preferred lifetime of %d, got %d", expectedPreferredLifetime, preferredLifetime)
@ -55,16 +55,16 @@ func TestMakeIaNaOption(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Unexpected serialization error: %s", err) t.Fatalf("Unexpected serialization error: %s", err)
} }
expectedId := []byte("1234") expectedID := []byte("1234")
var expectedT1, expectedT2 uint32 = 100, 200 var expectedT1, expectedT2 uint32 = 100, 200
iaNaOption := MakeIaNaOption(expectedId, expectedT1, expectedT2, iaAddrOption) iaNaOption := MakeIaNaOption(expectedID, expectedT1, expectedT2, iaAddrOption)
if iaNaOption.Id != OptIaNa { if iaNaOption.ID != OptIaNa {
t.Fatalf("Expected optionId %d, got %d", OptIaNa, iaNaOption.Id) t.Fatalf("Expected optionId %d, got %d", OptIaNa, iaNaOption.ID)
} }
if string(iaNaOption.Value[0:4]) != string(expectedId) { if string(iaNaOption.Value[0:4]) != string(expectedID) {
t.Fatalf("Expected id %s, got %s", expectedId, string(iaNaOption.Value[0:4])) t.Fatalf("Expected id %s, got %s", expectedID, string(iaNaOption.Value[0:4]))
} }
if t1 := uint32(binary.BigEndian.Uint32(iaNaOption.Value[4:])); t1 != expectedT1 { if t1 := uint32(binary.BigEndian.Uint32(iaNaOption.Value[4:])); t1 != expectedT1 {
t.Fatalf("Expected t1 of %d, got %d", expectedT1, t1) t.Fatalf("Expected t1 of %d, got %d", expectedT1, t1)
@ -82,8 +82,8 @@ func TestMakeStatusOption(t *testing.T) {
expectedStatusCode := uint16(2) expectedStatusCode := uint16(2)
noAddrOption := MakeStatusOption(expectedStatusCode, expectedMessage) noAddrOption := MakeStatusOption(expectedStatusCode, expectedMessage)
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)
@ -108,8 +108,8 @@ func TestMakeDNSServersOption(t *testing.T) {
expectedAddress2 := net.ParseIP("2001:db8:f00f:cafe::9A") expectedAddress2 := net.ParseIP("2001:db8:f00f:cafe::9A")
dnsServersOption := MakeDNSServersOption([]net.IP{expectedAddress1, expectedAddress2}) dnsServersOption := MakeDNSServersOption([]net.IP{expectedAddress1, expectedAddress2})
if dnsServersOption.Id != OptRecursiveDns { if dnsServersOption.ID != OptRecursiveDNS {
t.Fatalf("Expected option id %d, got %d", OptRecursiveDns, dnsServersOption.Id) t.Fatalf("Expected option id %d, got %d", OptRecursiveDNS, dnsServersOption.ID)
} }
if dnsServersOption.Length != 32 { if dnsServersOption.Length != 32 {
t.Fatalf("Expected length 32 bytes, got %d", dnsServersOption.Length) t.Fatalf("Expected length 32 bytes, got %d", dnsServersOption.Length)

View File

@ -40,15 +40,15 @@ func MakePacket(bs []byte, packetLength int) (*Packet, error) {
} }
func (p *Packet) Marshal() ([]byte, error) { func (p *Packet) Marshal() ([]byte, error) {
marshalled_options, err := p.Options.Marshal() marshalledOptions, err := p.Options.Marshal()
if err != nil { if err != nil {
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(marshalled_options) + 4, len(marshalled_options) + 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:], marshalled_options) copy(ret[4:], marshalledOptions)
return ret, nil return ret, nil
} }
@ -70,13 +70,13 @@ func (p *Packet) ShouldDiscard(serverDuid []byte) error {
func ShouldDiscardSolicit(p *Packet) error { func ShouldDiscardSolicit(p *Packet) error {
options := p.Options options := p.Options
if !options.HasBootFileUrlOption() { if !options.HasBootFileURLOption() {
return fmt.Errorf("'Solicit' packet doesn't have file url option") return fmt.Errorf("'Solicit' packet doesn't have file url option")
} }
if !options.HasClientId() { if !options.HasClientID() {
return fmt.Errorf("'Solicit' packet has no client id option") return fmt.Errorf("'Solicit' packet has no Client id option")
} }
if options.HasServerId() { if options.HasServerID() {
return fmt.Errorf("'Solicit' packet has server id option") return fmt.Errorf("'Solicit' packet has server id option")
} }
return nil return nil
@ -84,31 +84,31 @@ func ShouldDiscardSolicit(p *Packet) error {
func ShouldDiscardRequest(p *Packet, serverDuid []byte) error { func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
options := p.Options options := p.Options
if !options.HasBootFileUrlOption() { if !options.HasBootFileURLOption() {
return fmt.Errorf("'Request' packet doesn't have file url option") return fmt.Errorf("'Request' packet doesn't have file url option")
} }
if !options.HasClientId() { if !options.HasClientID() {
return fmt.Errorf("'Request' packet has no client id option") return fmt.Errorf("'Request' packet has no Client id option")
} }
if !options.HasServerId() { if !options.HasServerID() {
return fmt.Errorf("'Request' packet has no server id option") return fmt.Errorf("'Request' packet has no server id option")
} }
if bytes.Compare(options.ServerId(), serverDuid) != 0 { if bytes.Compare(options.ServerID(), serverDuid) != 0 {
return fmt.Errorf("'Request' packet's server id option (%d) is different from ours (%d)", options.ServerId(), serverDuid) return fmt.Errorf("'Request' packet's server id option (%d) is different from ours (%d)", options.ServerID(), serverDuid)
} }
return nil return nil
} }
func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error { func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error {
options := p.Options options := p.Options
if !options.HasBootFileUrlOption() { if !options.HasBootFileURLOption() {
return fmt.Errorf("'Information-request' packet doesn't have boot file url option") return fmt.Errorf("'Information-request' packet doesn't have boot file url option")
} }
if options.HasIaNa() || options.HasIaTa() { if options.HasIaNa() || options.HasIaTa() {
return fmt.Errorf("'Information-request' packet has an IA option present") return fmt.Errorf("'Information-request' packet has an IA option present")
} }
if options.HasServerId() && (bytes.Compare(options.ServerId(), serverDuid) != 0) { if options.HasServerID() && (bytes.Compare(options.ServerID(), serverDuid) != 0) {
return fmt.Errorf("'Information-request' packet's server id option (%d) is different from ours (%d)", options.ServerId(), serverDuid) return fmt.Errorf("'Information-request' packet's server id option (%d) is different from ours (%d)", options.ServerID(), serverDuid)
} }
return nil return nil
} }

View File

@ -15,116 +15,117 @@ func MakePacketBuilder(preferredLifetime, validLifetime uint32) *PacketBuilder {
return &PacketBuilder{PreferredLifetime: preferredLifetime, ValidLifetime: validLifetime} return &PacketBuilder{PreferredLifetime: preferredLifetime, ValidLifetime: validLifetime}
} }
func (b *PacketBuilder) BuildResponse(in *Packet, serverDuid []byte, configuration BootConfiguration, addresses AddressPool) (*Packet, error) { func (b *PacketBuilder) BuildResponse(in *Packet, serverDUID []byte, configuration BootConfiguration, addresses AddressPool) (*Packet, error) {
switch in.Type { switch in.Type {
case MsgSolicit: case MsgSolicit:
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 {
return nil, err return nil, err
} }
associations, err := addresses.ReserveAddresses(in.Options.ClientId(), in.Options.IaNaIds()) associations, err := addresses.ReserveAddresses(in.Options.ClientID(), in.Options.IaNaIDs())
if err != nil { if err != nil {
return b.MakeMsgAdvertiseWithNoAddrsAvailable(in.TransactionID, serverDuid, in.Options.ClientId(), err), err return b.MakeMsgAdvertiseWithNoAddrsAvailable(in.TransactionID, serverDUID, in.Options.ClientID(), err), err
} }
return b.MakeMsgAdvertise(in.TransactionID, serverDuid, in.Options.ClientId(), return b.MakeMsgAdvertise(in.TransactionID, serverDUID, in.Options.ClientID(),
in.Options.ClientArchType(), associations, bootFileUrl, configuration.GetPreference(), configuration.GetRecursiveDns()), nil in.Options.ClientArchType(), associations, bootFileURL, configuration.GetPreference(), configuration.GetRecursiveDNS()), nil
case MsgRequest: case MsgRequest:
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 {
return nil, err return nil, err
} }
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 {
return nil, err return nil, err
} }
return b.MakeMsgInformationRequestReply(in.TransactionID, serverDuid, in.Options.ClientId(), return b.MakeMsgInformationRequestReply(in.TransactionID, serverDUID, in.Options.ClientID(),
in.Options.ClientArchType(), bootFileUrl, configuration.GetRecursiveDns()), nil in.Options.ClientArchType(), bootFileURL, configuration.GetRecursiveDNS()), nil
case MsgRelease: case MsgRelease:
addresses.ReleaseAddresses(in.Options.ClientId(), in.Options.IaNaIds()) addresses.ReleaseAddresses(in.Options.ClientID(), in.Options.IaNaIDs())
return b.MakeMsgReleaseReply(in.TransactionID, serverDuid, in.Options.ClientId()), nil return b.MakeMsgReleaseReply(in.TransactionID, serverDUID, in.Options.ClientID()), nil
default: default:
return nil, nil return nil, nil
} }
} }
func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, serverDuid, clientId []byte, clientArchType uint16, func (b *PacketBuilder) MakeMsgAdvertise(transactionID [3]byte, serverDUID, clientID []byte, clientArchType uint16,
associations []*IdentityAssociation, bootFileUrl, preference []byte, dnsServers []net.IP) *Packet { associations []*IdentityAssociation, bootFileURL, preference []byte, dnsServers []net.IP) *Packet {
ret_options := make(Options) retOptions := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) retOptions.AddOption(MakeOption(OptClientID, clientID))
for _, association := range(associations) { for _, association := range(associations) {
ret_options.AddOption(MakeIaNaOption(association.InterfaceId, b.calculateT1(), b.calculateT2(), retOptions.AddOption(MakeIaNaOption(association.InterfaceID, b.calculateT1(), b.calculateT2(),
MakeIaAddrOption(association.IpAddress, b.PreferredLifetime, b.ValidLifetime))) MakeIaAddrOption(association.IPAddress, b.PreferredLifetime, b.ValidLifetime)))
} }
ret_options.AddOption(MakeOption(OptServerId, serverDuid)) retOptions.AddOption(MakeOption(OptServerID, serverDUID))
if 0x10 == clientArchType { // HTTPClient if 0x10 == clientArchType { // HTTPClient
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient retOptions.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
} }
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl)) retOptions.AddOption(MakeOption(OptBootfileURL, bootFileURL))
if preference != nil {ret_options.AddOption(MakeOption(OptPreference, preference))} if preference != nil {
if len(dnsServers) > 0 { ret_options.AddOption(MakeDNSServersOption(dnsServers)) } retOptions.AddOption(MakeOption(OptPreference, preference))}
if len(dnsServers) > 0 { retOptions.AddOption(MakeDNSServersOption(dnsServers)) }
return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgAdvertise, TransactionID: transactionID, Options: retOptions}
} }
func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, serverDuid, clientId []byte, clientArchType uint16, func (b *PacketBuilder) MakeMsgReply(transactionID [3]byte, serverDUID, clientID []byte, clientArchType uint16,
associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileUrl []byte, dnsServers []net.IP, err error) *Packet { associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileURL []byte, dnsServers []net.IP, err error) *Packet {
ret_options := make(Options) retOptions := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) retOptions.AddOption(MakeOption(OptClientID, clientID))
for _, association := range(associations) { for _, association := range(associations) {
ret_options.AddOption(MakeIaNaOption(association.InterfaceId, b.calculateT1(), b.calculateT2(), retOptions.AddOption(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) {
ret_options.AddOption(MakeIaNaOption(ia, b.calculateT1(), b.calculateT2(), retOptions.AddOption(MakeIaNaOption(ia, b.calculateT1(), b.calculateT2(),
MakeStatusOption(2, err.Error()))) MakeStatusOption(2, err.Error())))
} }
ret_options.AddOption(MakeOption(OptServerId, serverDuid)) retOptions.AddOption(MakeOption(OptServerID, serverDUID))
if 0x10 == clientArchType { // HTTPClient if 0x10 == clientArchType { // HTTPClient
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient retOptions.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
} }
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl)) retOptions.AddOption(MakeOption(OptBootfileURL, bootFileURL))
if len(dnsServers) > 0 { ret_options.AddOption(MakeDNSServersOption(dnsServers)) } if len(dnsServers) > 0 { retOptions.AddOption(MakeDNSServersOption(dnsServers)) }
return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgReply, TransactionID: transactionID, Options: retOptions}
} }
func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, serverDuid, clientId []byte, clientArchType uint16, func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionID [3]byte, serverDUID, clientID []byte, clientArchType uint16,
bootFileUrl []byte, dnsServers []net.IP) *Packet { bootFileURL []byte, dnsServers []net.IP) *Packet {
ret_options := make(Options) retOptions := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) retOptions.AddOption(MakeOption(OptClientID, clientID))
ret_options.AddOption(MakeOption(OptServerId, serverDuid)) retOptions.AddOption(MakeOption(OptServerID, serverDUID))
if 0x10 == clientArchType { // HTTPClient if 0x10 == clientArchType { // HTTPClient
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient retOptions.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
} }
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl)) retOptions.AddOption(MakeOption(OptBootfileURL, bootFileURL))
if len(dnsServers) > 0 { ret_options.AddOption(MakeDNSServersOption(dnsServers)) } if len(dnsServers) > 0 { retOptions.AddOption(MakeDNSServersOption(dnsServers)) }
return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgReply, TransactionID: transactionID, Options: retOptions}
} }
func (b *PacketBuilder) MakeMsgReleaseReply(transactionId [3]byte, serverDuid, clientId []byte) *Packet { func (b *PacketBuilder) MakeMsgReleaseReply(transactionID [3]byte, serverDUID, clientID []byte) *Packet {
ret_options := make(Options) retOptions := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) retOptions.AddOption(MakeOption(OptClientID, clientID))
ret_options.AddOption(MakeOption(OptServerId, serverDuid)) retOptions.AddOption(MakeOption(OptServerID, serverDUID))
v := make([]byte, 19, 19) v := make([]byte, 19, 19)
copy(v[2:], []byte("Release received.")) copy(v[2:], []byte("Release received."))
ret_options.AddOption(MakeOption(OptStatusCode, v)) retOptions.AddOption(MakeOption(OptStatusCode, v))
return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgReply, TransactionID: transactionID, Options: retOptions}
} }
func (b *PacketBuilder) MakeMsgAdvertiseWithNoAddrsAvailable(transactionId [3]byte, serverDuid, clientId []byte, err error) *Packet { func (b *PacketBuilder) MakeMsgAdvertiseWithNoAddrsAvailable(transactionID [3]byte, serverDUID, clientID []byte, err error) *Packet {
ret_options := make(Options) retOptions := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) retOptions.AddOption(MakeOption(OptClientID, clientID))
ret_options.AddOption(MakeOption(OptServerId, serverDuid)) retOptions.AddOption(MakeOption(OptServerID, serverDUID))
ret_options.AddOption(MakeStatusOption(2, err.Error())) // NoAddrAvailable retOptions.AddOption(MakeStatusOption(2, err.Error())) // NoAddrAvailable
return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgAdvertise, TransactionID: transactionID, Options: retOptions}
} }
func (b *PacketBuilder) calculateT1() uint32 { func (b *PacketBuilder) calculateT1() uint32 {
@ -135,36 +136,36 @@ 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 {
idType := binary.BigEndian.Uint16(optClientId[0:2]) idType := binary.BigEndian.Uint16(optClientID[0:2])
switch idType { switch idType {
case 1: case 1:
return optClientId[8:] return optClientID[8:]
case 3: case 3:
return optClientId[4:] return optClientID[4:]
default: default:
return optClientId[2:] return optClientID[2:]
} }
} }
func iasWithoutAddesses(availableAssociations []*IdentityAssociation, allIas [][]byte) [][]byte { func iasWithoutAddesses(availableAssociations []*IdentityAssociation, allIAs [][]byte) [][]byte {
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)
} }
} }
return ret return ret
} }
func calculateIaIdHash(interfaceId []byte) uint64 { func calculateIAIDHash(interfaceID []byte) uint64 {
h := fnv.New64a() h := fnv.New64a()
h.Write(interfaceId) h.Write(interfaceID)
return h.Sum64() return h.Sum64()
} }

View File

@ -8,52 +8,52 @@ import (
) )
func TestMakeMsgAdvertise(t *testing.T) { func TestMakeMsgAdvertise(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
expectedInterfaceId := []byte("id-1") expectedInterfaceID := []byte("id-1")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99") expectedDnsServerIP := net.ParseIP("2001:db8:f00f:cafe::99")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: expectedInterfaceId} identityAssociation := &IdentityAssociation{IPAddress: expectedIP, InterfaceID: expectedInterfaceID}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgAdvertise(transactionId, expectedServerId, expectedClientId, 0x11, msg := builder.MakeMsgAdvertise(transactionID, expectedServerID, expectedClientID, 0x11,
[]*IdentityAssociation{identityAssociation}, expectedBootFileUrl, nil, []net.IP{expectedDnsServerIp}) []*IdentityAssociation{identityAssociation}, expectedBootFileURL, nil, []net.IP{expectedDnsServerIP})
if msg.Type != MsgAdvertise { if msg.Type != MsgAdvertise {
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
} }
if transactionId != msg.TransactionID { if transactionID != msg.TransactionID {
t.Fatalf("Expected transaction Id %v, got %v", transactionId, msg.TransactionID) t.Fatalf("Expected transaction ID %v, got %v", transactionID, msg.TransactionID)
} }
clientIdOption := msg.Options.ClientId() clientIDOption := msg.Options.ClientID()
if clientIdOption == nil { if clientIDOption == nil {
t.Fatalf("Client Id option should be present") t.Fatalf("Client ID option should be present")
} }
if string(expectedClientId) != string(clientIdOption) { if string(expectedClientID) != string(clientIDOption) {
t.Fatalf("Expected client id %v, got %v", expectedClientId, clientIdOption) t.Fatalf("Expected Client id %v, got %v", expectedClientID, clientIDOption)
} }
serverIdOption := msg.Options.ServerId() serverIDOption := msg.Options.ServerID()
if serverIdOption == nil { if serverIDOption == nil {
t.Fatalf("Server Id option should be present") t.Fatalf("Server ID option should be present")
} }
if string(expectedServerId) != string(serverIdOption) { if string(expectedServerID) != string(serverIDOption) {
t.Fatalf("Expected server id %v, got %v", expectedClientId, serverIdOption) t.Fatalf("Expected server id %v, got %v", expectedClientID, serverIDOption)
} }
bootfileUrlOption := msg.Options[OptBootfileUrl][0] bootfileURLOption := msg.Options[OptBootfileURL][0]
if bootfileUrlOption == nil { if bootfileURLOption == nil {
t.Fatalf("Bootfile URL option should be present") t.Fatalf("Bootfile URL option should be present")
} }
if string(expectedBootFileUrl) != string(bootfileUrlOption.Value) { if string(expectedBootFileURL) != string(bootfileURLOption.Value) {
t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileUrl, bootfileUrlOption) t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileURL, bootfileURLOption)
} }
iaNaOption := msg.Options.IaNaIds() iaNaOption := msg.Options.IaNaIDs()
if len(iaNaOption) == 0 { if len(iaNaOption) == 0 {
t.Fatalf("interface non-temporary association option should be present") t.Fatalf("interface non-temporary association option should be present")
} }
@ -63,36 +63,36 @@ func TestMakeMsgAdvertise(t *testing.T) {
t.Fatalf("Preference option shouldn't be set") t.Fatalf("Preference option shouldn't be set")
} }
dnsServersOption := msg.Options[OptRecursiveDns] dnsServersOption := msg.Options[OptRecursiveDNS]
if dnsServersOption == nil { if dnsServersOption == nil {
t.Fatalf("DNS servers option should be set") t.Fatalf("DNS servers option should be set")
} }
if string(dnsServersOption[0].Value) != string(expectedDnsServerIp) { if string(dnsServersOption[0].Value) != string(expectedDnsServerIP) {
t.Fatalf("Expected dns server %v, got %v", expectedDnsServerIp, net.IP(dnsServersOption[0].Value)) t.Fatalf("Expected dns server %v, got %v", expectedDnsServerIP, net.IP(dnsServersOption[0].Value))
} }
} }
func TestMakeMsgAdvertiseShouldSkipDnsServersIfNoneConfigured(t *testing.T) { func TestMakeMsgAdvertiseShouldSkipDnsServersIfNoneConfigured(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
expectedInterfaceId := []byte("id-1") expectedInterfaceID := []byte("id-1")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: expectedInterfaceId} identityAssociation := &IdentityAssociation{IPAddress: expectedIP, InterfaceID: expectedInterfaceID}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
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")
} }
} }
func TestShouldSetPreferenceOptionWhenSpecified(t *testing.T) { func TestShouldSetPreferenceOptionWhenSpecified(t *testing.T) {
identityAssociation := &IdentityAssociation{IpAddress: net.ParseIP("2001:db8:f00f:cafe::1"), InterfaceId: []byte("id-1")} identityAssociation := &IdentityAssociation{IPAddress: net.ParseIP("2001:db8:f00f:cafe::1"), InterfaceID: []byte("id-1")}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
@ -110,62 +110,62 @@ func TestShouldSetPreferenceOptionWhenSpecified(t *testing.T) {
} }
func TestMakeMsgAdvertiseWithHttpClientArch(t *testing.T) { func TestMakeMsgAdvertiseWithHttpClientArch(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} identityAssociation := &IdentityAssociation{IPAddress: expectedIP, InterfaceID: []byte("id-1")}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgAdvertise(transactionId, expectedServerId, expectedClientId, 0x10, msg := builder.MakeMsgAdvertise(transactionID, expectedServerID, expectedClientID, 0x10,
[]*IdentityAssociation{identityAssociation}, expectedBootFileUrl, nil, []net.IP{}) []*IdentityAssociation{identityAssociation}, expectedBootFileURL, nil, []net.IP{})
vendorClassOption := msg.Options[OptVendorClass] vendorClassOption := msg.Options[OptVendorClass]
if vendorClassOption == nil { if vendorClassOption == nil {
t.Fatalf("Vendor class option should be present") t.Fatalf("Vendor class option should be present")
} }
bootfileUrlOption := msg.Options.BootfileUrl() bootfileURLOption := msg.Options.BootFileURL()
if bootfileUrlOption == nil { if bootfileURLOption == nil {
t.Fatalf("Bootfile URL option should be present") t.Fatalf("Bootfile URL option should be present")
} }
if string(expectedBootFileUrl) != string(bootfileUrlOption) { if string(expectedBootFileURL) != string(bootfileURLOption) {
t.Fatalf("Expected bootfile URL %s, got %s", expectedBootFileUrl, bootfileUrlOption) t.Fatalf("Expected bootfile URL %s, got %s", expectedBootFileURL, bootfileURLOption)
} }
} }
func TestMakeNoAddrsAvailable(t *testing.T) { func TestMakeNoAddrsAvailable(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedMessage := "Boom!" expectedMessage := "Boom!"
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgAdvertiseWithNoAddrsAvailable(transactionId, expectedServerId, expectedClientId, fmt.Errorf(expectedMessage)) msg := builder.MakeMsgAdvertiseWithNoAddrsAvailable(transactionID, expectedServerID, expectedClientID, fmt.Errorf(expectedMessage))
if msg.Type != MsgAdvertise { if msg.Type != MsgAdvertise {
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
} }
if transactionId != msg.TransactionID { if transactionID != msg.TransactionID {
t.Fatalf("Expected transaction Id %v, got %v", transactionId, msg.TransactionID) t.Fatalf("Expected transaction ID %v, got %v", transactionID, msg.TransactionID)
} }
clientIdOption := msg.Options.ClientId() clientIDOption := msg.Options.ClientID()
if clientIdOption == nil { if clientIDOption == nil {
t.Fatalf("Client Id option should be present") t.Fatalf("Client ID option should be present")
} }
if string(expectedClientId) != string(clientIdOption) { if string(expectedClientID) != string(clientIDOption) {
t.Fatalf("Expected client id %v, got %v", expectedClientId, clientIdOption) t.Fatalf("Expected Client id %v, got %v", expectedClientID, clientIDOption)
} }
serverIdOption := msg.Options.ServerId() serverIDOption := msg.Options.ServerID()
if serverIdOption == nil { if serverIDOption == nil {
t.Fatalf("Server Id option should be present") t.Fatalf("Server ID option should be present")
} }
if string(expectedServerId) != string(serverIdOption) { if string(expectedServerID) != string(serverIDOption) {
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 {
@ -181,54 +181,54 @@ func TestMakeNoAddrsAvailable(t *testing.T) {
} }
func TestMakeMsgReply(t *testing.T) { func TestMakeMsgReply(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99") expectedDnsServerIP := net.ParseIP("2001:db8:f00f:cafe::99")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} identityAssociation := &IdentityAssociation{IPAddress: expectedIP, InterfaceID: []byte("id-1")}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgReply(transactionId, expectedServerId, expectedClientId, 0x11, msg := builder.MakeMsgReply(transactionID, expectedServerID, expectedClientID, 0x11,
[]*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileUrl, []net.IP{expectedDnsServerIp}, nil) []*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileURL, []net.IP{expectedDnsServerIP}, nil)
if msg.Type != MsgReply { if msg.Type != MsgReply {
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
} }
if transactionId != msg.TransactionID { if transactionID != msg.TransactionID {
t.Fatalf("Expected transaction Id %v, got %v", transactionId, msg.TransactionID) t.Fatalf("Expected transaction ID %v, got %v", transactionID, msg.TransactionID)
} }
clientIdOption := msg.Options.ClientId() clientIDOption := msg.Options.ClientID()
if clientIdOption == nil { if clientIDOption == nil {
t.Fatalf("Client Id option should be present") t.Fatalf("Client ID option should be present")
} }
if string(expectedClientId) != string(clientIdOption) { if string(expectedClientID) != string(clientIDOption) {
t.Fatalf("Expected client id %v, got %v", expectedClientId, clientIdOption) t.Fatalf("Expected Client id %v, got %v", expectedClientID, clientIDOption)
} }
if len(expectedClientId) != len(clientIdOption) { if len(expectedClientID) != len(clientIDOption) {
t.Fatalf("Expected client id length of %d, got %d", len(expectedClientId), len(clientIdOption)) t.Fatalf("Expected Client id length of %d, got %d", len(expectedClientID), len(clientIDOption))
} }
serverIdOption := msg.Options.ServerId() serverIDOption := msg.Options.ServerID()
if serverIdOption == nil { if serverIDOption == nil {
t.Fatalf("Server Id option should be present") t.Fatalf("Server ID option should be present")
} }
if string(expectedServerId) != string(serverIdOption) { if string(expectedServerID) != string(serverIDOption) {
t.Fatalf("Expected server id %v, got %v", expectedClientId, serverIdOption) t.Fatalf("Expected server id %v, got %v", expectedClientID, serverIDOption)
} }
if len(expectedServerId) != len(serverIdOption) { if len(expectedServerID) != len(serverIDOption) {
t.Fatalf("Expected server id length of %d, got %d", len(expectedClientId), len(serverIdOption)) t.Fatalf("Expected server id length of %d, got %d", len(expectedClientID), len(serverIDOption))
} }
bootfileUrlOption := msg.Options.BootfileUrl() bootfileURLOption := msg.Options.BootFileURL()
if bootfileUrlOption == nil { if bootfileURLOption == nil {
t.Fatalf("Bootfile URL option should be present") t.Fatalf("Bootfile URL option should be present")
} }
if string(expectedBootFileUrl) != string(bootfileUrlOption) { if string(expectedBootFileURL) != string(bootfileURLOption) {
t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileUrl, bootfileUrlOption) t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileURL, bootfileURLOption)
} }
iaNaOption := msg.Options[OptIaNa] iaNaOption := msg.Options[OptIaNa]
@ -236,73 +236,73 @@ func TestMakeMsgReply(t *testing.T) {
t.Fatalf("interface non-temporary association option should be present") t.Fatalf("interface non-temporary association option should be present")
} }
dnsServersOption := msg.Options[OptRecursiveDns] dnsServersOption := msg.Options[OptRecursiveDNS]
if dnsServersOption == nil { if dnsServersOption == nil {
t.Fatalf("DNS servers option should be set") t.Fatalf("DNS servers option should be set")
} }
if string(dnsServersOption[0].Value) != string(expectedDnsServerIp) { if string(dnsServersOption[0].Value) != string(expectedDnsServerIP) {
t.Fatalf("Expected dns server %v, got %v", expectedDnsServerIp, net.IP(dnsServersOption[0].Value)) t.Fatalf("Expected dns server %v, got %v", expectedDnsServerIP, net.IP(dnsServersOption[0].Value))
} }
} }
func TestMakeMsgReplyShouldSkipDnsServersIfNoneWereConfigured(t *testing.T) { func TestMakeMsgReplyShouldSkipDnsServersIfNoneWereConfigured(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} identityAssociation := &IdentityAssociation{IPAddress: expectedIP, InterfaceID: []byte("id-1")}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
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")
} }
} }
func TestMakeMsgReplyWithHttpClientArch(t *testing.T) { func TestMakeMsgReplyWithHttpClientArch(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} identityAssociation := &IdentityAssociation{IPAddress: expectedIP, InterfaceID: []byte("id-1")}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgReply(transactionId, expectedServerId, expectedClientId, 0x10, msg := builder.MakeMsgReply(transactionID, expectedServerID, expectedClientID, 0x10,
[]*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileUrl, []net.IP{}, nil) []*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileURL, []net.IP{}, nil)
vendorClassOption := msg.Options[OptVendorClass] vendorClassOption := msg.Options[OptVendorClass]
if vendorClassOption == nil { if vendorClassOption == nil {
t.Fatalf("Vendor class option should be present") t.Fatalf("Vendor class option should be present")
} }
bootfileUrlOption := msg.Options.BootfileUrl() bootfileURLOption := msg.Options.BootFileURL()
if bootfileUrlOption == nil { if bootfileURLOption == nil {
t.Fatalf("Bootfile URL option should be present") t.Fatalf("Bootfile URL option should be present")
} }
if string(expectedBootFileUrl) != string(bootfileUrlOption) { if string(expectedBootFileURL) != string(bootfileURLOption) {
t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileUrl, bootfileUrlOption) t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileURL, bootfileURLOption)
} }
} }
func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) { func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} identityAssociation := &IdentityAssociation{IPAddress: expectedIP, InterfaceID: []byte("id-1")}
expectedErrorMessage := "Boom!" expectedErrorMessage := "Boom!"
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgReply(transactionId, expectedServerId, expectedClientId, 0x10, msg := builder.MakeMsgReply(transactionID, expectedServerID, expectedClientID, 0x10,
[]*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileUrl, []net.IP{}, []*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileURL, []net.IP{},
fmt.Errorf(expectedErrorMessage)) fmt.Errorf(expectedErrorMessage))
iaNaOption := msg.Options[OptIaNa] iaNaOption := msg.Options[OptIaNa]
@ -325,16 +325,16 @@ func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed to unmarshal IaNa options: %s", err) t.Fatalf("Failed to unmarshal IaNa options: %s", err)
} }
if possiblyIaAddrOption.Id != OptIaAddr { if possiblyIaAddrOption.ID != OptIaAddr {
t.Fatalf("Expected option 5 (ia address), got %d", possiblyIaAddrOption.Id) t.Fatalf("Expected option 5 (ia address), got %d", possiblyIaAddrOption.ID)
} }
possiblyStatusOption, err := UnmarshalOption(failedIaNaOption[12:]) possiblyStatusOption, err := UnmarshalOption(failedIaNaOption[12:])
if err != nil { if err != nil {
t.Fatalf("Failed to unmarshal IaNa options: %s", err) t.Fatalf("Failed to unmarshal IaNa options: %s", err)
} }
if possiblyStatusOption.Id != OptStatusCode { if possiblyStatusOption.ID != OptStatusCode {
t.Fatalf("Expected option 13 (status code), got %d", possiblyStatusOption.Id) t.Fatalf("Expected option 13 (status code), got %d", possiblyStatusOption.ID)
} }
if binary.BigEndian.Uint16(possiblyStatusOption.Value[0:2]) != uint16(2) { if binary.BigEndian.Uint16(possiblyStatusOption.Value[0:2]) != uint16(2) {
t.Fatalf("Expected status code 2, got %d", binary.BigEndian.Uint16(possiblyStatusOption.Value[0:2])) t.Fatalf("Expected status code 2, got %d", binary.BigEndian.Uint16(possiblyStatusOption.Value[0:2]))
@ -345,147 +345,147 @@ func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) {
} }
func TestMakeMsgInformationRequestReply(t *testing.T) { func TestMakeMsgInformationRequestReply(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99") expectedDnsServerIP := net.ParseIP("2001:db8:f00f:cafe::99")
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedServerId, expectedClientId, 0x11, msg := builder.MakeMsgInformationRequestReply(transactionID, expectedServerID, expectedClientID, 0x11,
expectedBootFileUrl, []net.IP{expectedDnsServerIp}) expectedBootFileURL, []net.IP{expectedDnsServerIP})
if msg.Type != MsgReply { if msg.Type != MsgReply {
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
} }
if transactionId != msg.TransactionID { if transactionID != msg.TransactionID {
t.Fatalf("Expected transaction Id %v, got %v", transactionId, msg.TransactionID) t.Fatalf("Expected transaction ID %v, got %v", transactionID, msg.TransactionID)
} }
clientIdOption := msg.Options.ClientId() clientIDOption := msg.Options.ClientID()
if clientIdOption == nil { if clientIDOption == nil {
t.Fatalf("Client Id option should be present") t.Fatalf("Client ID option should be present")
} }
if string(expectedClientId) != string(clientIdOption) { if string(expectedClientID) != string(clientIDOption) {
t.Fatalf("Expected client id %v, got %v", expectedClientId, clientIdOption) t.Fatalf("Expected Client id %v, got %v", expectedClientID, clientIDOption)
} }
if len(expectedClientId) != len(clientIdOption) { if len(expectedClientID) != len(clientIDOption) {
t.Fatalf("Expected client id length of %d, got %d", len(expectedClientId), len(clientIdOption)) t.Fatalf("Expected Client id length of %d, got %d", len(expectedClientID), len(clientIDOption))
} }
serverIdOption := msg.Options.ServerId() serverIDOption := msg.Options.ServerID()
if serverIdOption == nil { if serverIDOption == nil {
t.Fatalf("Server Id option should be present") t.Fatalf("Server ID option should be present")
} }
if string(expectedServerId) != string(serverIdOption) { if string(expectedServerID) != string(serverIDOption) {
t.Fatalf("Expected server id %v, got %v", expectedClientId, serverIdOption) t.Fatalf("Expected server id %v, got %v", expectedClientID, serverIDOption)
} }
if len(expectedServerId) != len(serverIdOption) { if len(expectedServerID) != len(serverIDOption) {
t.Fatalf("Expected server id length of %d, got %d", len(expectedClientId), len(serverIdOption)) t.Fatalf("Expected server id length of %d, got %d", len(expectedClientID), len(serverIDOption))
} }
bootfileUrlOption := msg.Options.BootfileUrl() bootfileURLOption := msg.Options.BootFileURL()
if bootfileUrlOption == nil { if bootfileURLOption == nil {
t.Fatalf("Bootfile URL option should be present") t.Fatalf("Bootfile URL option should be present")
} }
if string(expectedBootFileUrl) != string(bootfileUrlOption) { if string(expectedBootFileURL) != string(bootfileURLOption) {
t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileUrl, bootfileUrlOption) t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileURL, bootfileURLOption)
} }
dnsServersOption := msg.Options[OptRecursiveDns] dnsServersOption := msg.Options[OptRecursiveDNS]
if dnsServersOption == nil { if dnsServersOption == nil {
t.Fatalf("DNS servers option should be set") t.Fatalf("DNS servers option should be set")
} }
if string(dnsServersOption[0].Value) != string(expectedDnsServerIp) { if string(dnsServersOption[0].Value) != string(expectedDnsServerIP) {
t.Fatalf("Expected dns server %v, got %v", expectedDnsServerIp, net.IP(dnsServersOption[0].Value)) t.Fatalf("Expected dns server %v, got %v", expectedDnsServerIP, net.IP(dnsServersOption[0].Value))
} }
} }
func TestMakeMsgInformationRequestReplyShouldSkipDnsServersIfNoneWereConfigured(t *testing.T) { func TestMakeMsgInformationRequestReplyShouldSkipDnsServersIfNoneWereConfigured(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
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")
} }
} }
func TestMakeMsgInformationRequestReplyWithHttpClientArch(t *testing.T) { func TestMakeMsgInformationRequestReplyWithHttpClientArch(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
expectedBootFileUrl := []byte("http://bootfileurl") expectedBootFileURL := []byte("http://bootfileurl")
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedServerId, expectedClientId, 0x10, msg := builder.MakeMsgInformationRequestReply(transactionID, expectedServerID, expectedClientID, 0x10,
expectedBootFileUrl, []net.IP{}) expectedBootFileURL, []net.IP{})
vendorClassOption := msg.Options[OptVendorClass] vendorClassOption := msg.Options[OptVendorClass]
if vendorClassOption == nil { if vendorClassOption == nil {
t.Fatalf("Vendor class option should be present") t.Fatalf("Vendor class option should be present")
} }
bootfileUrlOption := msg.Options.BootfileUrl() bootfileURLOption := msg.Options.BootFileURL()
if bootfileUrlOption == nil { if bootfileURLOption == nil {
t.Fatalf("Bootfile URL option should be present") t.Fatalf("Bootfile URL option should be present")
} }
if string(expectedBootFileUrl) != string(bootfileUrlOption) { if string(expectedBootFileURL) != string(bootfileURLOption) {
t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileUrl, bootfileUrlOption) t.Fatalf("Expected bootfile URL %v, got %v", expectedBootFileURL, bootfileURLOption)
} }
} }
func TestMakeMsgReleaseReply(t *testing.T) { func TestMakeMsgReleaseReply(t *testing.T) {
expectedClientId := []byte("clientid") expectedClientID := []byte("clientid")
expectedServerId := []byte("serverid") expectedServerID := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'} transactionID := [3]byte{'1', '2', '3'}
builder := MakePacketBuilder(90, 100) builder := MakePacketBuilder(90, 100)
msg := builder.MakeMsgReleaseReply(transactionId, expectedServerId, expectedClientId) msg := builder.MakeMsgReleaseReply(transactionID, expectedServerID, expectedClientID)
if msg.Type != MsgReply { if msg.Type != MsgReply {
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
} }
if transactionId != msg.TransactionID { if transactionID != msg.TransactionID {
t.Fatalf("Expected transaction Id %v, got %v", transactionId, msg.TransactionID) t.Fatalf("Expected transaction ID %v, got %v", transactionID, msg.TransactionID)
} }
clientIdOption := msg.Options.ClientId() clientIDOption := msg.Options.ClientID()
if clientIdOption == nil { if clientIDOption == nil {
t.Fatalf("Client Id option should be present") t.Fatalf("Client ID option should be present")
} }
if string(expectedClientId) != string(clientIdOption) { if string(expectedClientID) != string(clientIDOption) {
t.Fatalf("Expected client id %v, got %v", expectedClientId, clientIdOption) t.Fatalf("Expected Client id %v, got %v", expectedClientID, clientIDOption)
} }
if len(expectedClientId) != len(clientIdOption) { if len(expectedClientID) != len(clientIDOption) {
t.Fatalf("Expected client id length of %d, got %d", len(expectedClientId), len(clientIdOption)) t.Fatalf("Expected Client id length of %d, got %d", len(expectedClientID), len(clientIDOption))
} }
serverIdOption := msg.Options.ServerId() serverIDOption := msg.Options.ServerID()
if serverIdOption == nil { if serverIDOption == nil {
t.Fatalf("Server Id option should be present") t.Fatalf("Server ID option should be present")
} }
if string(expectedServerId) != string(serverIdOption) { if string(expectedServerID) != string(serverIDOption) {
t.Fatalf("Expected server id %v, got %v", expectedClientId, serverIdOption) t.Fatalf("Expected server id %v, got %v", expectedClientID, serverIDOption)
} }
if len(expectedServerId) != len(serverIdOption) { if len(expectedServerID) != len(serverIDOption) {
t.Fatalf("Expected server id length of %d, got %d", len(expectedClientId), len(serverIdOption)) t.Fatalf("Expected server id length of %d, got %d", len(expectedClientID), len(serverIDOption))
} }
} }
func TestExtractLLAddressOrIdWithDUIDLLT(t *testing.T) { func TestExtractLLAddressOrIdWithDUIDLLT(t *testing.T) {
builder := &PacketBuilder{} builder := &PacketBuilder{}
expectedLLAddress := []byte{0xac, 0xbc, 0x32, 0xae, 0x86, 0x37} expectedLLAddress := []byte{0xac, 0xbc, 0x32, 0xae, 0x86, 0x37}
llAddress := builder.ExtractLLAddressOrId([]byte{0x0, 0x1, 0x0, 0x1, 0x1, 0x2, 0x3, 0x4, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37}) llAddress := builder.ExtractLLAddressOrID([]byte{0x0, 0x1, 0x0, 0x1, 0x1, 0x2, 0x3, 0x4, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37})
if string(expectedLLAddress) != string(llAddress) { if string(expectedLLAddress) != string(llAddress) {
t.Fatalf("Expected ll address %x, got: %x", expectedLLAddress, llAddress) t.Fatalf("Expected ll address %x, got: %x", expectedLLAddress, llAddress)
} }
@ -494,7 +494,7 @@ func TestExtractLLAddressOrIdWithDUIDLLT(t *testing.T) {
func TestExtractLLAddressOrIdWithDUIDEN(t *testing.T) { func TestExtractLLAddressOrIdWithDUIDEN(t *testing.T) {
builder := &PacketBuilder{} builder := &PacketBuilder{}
expectedId := []byte{0x0, 0x1, 0x2, 0x3, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37} expectedId := []byte{0x0, 0x1, 0x2, 0x3, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37}
id := builder.ExtractLLAddressOrId([]byte{0x0, 0x2, 0x0, 0x1, 0x2, 0x3, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37}) id := builder.ExtractLLAddressOrID([]byte{0x0, 0x2, 0x0, 0x1, 0x2, 0x3, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37})
if string(expectedId) != string(id) { if string(expectedId) != string(id) {
t.Fatalf("Expected id %x, got: %x", expectedId, id) t.Fatalf("Expected id %x, got: %x", expectedId, id)
} }
@ -503,7 +503,7 @@ func TestExtractLLAddressOrIdWithDUIDEN(t *testing.T) {
func TestExtractLLAddressOrIdWithDUIDLL(t *testing.T) { func TestExtractLLAddressOrIdWithDUIDLL(t *testing.T) {
builder := &PacketBuilder{} builder := &PacketBuilder{}
expectedLLAddress := []byte{0xac, 0xbc, 0x32, 0xae, 0x86, 0x37} expectedLLAddress := []byte{0xac, 0xbc, 0x32, 0xae, 0x86, 0x37}
llAddress := builder.ExtractLLAddressOrId([]byte{0x0, 0x3, 0x0, 0x1, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37}) llAddress := builder.ExtractLLAddressOrID([]byte{0x0, 0x3, 0x0, 0x1, 0xac, 0xbc, 0x32, 0xae, 0x86, 0x37})
if string(expectedLLAddress) != string(llAddress) { if string(expectedLLAddress) != string(llAddress) {
t.Fatalf("Expected ll address %x, got: %x", expectedLLAddress, llAddress) t.Fatalf("Expected ll address %x, got: %x", expectedLLAddress, llAddress)
} }

View File

@ -6,9 +6,9 @@ import (
) )
func TestShouldDiscardSolicitWithoutBootfileUrlOption(t *testing.T) { func TestShouldDiscardSolicitWithoutBootfileUrlOption(t *testing.T) {
clientId := []byte("clientid") clientID := []byte("clientid")
options := make(Options) options := make(Options)
options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId}) options.AddOption(&Option{ID: OptClientID, Length: uint16(len(clientID)), Value: clientID})
solicit := &Packet{Type: MsgSolicit, TransactionID: [3]byte{'1', '2', '3'}, Options: options} solicit := &Packet{Type: MsgSolicit, TransactionID: [3]byte{'1', '2', '3'}, Options: options}
if err := ShouldDiscardSolicit(solicit); err == nil { if err := ShouldDiscardSolicit(solicit); err == nil {
@ -18,7 +18,7 @@ func TestShouldDiscardSolicitWithoutBootfileUrlOption(t *testing.T) {
func TestShouldDiscardSolicitWithoutClientIdOption(t *testing.T) { func TestShouldDiscardSolicitWithoutClientIdOption(t *testing.T) {
options := make(Options) options := make(Options)
options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileUrl})) options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileURL}))
solicit := &Packet{Type: MsgSolicit, TransactionID: [3]byte{'1', '2', '3'}, Options: options} solicit := &Packet{Type: MsgSolicit, TransactionID: [3]byte{'1', '2', '3'}, Options: options}
if err := ShouldDiscardSolicit(solicit); err == nil { if err := ShouldDiscardSolicit(solicit); err == nil {
@ -27,12 +27,12 @@ func TestShouldDiscardSolicitWithoutClientIdOption(t *testing.T) {
} }
func TestShouldDiscardSolicitWithServerIdOption(t *testing.T) { func TestShouldDiscardSolicitWithServerIdOption(t *testing.T) {
serverId := []byte("serverid") serverID := []byte("serverid")
clientId := []byte("clientid") clientID := []byte("clientid")
options := make(Options) options := make(Options)
options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileUrl})) options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileURL}))
options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId}) options.AddOption(&Option{ID: OptClientID, Length: uint16(len(clientID)), Value: clientID})
options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverId)), Value: serverId}) options.AddOption(&Option{ID: OptServerID, Length: uint16(len(serverID)), Value: serverID})
solicit := &Packet{Type: MsgSolicit, TransactionID: [3]byte{'1', '2', '3'}, Options: options} solicit := &Packet{Type: MsgSolicit, TransactionID: [3]byte{'1', '2', '3'}, Options: options}
if err := ShouldDiscardSolicit(solicit); err == nil { if err := ShouldDiscardSolicit(solicit); err == nil {
@ -41,35 +41,35 @@ func TestShouldDiscardSolicitWithServerIdOption(t *testing.T) {
} }
func TestShouldDiscardRequestWithoutBootfileUrlOption(t *testing.T) { func TestShouldDiscardRequestWithoutBootfileUrlOption(t *testing.T) {
serverId := []byte("serverid") serverID := []byte("serverid")
clientId := []byte("clientid") clientID := []byte("clientid")
options := make(Options) options := make(Options)
options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId}) options.AddOption(&Option{ID: OptClientID, Length: uint16(len(clientID)), Value: clientID})
options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverId)), Value: serverId}) options.AddOption(&Option{ID: OptServerID, Length: uint16(len(serverID)), Value: serverID})
request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options} request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options}
if err := ShouldDiscardRequest(request, serverId); err == nil { if err := ShouldDiscardRequest(request, serverID); err == nil {
t.Fatalf("Should discard request packet without bootfile url option, but didn't") t.Fatalf("Should discard request packet without bootfile url option, but didn't")
} }
} }
func TestShouldDiscardRequestWithoutClientIdOption(t *testing.T) { func TestShouldDiscardRequestWithoutClientIdOption(t *testing.T) {
serverId := []byte("serverid") serverID := []byte("serverid")
options := make(Options) options := make(Options)
options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileUrl})) options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileURL}))
options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverId)), Value: serverId}) options.AddOption(&Option{ID: OptServerID, Length: uint16(len(serverID)), Value: serverID})
request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options} request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options}
if err := ShouldDiscardRequest(request, serverId); err == nil { if err := ShouldDiscardRequest(request, serverID); err == nil {
t.Fatalf("Should discard request packet without client id option, but didn't") t.Fatalf("Should discard request packet without client id option, but didn't")
} }
} }
func TestShouldDiscardRequestWithoutServerIdOption(t *testing.T) { func TestShouldDiscardRequestWithoutServerIdOption(t *testing.T) {
clientId := []byte("clientid") clientID := []byte("clientid")
options := make(Options) options := make(Options)
options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileUrl})) options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileURL}))
options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId}) options.AddOption(&Option{ID: OptClientID, Length: uint16(len(clientID)), Value: clientID})
request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options} request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options}
if err := ShouldDiscardRequest(request, []byte("serverid")); err == nil { if err := ShouldDiscardRequest(request, []byte("serverid")); err == nil {
@ -78,12 +78,12 @@ func TestShouldDiscardRequestWithoutServerIdOption(t *testing.T) {
} }
func TestShouldDiscardRequestWithWrongServerId(t *testing.T) { func TestShouldDiscardRequestWithWrongServerId(t *testing.T) {
clientId := []byte("clientid") clientID := []byte("clientid")
serverId := []byte("serverid") serverID := []byte("serverid")
options := make(Options) options := make(Options)
options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileUrl})) options.AddOption(MakeOptionRequestOptions([]uint16{OptBootfileURL}))
options.AddOption(&Option{Id: OptClientId, Length: uint16(len(clientId)), Value: clientId}) options.AddOption(&Option{ID: OptClientID, Length: uint16(len(clientID)), Value: clientID})
options.AddOption(&Option{Id: OptServerId, Length: uint16(len(serverId)), Value: serverId}) options.AddOption(&Option{ID: OptServerID, Length: uint16(len(serverID)), Value: serverID})
request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options} request := &Packet{Type: MsgRequest, TransactionID: [3]byte{'1', '2', '3'}, Options: options}
if err := ShouldDiscardRequest(request, []byte("wrongid")); err == nil { if err := ShouldDiscardRequest(request, []byte("wrongid")); err == nil {
@ -97,6 +97,6 @@ func MakeOptionRequestOptions(options []uint16) *Option {
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}
} }

View File

@ -26,9 +26,9 @@ func (f *Fifo) Push(v interface{}) {
} }
func (f *Fifo) Shift() interface{} { func (f *Fifo) Shift() interface{} {
var to_ret interface{} var ret interface{}
to_ret, f.q = f.q[0], f.q[1:] ret, f.q = f.q[0], f.q[1:]
return to_ret return ret
} }
func (f *Fifo) Size() int { func (f *Fifo) Size() int {
@ -54,37 +54,37 @@ type RandomAddressPool struct {
} }
func NewRandomAddressPool(poolStartAddress net.IP, poolSize uint64, validLifetime uint32) *RandomAddressPool { func NewRandomAddressPool(poolStartAddress net.IP, poolSize uint64, validLifetime uint32) *RandomAddressPool {
to_ret := &RandomAddressPool{} ret := &RandomAddressPool{}
to_ret.validLifetime = validLifetime ret.validLifetime = validLifetime
to_ret.poolStartAddress = big.NewInt(0) ret.poolStartAddress = big.NewInt(0)
to_ret.poolStartAddress.SetBytes(poolStartAddress) ret.poolStartAddress.SetBytes(poolStartAddress)
to_ret.poolSize = poolSize ret.poolSize = poolSize
to_ret.identityAssociations = make(map[uint64]*IdentityAssociation) ret.identityAssociations = make(map[uint64]*IdentityAssociation)
to_ret.usedIps = make(map[uint64]struct{}) ret.usedIps = make(map[uint64]struct{})
to_ret.identityAssociationExpirations = newFifo() ret.identityAssociationExpirations = newFifo()
to_ret.timeNow = func() time.Time { return time.Now() } ret.timeNow = func() time.Time { return time.Now() }
ticker := time.NewTicker(time.Second * 10).C ticker := time.NewTicker(time.Second * 10).C
go func() { go func() {
for { for {
<- ticker <- ticker
to_ret.ExpireIdentityAssociations() ret.ExpireIdentityAssociations()
} }
}() }()
return to_ret return ret
} }
func (p *RandomAddressPool) ReserveAddresses(clientId []byte, interfaceIds [][]byte) ([]*IdentityAssociation, error) { func (p *RandomAddressPool) ReserveAddresses(clientID []byte, interfaceIDs [][]byte) ([]*IdentityAssociation, error) {
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
ret := make([]*IdentityAssociation, 0, len(interfaceIds)) ret := make([]*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)
@ -101,11 +101,11 @@ func (p *RandomAddressPool) ReserveAddresses(clientId []byte, interfaceIds [][]b
_, exists := p.usedIps[newIp.Uint64()]; _, exists := p.usedIps[newIp.Uint64()];
if !exists { if !exists {
timeNow := p.timeNow() timeNow := p.timeNow()
association := &IdentityAssociation{ClientId: clientId, association := &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})
ret = append(ret, association) ret = append(ret, association)
@ -117,17 +117,17 @@ func (p *RandomAddressPool) ReserveAddresses(clientId []byte, interfaceIds [][]b
return ret, nil return ret, nil
} }
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
} }
delete(p.usedIps, big.NewInt(0).SetBytes(association.IpAddress).Uint64()) delete(p.usedIps, big.NewInt(0).SetBytes(association.IPAddress).Uint64())
delete(p.identityAssociations, p.calculateIaIdHash(clientId, interfaceId)) delete(p.identityAssociations, p.calculateIAIDHash(clientID, interfaceId))
} }
} }
@ -140,8 +140,8 @@ func (p *RandomAddressPool) ExpireIdentityAssociations() {
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())
} }
} }
@ -149,10 +149,10 @@ func (p *RandomAddressPool) calculateAssociationExpiration(now time.Time) time.T
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 {
h := fnv.New64a() h := fnv.New64a()
h.Write(clientId) h.Write(clientID)
h.Write(interfaceId) h.Write(interfaceID)
return h.Sum64() return h.Sum64()
} }

View File

@ -7,42 +7,42 @@ import (
) )
func TestReserveAddress(t *testing.T) { func TestReserveAddress(t *testing.T) {
expectedIp1 := net.ParseIP("2001:db8:f00f:cafe::1") expectedIP1 := net.ParseIP("2001:db8:f00f:cafe::1")
expectedIp2 := net.ParseIP("2001:db8:f00f:cafe::2") expectedIP2 := net.ParseIP("2001:db8:f00f:cafe::2")
expectedClientId := []byte("client-id") expectedClientID := []byte("Client-id")
expectedIaId1 := []byte("interface-id-1") expectedIAID1 := []byte("interface-id-1")
expectedIaId2 := []byte("interface-id-2") expectedIAID2 := []byte("interface-id-2")
expectedTime := time.Now() expectedTime := time.Now()
expectedMaxLifetime := uint32(100) expectedMaxLifetime := uint32(100)
pool := NewRandomAddressPool(expectedIp1, 2, expectedMaxLifetime) pool := NewRandomAddressPool(expectedIP1, 2, expectedMaxLifetime)
pool.timeNow = func() time.Time { return expectedTime } pool.timeNow = func() time.Time { return expectedTime }
ias, _ := pool.ReserveAddresses(expectedClientId, [][]byte{expectedIaId1, expectedIaId2}) ias, _ := pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID1, expectedIAID2})
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 {
t.Fatalf("Expected creation time: %v, but got: %v", expectedTime, ias[1].CreatedAt) t.Fatalf("Expected creation time: %v, but got: %v", expectedTime, ias[1].CreatedAt)
@ -50,35 +50,35 @@ func TestReserveAddress(t *testing.T) {
} }
func TestReserveAddressUpdatesAddressPool(t *testing.T) { func TestReserveAddressUpdatesAddressPool(t *testing.T) {
expectedClientId := []byte("client-id") expectedClientID := []byte("Client-id")
expectedIaId := []byte("interface-id") expectedIAID := []byte("interface-id")
expectedTime := time.Now() expectedTime := time.Now()
expectedMaxLifetime := uint32(100) expectedMaxLifetime := uint32(100)
pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime) pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime)
pool.timeNow = func() time.Time { return expectedTime } pool.timeNow = func() time.Time { return expectedTime }
pool.ReserveAddresses(expectedClientId, [][]byte{expectedIaId}) pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID})
expectedIdx := pool.calculateIaIdHash(expectedClientId, expectedIaId) expectedIdx := pool.calculateIAIDHash(expectedClientID, expectedIAID)
a, exists := pool.identityAssociations[expectedIdx] a, exists := pool.identityAssociations[expectedIdx]
if !exists { if !exists {
t.Fatalf("Expected to find identity association at %d but didn't", expectedIdx) t.Fatalf("Expected to find identity association at %d but didn't", expectedIdx)
} }
if string(a.ClientId) != string(expectedClientId) || string(a.InterfaceId) != string(expectedIaId) { if string(a.ClientID) != string(expectedClientID) || string(a.InterfaceID) != string(expectedIAID) {
t.Fatalf("Expected ia association with client id %x and ia id %x, but got %x %x respectively", t.Fatalf("Expected ia association with Client id %x and ia id %x, but got %x %x respectively",
expectedClientId, expectedIaId, a.ClientId, a.InterfaceId) expectedClientID, expectedIAID, a.ClientID, a.InterfaceID)
} }
} }
func TestReserveAddressKeepsTrackOfUsedAddresses(t *testing.T) { func TestReserveAddressKeepsTrackOfUsedAddresses(t *testing.T) {
expectedClientId := []byte("client-id") expectedClientID := []byte("Client-id")
expectedIaId := []byte("interface-id") expectedIAID := []byte("interface-id")
expectedTime := time.Now() expectedTime := time.Now()
expectedMaxLifetime := uint32(100) expectedMaxLifetime := uint32(100)
pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime) pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime)
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")
@ -86,14 +86,14 @@ func TestReserveAddressKeepsTrackOfUsedAddresses(t *testing.T) {
} }
func TestReserveAddressKeepsTrackOfAssociationExpiration(t *testing.T) { func TestReserveAddressKeepsTrackOfAssociationExpiration(t *testing.T) {
expectedClientId := []byte("client-id") expectedClientID := []byte("Client-id")
expectedIaId := []byte("interface-id") expectedIAID := []byte("interface-id")
expectedTime := time.Now() expectedTime := time.Now()
expectedMaxLifetime := uint32(100) expectedMaxLifetime := uint32(100)
pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime) pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime)
pool.timeNow = func() time.Time { return expectedTime } pool.timeNow = func() time.Time { return expectedTime }
pool.ReserveAddresses(expectedClientId, [][]byte{expectedIaId}) pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID})
expiration := pool.identityAssociationExpirations.Peek().(*AssociationExpiration) expiration := pool.identityAssociationExpirations.Peek().(*AssociationExpiration)
if expiration == nil { if expiration == nil {
@ -106,15 +106,15 @@ func TestReserveAddressKeepsTrackOfAssociationExpiration(t *testing.T) {
} }
func TestReserveAddressReturnsExistingAssociation(t *testing.T) { func TestReserveAddressReturnsExistingAssociation(t *testing.T) {
expectedClientId := []byte("client-id") expectedClientID := []byte("Client-id")
expectedIaId := []byte("interface-id") expectedIAID := []byte("interface-id")
expectedTime := time.Now() expectedTime := time.Now()
expectedMaxLifetime := uint32(100) expectedMaxLifetime := uint32(100)
pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime) pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime)
pool.timeNow = func() time.Time { return expectedTime } pool.timeNow = func() time.Time { return expectedTime }
firstAssociation, _ := pool.ReserveAddresses(expectedClientId, [][]byte{expectedIaId}) firstAssociation, _ := pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID})
secondAssociation, _ := pool.ReserveAddresses(expectedClientId, [][]byte{expectedIaId}) secondAssociation, _ := pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID})
if len(firstAssociation) < 1 { if len(firstAssociation) < 1 {
t.Fatalf("No associations returned from the first call to ReserveAddresses") t.Fatalf("No associations returned from the first call to ReserveAddresses")
@ -122,24 +122,24 @@ func TestReserveAddressReturnsExistingAssociation(t *testing.T) {
if len(secondAssociation) < 1 { if len(secondAssociation) < 1 {
t.Fatalf("No associations returned from the second call to ReserveAddresses") t.Fatalf("No associations returned from the second call to ReserveAddresses")
} }
if string(firstAssociation[0].IpAddress) != string(secondAssociation[0].IpAddress) { if string(firstAssociation[0].IPAddress) != string(secondAssociation[0].IPAddress) {
t.Fatal("Expected return of the same ip address on both invocations") t.Fatal("Expected return of the same ip address on both invocations")
} }
} }
func TestReleaseAddress(t *testing.T) { func TestReleaseAddress(t *testing.T) {
expectedClientId := []byte("client-id") expectedClientID := []byte("Client-id")
expectedIaId := []byte("interface-id") expectedIAID := []byte("interface-id")
expectedTime := time.Now() expectedTime := time.Now()
expectedMaxLifetime := uint32(100) expectedMaxLifetime := uint32(100)
pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime) pool := NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, expectedMaxLifetime)
pool.timeNow = func() time.Time { return expectedTime } pool.timeNow = func() time.Time { return expectedTime }
a, _ := pool.ReserveAddresses(expectedClientId, [][]byte{expectedIaId}) a, _ := pool.ReserveAddresses(expectedClientID, [][]byte{expectedIAID})
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)
} }
} }

View File

@ -18,11 +18,11 @@ var bootIPv6Cmd = &cobra.Command{
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
} }
ipxeUrl, err := cmd.Flags().GetString("ipxe-url") ipxeURL, err := cmd.Flags().GetString("ipxe-url")
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
} }
httpBootUrl, err := cmd.Flags().GetString("httpboot-url") httpBootURL, err := cmd.Flags().GetString("httpboot-url")
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
} }
@ -40,10 +40,10 @@ var bootIPv6Cmd = &cobra.Command{
fatalf("Please specify address to bind to") fatalf("Please specify address to bind to")
} else { } else {
} }
if ipxeUrl == "" { if ipxeURL == "" {
fatalf("Please specify ipxe config file url") fatalf("Please specify ipxe config file url")
} }
if httpBootUrl == "" { if httpBootURL == "" {
fatalf("Please specify httpboot url") fatalf("Please specify httpboot url")
} }
@ -62,7 +62,7 @@ var bootIPv6Cmd = &cobra.Command{
dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress)) dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress))
} }
} }
s.BootConfig = dhcp6.MakeStaticBootConfiguration(httpBootUrl, ipxeUrl, preference, s.BootConfig = dhcp6.MakeStaticBootConfiguration(httpBootURL, ipxeURL, preference,
cmd.Flags().Changed("preference"), dnsServerAddresses) cmd.Flags().Changed("preference"), dnsServerAddresses)
addressPoolStart, err := cmd.Flags().GetString("address-pool-start") addressPoolStart, err := cmd.Flags().GetString("address-pool-start")

View File

@ -20,7 +20,7 @@ var ipv6ApiCmd = &cobra.Command{
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
} }
apiUrl, err := cmd.Flags().GetString("api-request-url") apiURL, err := cmd.Flags().GetString("api-request-url")
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
} }
@ -41,7 +41,7 @@ var ipv6ApiCmd = &cobra.Command{
fatalf("Please specify address to bind to") fatalf("Please specify address to bind to")
} else { } else {
} }
if apiUrl == "" { if apiURL == "" {
fatalf("Please specify ipxe config file url") fatalf("Please specify ipxe config file url")
} }
s.Address = addr s.Address = addr
@ -59,7 +59,7 @@ var ipv6ApiCmd = &cobra.Command{
dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress)) dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress))
} }
} }
s.BootConfig = dhcp6.MakeApiBootConfiguration(apiUrl, apiTimeout, preference, s.BootConfig = dhcp6.MakeApiBootConfiguration(apiURL, apiTimeout, preference,
cmd.Flags().Changed("preference"), dnsServerAddresses) cmd.Flags().Changed("preference"), dnsServerAddresses)
addressPoolStart, err := cmd.Flags().GetString("address-pool-start") addressPoolStart, err := cmd.Flags().GetString("address-pool-start")
@ -81,7 +81,7 @@ var ipv6ApiCmd = &cobra.Command{
}, },
} }
func serverv6ApiConfigFlags(cmd *cobra.Command) { func serverv6APIConfigFlags(cmd *cobra.Command) {
cmd.Flags().StringP("listen-addr", "", "", "IPv6 address to listen on") cmd.Flags().StringP("listen-addr", "", "", "IPv6 address to listen on")
cmd.Flags().StringP("api-request-url", "", "", "Ipv6-specific API server url") cmd.Flags().StringP("api-request-url", "", "", "Ipv6-specific API server url")
cmd.Flags().Duration("api-request-timeout", 5*time.Second, "Timeout for request to the API server") cmd.Flags().Duration("api-request-timeout", 5*time.Second, "Timeout for request to the API server")
@ -95,6 +95,6 @@ func serverv6ApiConfigFlags(cmd *cobra.Command) {
func init() { func init() {
rootCmd.AddCommand(ipv6ApiCmd) rootCmd.AddCommand(ipv6ApiCmd)
serverv6ApiConfigFlags(ipv6ApiCmd) serverv6APIConfigFlags(ipv6ApiCmd)
} }

View File

@ -34,13 +34,13 @@ func (s *ServerV6) serveDHCP(conn *dhcp6.Conn) error {
continue continue
} }
marshalled_response, err := response.Marshal() marshalledResponse, err := response.Marshal()
if err != nil { if err != nil {
s.log("dhcpv6", fmt.Sprintf("Error marshalling response: %s", response.Type, response.TransactionID, err)) s.log("dhcpv6", fmt.Sprintf("Error marshalling response: %s", response.Type, response.TransactionID, err))
continue continue
} }
if err := conn.SendDHCP(src, marshalled_response); err != nil { if err := conn.SendDHCP(src, marshalledResponse); err != nil {
s.log("dhcpv6", fmt.Sprintf("Error sending reply (%d) (%d): %s", response.Type, response.TransactionID, err)) s.log("dhcpv6", fmt.Sprintf("Error sending reply (%d) (%d): %s", response.Type, response.TransactionID, err))
continue continue
} }