package dhcp import "net/netip" type Parameter interface { Code() OptionTag Len() int Bytes() []byte // the serialized parameter Valid() bool } func (packet *Packet) AddParameter(p Parameter) { packet.Parameters = append(packet.Parameters, p) } type parameterWithAddr struct { code OptionTag addr netip.Addr } func (p parameterWithAddr) Code() OptionTag { return p.code } func (p parameterWithAddr) Len() int { return len(p.addr.AsSlice()) } func (p parameterWithAddr) Bytes() []byte { return append([]byte{byte(p.code), uint8(p.Len())}, p.addr.AsSlice()...) } func (p parameterWithAddr) Valid() bool { return p.addr.Is4() && p.addr.IsValid() && !p.addr.IsUnspecified() } type parameterWithAddrs struct { code OptionTag addrs []netip.Addr } func (p parameterWithAddrs) Code() OptionTag { return p.code } func (p parameterWithAddrs) Len() int { plen := 0 for _, addr := range p.addrs { plen += len(addr.AsSlice()) } return plen } func (p parameterWithAddrs) Bytes() []byte { out := []byte{byte(p.code), byte(p.Len())} for _, addr := range p.addrs { out = append(out, addr.AsSlice()...) } return out } func (p parameterWithAddrs) Valid() bool { for _, addr := range p.addrs { if !(addr.Is4() && addr.IsValid() && !addr.IsUnspecified()) { return false } } return true } type parameterWithString struct { code OptionTag data string } func (p parameterWithString) Code() OptionTag { return p.code } func (p parameterWithString) Len() int { return len(p.data) } func (p parameterWithString) Bytes() []byte { out := []byte{byte(p.code), byte(p.Len())} return append(out, []byte(p.data)...) } func (p parameterWithString) Valid() bool { return len(p.data) > 0 } func ParameterRouter(router netip.Addr) Parameter { return ¶meterWithAddr{ code: OptionTagRouter, addr: router, } } func ParameterSubnetMask(mask netip.Addr) Parameter { return ¶meterWithAddr{ code: OptionTagSubnetMask, addr: mask, } } func ParameterDNS(dns []netip.Addr) Parameter { return ¶meterWithAddrs{ code: OptionTagDomainNameServer, addrs: dns, } } func ParameterHostName(name string) Parameter { return ¶meterWithString{ code: OptionTagHostName, data: name, } }