added support for generation of "dns servers" option

This commit is contained in:
Dmitri Dolguikh 2017-10-30 16:28:33 -07:00 committed by Dave Anderson
parent b78d515ee1
commit 6c11f1e722
8 changed files with 102 additions and 38 deletions

View File

@ -20,10 +20,6 @@ import (
"go.universe.tf/netboot/third_party/ipxe" "go.universe.tf/netboot/third_party/ipxe"
) )
// qemu-system-x86_64 -L . --bios /usr/share/edk2-firmware/ipv6/OVMF.fd -netdev bridge,br=br1,id=net0 -device virtio-net-pci,netdev=net0
// sudo ./pixiecore bootipv6 --listen-addr=2001:db8:f00f:cafe::4/64 --httpboot-url=http://[2001:db8:f00f:cafe::4]/bootx64.efi --ipxe-url=http://[2001:db8:f00f:cafe::4]/script.ipxe
// sudo ./pixiecore ipv6api --listen-addr=2001:db8:f00f:cafe::4 --api-request-url=http://[2001:db8:f00f:cafe::4]:8888
func main() { func main() {
cli.Ipxe[pixiecore.FirmwareX86PC] = ipxe.MustAsset("undionly.kpxe") cli.Ipxe[pixiecore.FirmwareX86PC] = ipxe.MustAsset("undionly.kpxe")
cli.Ipxe[pixiecore.FirmwareEFI32] = ipxe.MustAsset("ipxe-i386.efi") cli.Ipxe[pixiecore.FirmwareEFI32] = ipxe.MustAsset("ipxe-i386.efi")

View File

@ -7,28 +7,31 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"bytes" "bytes"
"net"
) )
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() []byte GetRecursiveDns() []net.IP
} }
type StaticBootConfiguration struct { type StaticBootConfiguration struct {
HttpBootUrl []byte HttpBootUrl []byte
IPxeBootUrl []byte IPxeBootUrl []byte
RecursiveDns []byte RecursiveDns []net.IP
Preference []byte Preference []byte
UsePreference bool UsePreference bool
} }
func MakeStaticBootConfiguration(httpBootUrl, ipxeBootUrl string, preference uint8, usePreference bool) *StaticBootConfiguration { func MakeStaticBootConfiguration(httpBootUrl, ipxeBootUrl string, preference uint8, usePreference bool,
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
return ret return ret
} }
@ -43,19 +46,20 @@ func (bc *StaticBootConfiguration) GetPreference() []byte {
return bc.Preference return bc.Preference
} }
func (bc *StaticBootConfiguration) GetRecursiveDns() []byte { 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 []byte RecursiveDns []net.IP
Preference []byte Preference []byte
UsePreference bool UsePreference bool
} }
func MakeApiBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool) *ApiBootConfiguration { func MakeApiBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool,
dnsServerAddresses []net.IP) *ApiBootConfiguration {
if !strings.HasSuffix(url, "/") { if !strings.HasSuffix(url, "/") {
url += "/" url += "/"
} }
@ -68,6 +72,7 @@ func MakeApiBootConfiguration(url string, timeout time.Duration, preference uint
ret.Preference = make([]byte, 1) ret.Preference = make([]byte, 1)
ret.Preference[0] = byte(preference) ret.Preference[0] = byte(preference)
} }
ret.RecursiveDns = dnsServerAddresses
return ret return ret
} }
@ -110,6 +115,6 @@ func (bc *ApiBootConfiguration) GetPreference() []byte {
return bc.Preference return bc.Preference
} }
func (bc *ApiBootConfiguration) GetRecursiveDns() []byte { func (bc *ApiBootConfiguration) GetRecursiveDns() []net.IP {
return bc.RecursiveDns return bc.RecursiveDns
} }

View File

@ -158,6 +158,14 @@ func MakeStatusOption(statusCode uint16, message string) *Option {
return MakeOption(OptStatusCode, value) return MakeOption(OptStatusCode, value)
} }
func MakeDNSServersOption(addresses []net.IP) *Option {
value := make([]byte, 16*len(addresses))
for i, dnsAddress := range addresses {
copy(value[i*16:], dnsAddress)
}
return MakeOption(OptRecursiveDns, value)
}
func (o Options) Marshal() ([]byte, error) { func (o Options) Marshal() ([]byte, error) {
buffer := bytes.NewBuffer(make([]byte, 0, 1446)) buffer := bytes.NewBuffer(make([]byte, 0, 1446))
for _, multipleOptions := range(o) { for _, multipleOptions := range(o) {

View File

@ -102,3 +102,22 @@ func TestUnmarshalFailsIfOROLengthIsOdd(t *testing.T) {
t.Fatalf("Parsing options should fail: option request for options has odd length.") t.Fatalf("Parsing options should fail: option request for options has odd length.")
} }
} }
func TestMakeDNSServersOption(t *testing.T) {
expectedAddress1 := net.ParseIP("2001:db8:f00f:cafe::99")
expectedAddress2 := net.ParseIP("2001:db8:f00f:cafe::9A")
dnsServersOption := MakeDNSServersOption([]net.IP{expectedAddress1, expectedAddress2})
if dnsServersOption.Id != OptRecursiveDns {
t.Fatalf("Expected option id %d, got %d", OptRecursiveDns, dnsServersOption.Id)
}
if dnsServersOption.Length != 32 {
t.Fatalf("Expected length 32 bytes, got %d", dnsServersOption.Length)
}
if string(dnsServersOption.Value[0:16]) != string(expectedAddress1) {
t.Fatalf("Expected dns server address %v, got %v", expectedAddress1, net.IP(dnsServersOption.Value[0:16]))
}
if string(dnsServersOption.Value[16:]) != string(expectedAddress2) {
t.Fatalf("Expected dns server address %v, got %v", expectedAddress2, net.IP(dnsServersOption.Value[16:]))
}
}

View File

@ -3,6 +3,7 @@ package dhcp6
import ( import (
"hash/fnv" "hash/fnv"
"encoding/binary" "encoding/binary"
"net"
) )
type PacketBuilder struct { type PacketBuilder struct {
@ -27,7 +28,7 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio
return b.MakeMsgAdvertiseWithNoAddrsAvailable(in.TransactionID, in.Options.ClientId(), err), err return b.MakeMsgAdvertiseWithNoAddrsAvailable(in.TransactionID, in.Options.ClientId(), err), err
} }
return b.MakeMsgAdvertise(in.TransactionID, in.Options.ClientId(), return b.MakeMsgAdvertise(in.TransactionID, in.Options.ClientId(),
in.Options.ClientArchType(), associations, bootFileUrl, configuration.GetPreference()), 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 {
@ -35,14 +36,15 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio
} }
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, in.Options.ClientId(), return b.MakeMsgReply(in.TransactionID, in.Options.ClientId(),
in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIds()), bootFileUrl, err), err in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIds()), bootFileUrl,
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, in.Options.ClientId(), return b.MakeMsgInformationRequestReply(in.TransactionID, in.Options.ClientId(),
in.Options.ClientArchType(), bootFileUrl), 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, in.Options.ClientId()), nil return b.MakeMsgReleaseReply(in.TransactionID, in.Options.ClientId()), nil
@ -52,7 +54,7 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio
} }
func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte, clientArchType uint16, func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte, clientArchType uint16,
associations []*IdentityAssociation, bootFileUrl, preference []byte) *Packet { associations []*IdentityAssociation, bootFileUrl, preference []byte, dnsServers []net.IP) *Packet {
ret_options := make(Options) ret_options := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) ret_options.AddOption(MakeOption(OptClientId, clientId))
for _, association := range(associations) { for _, association := range(associations) {
@ -65,15 +67,13 @@ func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte,
} }
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl)) ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
if preference != nil {ret_options.AddOption(MakeOption(OptPreference, preference))} if preference != nil {ret_options.AddOption(MakeOption(OptPreference, preference))}
ret_options.AddOption(MakeDNSServersOption(dnsServers))
//ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
//ret_options.AddOption(OptBootfileParam, []byte("http://")
return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options}
} }
func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, clientArchType uint16, func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, clientArchType uint16,
associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileUrl []byte, err error) *Packet { associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileUrl []byte, dnsServers []net.IP, err error) *Packet {
ret_options := make(Options) ret_options := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) ret_options.AddOption(MakeOption(OptClientId, clientId))
for _, association := range(associations) { for _, association := range(associations) {
@ -89,12 +89,13 @@ func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, cli
ret_options.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(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)) ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
ret_options.AddOption(MakeDNSServersOption(dnsServers))
return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options}
} }
func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, clientId []byte, clientArchType uint16, func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, clientId []byte, clientArchType uint16,
bootFileUrl []byte) *Packet { bootFileUrl []byte, dnsServers []net.IP) *Packet {
ret_options := make(Options) ret_options := make(Options)
ret_options.AddOption(MakeOption(OptClientId, clientId)) ret_options.AddOption(MakeOption(OptClientId, clientId))
ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid)) ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid))
@ -102,6 +103,7 @@ func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, cl
ret_options.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(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)) ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
ret_options.AddOption(MakeDNSServersOption(dnsServers))
return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options}
} }

View File

@ -14,12 +14,13 @@ func TestMakeMsgAdvertise(t *testing.T) {
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")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: expectedInterfaceId} identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: expectedInterfaceId}
builder := MakePacketBuilder(expectedServerId, 90, 100) builder := MakePacketBuilder(expectedServerId, 90, 100)
msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation}, msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation},
expectedBootFileUrl, nil) 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)
@ -70,7 +71,7 @@ func TestShouldSetPreferenceOptionWhenSpecified(t *testing.T) {
expectedPreference := []byte{128} expectedPreference := []byte{128}
msg := builder.MakeMsgAdvertise([3]byte{'t', 'i', 'd'}, []byte("clientid"), 0x11, msg := builder.MakeMsgAdvertise([3]byte{'t', 'i', 'd'}, []byte("clientid"), 0x11,
[]*IdentityAssociation{identityAssociation}, []byte("http://bootfileurl"), expectedPreference) []*IdentityAssociation{identityAssociation}, []byte("http://bootfileurl"), expectedPreference, []net.IP{})
preferenceOption := msg.Options[OptPreference] preferenceOption := msg.Options[OptPreference]
if preferenceOption == nil { if preferenceOption == nil {
@ -92,7 +93,7 @@ func TestMakeMsgAdvertiseWithHttpClientArch(t *testing.T) {
builder := MakePacketBuilder(expectedServerId, 90, 100) builder := MakePacketBuilder(expectedServerId, 90, 100)
msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x10, []*IdentityAssociation{identityAssociation}, msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x10, []*IdentityAssociation{identityAssociation},
expectedBootFileUrl, nil) expectedBootFileUrl, nil, []net.IP{})
vendorClassOption := msg.Options[OptVendorClass] vendorClassOption := msg.Options[OptVendorClass]
if vendorClassOption == nil { if vendorClassOption == nil {
@ -158,12 +159,13 @@ func TestMakeMsgReply(t *testing.T) {
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")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")}
builder := MakePacketBuilder(expectedServerId, 90, 100) builder := MakePacketBuilder(expectedServerId, 90, 100)
msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation}, msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation},
make([][]byte, 0), expectedBootFileUrl, nil) 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)
@ -220,7 +222,7 @@ func TestMakeMsgReplyWithHttpClientArch(t *testing.T) {
msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10, msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10,
[]*IdentityAssociation{identityAssociation}, make([][]byte, 0), []*IdentityAssociation{identityAssociation}, make([][]byte, 0),
expectedBootFileUrl, nil) expectedBootFileUrl, []net.IP{}, nil)
vendorClassOption := msg.Options[OptVendorClass] vendorClassOption := msg.Options[OptVendorClass]
if vendorClassOption == nil { if vendorClassOption == nil {
@ -248,7 +250,7 @@ func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) {
builder := MakePacketBuilder(expectedServerId, 90, 100) builder := MakePacketBuilder(expectedServerId, 90, 100)
msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10, msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10,
[]*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileUrl, []*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileUrl, []net.IP{},
fmt.Errorf(expectedErrorMessage)) fmt.Errorf(expectedErrorMessage))
iaNaOption := msg.Options[OptIaNa] iaNaOption := msg.Options[OptIaNa]
@ -295,10 +297,12 @@ func TestMakeMsgInformationRequestReply(t *testing.T) {
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")
builder := MakePacketBuilder(expectedServerId, 90, 100) builder := MakePacketBuilder(expectedServerId, 90, 100)
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x11, expectedBootFileUrl) msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x11,
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)
@ -346,7 +350,8 @@ func TestMakeMsgInformationRequestReplyWithHttpClientArch(t *testing.T) {
builder := MakePacketBuilder(expectedServerId, 90, 100) builder := MakePacketBuilder(expectedServerId, 90, 100)
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x10, expectedBootFileUrl) msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x10,
expectedBootFileUrl, []net.IP{})
vendorClassOption := msg.Options[OptVendorClass] vendorClassOption := msg.Options[OptVendorClass]
if vendorClassOption == nil { if vendorClassOption == nil {

View File

@ -6,8 +6,10 @@ import (
"go.universe.tf/netboot/pixiecorev6" "go.universe.tf/netboot/pixiecorev6"
"go.universe.tf/netboot/dhcp6" "go.universe.tf/netboot/dhcp6"
"net" "net"
"strings"
) )
// pixiecore bootipv6 --listen-addr=2001:db8:f00f:cafe::4/64 --httpboot-url=http://[2001:db8:f00f:cafe::4]/bootx64.efi --ipxe-url=http://[2001:db8:f00f:cafe::4]/script.ipxe
var bootIPv6Cmd = &cobra.Command{ var bootIPv6Cmd = &cobra.Command{
Use: "bootipv6", Use: "bootipv6",
Short: "Boot a kernel and optional init ramdisks over IPv6", Short: "Boot a kernel and optional init ramdisks over IPv6",
@ -50,7 +52,18 @@ var bootIPv6Cmd = &cobra.Command{
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
} }
s.BootConfig = dhcp6.MakeStaticBootConfiguration(httpBootUrl, ipxeUrl, preference, cmd.Flags().Changed("preference")) dnsServers, err := cmd.Flags().GetString("dns-servers")
if err != nil {
fatalf("Error reading flag: %s", err)
}
dnsServerAddresses := make([]net.IP, 0)
if cmd.Flags().Changed("dns-servers") {
for _, dnsServerAddress := range strings.Split(dnsServers, ",") {
dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress))
}
}
s.BootConfig = dhcp6.MakeStaticBootConfiguration(httpBootUrl, ipxeUrl, preference,
cmd.Flags().Changed("preference"), dnsServerAddresses)
addressPoolStart, err := cmd.Flags().GetString("address-pool-start") addressPoolStart, err := cmd.Flags().GetString("address-pool-start")
if err != nil { if err != nil {
@ -80,6 +93,7 @@ func serverv6ConfigFlags(cmd *cobra.Command) {
cmd.Flags().StringP("address-pool-start", "", "2001:db8:f00f:cafe:ffff::100", "Starting ip of the address pool, e.g. 2001:db8:f00f:cafe:ffff::100") cmd.Flags().StringP("address-pool-start", "", "2001:db8:f00f:cafe:ffff::100", "Starting ip of the address pool, e.g. 2001:db8:f00f:cafe:ffff::100")
cmd.Flags().Uint64("address-pool-size", 50, "Address pool size") cmd.Flags().Uint64("address-pool-size", 50, "Address pool size")
cmd.Flags().Uint32("address-pool-lifetime", 1850, "Address pool ip valid lifetime in seconds") cmd.Flags().Uint32("address-pool-lifetime", 1850, "Address pool ip valid lifetime in seconds")
cmd.Flags().StringP("dns-servers", "", "", "Comma separated list of one or more dns server addresses")
} }
func init() { func init() {

View File

@ -7,8 +7,11 @@ import (
"go.universe.tf/netboot/dhcp6" "go.universe.tf/netboot/dhcp6"
"time" "time"
"net" "net"
"strings"
) )
// pixiecore ipv6api --listen-addr=2001:db8:f00f:cafe::4 --api-request-url=http://[2001:db8:f00f:cafe::4]:8888
var ipv6ApiCmd = &cobra.Command{ var ipv6ApiCmd = &cobra.Command{
Use: "ipv6api", Use: "ipv6api",
Short: "Boot a kernel and optional init ramdisks over IPv6 using api", Short: "Boot a kernel and optional init ramdisks over IPv6 using api",
@ -46,7 +49,18 @@ var ipv6ApiCmd = &cobra.Command{
if err != nil { if err != nil {
fatalf("Error reading flag: %s", err) fatalf("Error reading flag: %s", err)
} }
s.BootConfig = dhcp6.MakeApiBootConfiguration(apiUrl, apiTimeout, preference, cmd.Flags().Changed("preference")) dnsServers, err := cmd.Flags().GetString("dns-servers")
if err != nil {
fatalf("Error reading flag: %s", err)
}
dnsServerAddresses := make([]net.IP, 0)
if cmd.Flags().Changed("dns-servers") {
for _, dnsServerAddress := range strings.Split(dnsServers, ",") {
dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress))
}
}
s.BootConfig = dhcp6.MakeApiBootConfiguration(apiUrl, apiTimeout, preference,
cmd.Flags().Changed("preference"), dnsServerAddresses)
addressPoolStart, err := cmd.Flags().GetString("address-pool-start") addressPoolStart, err := cmd.Flags().GetString("address-pool-start")
if err != nil { if err != nil {
@ -76,6 +90,7 @@ func serverv6ApiConfigFlags(cmd *cobra.Command) {
cmd.Flags().StringP("address-pool-start", "", "2001:db8:f00f:cafe:ffff::100", "Starting ip of the address pool, e.g. 2001:db8:f00f:cafe:ffff::100") cmd.Flags().StringP("address-pool-start", "", "2001:db8:f00f:cafe:ffff::100", "Starting ip of the address pool, e.g. 2001:db8:f00f:cafe:ffff::100")
cmd.Flags().Uint64("address-pool-size", 50, "Address pool size") cmd.Flags().Uint64("address-pool-size", 50, "Address pool size")
cmd.Flags().Uint32("address-pool-lifetime", 1850, "Address pool ip address valid lifetime in seconds") cmd.Flags().Uint32("address-pool-lifetime", 1850, "Address pool ip address valid lifetime in seconds")
cmd.Flags().StringP("dns-servers", "", "", "Comma separated list of one or more dns server addresses")
} }
func init() { func init() {