| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package dhcp
- import (
- "encoding/binary"
- "net"
- "strings"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- )
- // DHCPv6 https://datatracker.ietf.org/doc/html/rfc8415
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | msg-type | transaction-id |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- . options .
- . (variable number and length) .
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | msg-type | hop-count | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
- | |
- | link-address |
- | |
- | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
- | | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
- | |
- | peer-address |
- | |
- | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
- | | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
- . .
- . options (variable number and length) .... .
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- // DHCPv6 Message Type
- const (
- DHCPV6_SOLICIT MessageType = 1
- DHCPV6_ADVERTISE MessageType = 2
- DHCPV6_REQUEST MessageType = 3
- DHCPV6_CONFIRM MessageType = 4
- DHCPV6_RENEW MessageType = 5
- DHCPV6_REBIND MessageType = 6
- DHCPV6_REPLY MessageType = 7
- DHCPV6_RELEASE MessageType = 8
- DHCPV6_DECLINE MessageType = 9
- DHCPV6_RECONFIGURE MessageType = 10
- DHCPV6_INFORMATION_REQUEST MessageType = 11
- DHCPV6_RELAY_FORW MessageType = 12
- DHCPV6_RELAY_REPL MessageType = 13
- )
- type OptionCode6 uint16
- const (
- DHCPV6_OPTION_CLIENTID OptionCode6 = 1
- DHCPV6_OPTION_SERVERID OptionCode6 = 2
- DHCPV6_OPTION_IA_NA OptionCode6 = 3
- DHCPV6_OPTION_IA_TA OptionCode6 = 4
- DHCPV6_OPTION_IAADDR OptionCode6 = 5
- DHCPV6_OPTION_ORO OptionCode6 = 6
- DHCPV6_OPTION_PREFERENCE OptionCode6 = 7
- DHCPV6_OPTION_ELAPSED_TIME OptionCode6 = 8
- DHCPV6_OPTION_RELAY_MSG OptionCode6 = 9
- DHCPV6_OPTION_AUTH OptionCode6 = 11
- DHCPV6_OPTION_UNICAST OptionCode6 = 12
- DHCPV6_OPTION_STATUS_CODE OptionCode6 = 13
- DHCPV6_OPTION_RAPID_COMMIT OptionCode6 = 14
- DHCPV6_OPTION_USER_CLASS OptionCode6 = 15
- DHCPV6_OPTION_VENDOR_CLASS OptionCode6 = 16
- DHCPV6_OPTION_VENDOR_OPTS OptionCode6 = 17
- DHCPV6_OPTION_INTERFACE_ID OptionCode6 = 18
- DHCPV6_OPTION_RECONF_MSG OptionCode6 = 19
- DHCPV6_OPTION_RECONF_ACCEPT OptionCode6 = 20
- DHCPV6_OPTION_IA_PD OptionCode6 = 25
- DHCPV6_OPTION_IAPREFIX OptionCode6 = 26
- DHCPV6_OPTION_INFORMATION_REFRESH_TIME OptionCode6 = 32
- DHCPV6_OPTION_SOL_MAX_RT OptionCode6 = 82
- DHCPV6_OPTION_INF_MAX_RT OptionCode6 = 83
- // https://www.rfc-editor.org/rfc/rfc3646
- OPTION_DNS_SERVERS OptionCode6 = 23
- OPTION_DOMAIN_LIST OptionCode6 = 24
- // https://www.rfc-editor.org/rfc/rfc4075
- OPTION_SNTP_SERVERS OptionCode6 = 31
- //https://www.rfc-editor.org/rfc/rfc5908
- OPTION_NTP_SERVERS6 OptionCode6 = 56
- // https://www.rfc-editor.org/rfc/rfc4833
- OPTION_NEW_POSIX_TIMEZONE OptionCode6 = 41
- OPTION_NEW_TZDB_TIMEZONE OptionCode6 = 42
- )
- func (opt OptionCode6) String() string {
- switch opt {
- case DHCPV6_OPTION_CLIENTID:
- return "DHCPV6_OPTION_CLIENTID"
- case DHCPV6_OPTION_SERVERID:
- return "DHCPV6_OPTION_SERVERID"
- case DHCPV6_OPTION_IA_NA:
- return "DHCPV6_OPTION_IA_NA"
- case DHCPV6_OPTION_IA_TA:
- return "DHCPV6_OPTION_IA_TA"
- case DHCPV6_OPTION_IAADDR:
- return "DHCPV6_OPTION_IAADDR"
- case DHCPV6_OPTION_ORO:
- return "DHCPV6_OPTION_ORO"
- case DHCPV6_OPTION_PREFERENCE:
- return "DHCPV6_OPTION_PREFERENCE"
- case DHCPV6_OPTION_ELAPSED_TIME:
- return "DHCPV6_OPTION_ELAPSED_TIME"
- case DHCPV6_OPTION_RELAY_MSG:
- return "DHCPV6_OPTION_RELAY_MSG"
- case DHCPV6_OPTION_AUTH:
- return "DHCPV6_OPTION_AUTH"
- case DHCPV6_OPTION_UNICAST:
- return "DHCPV6_OPTION_UNICAST"
- case DHCPV6_OPTION_STATUS_CODE:
- return "DHCPV6_OPTION_STATUS_CODE"
- case DHCPV6_OPTION_RAPID_COMMIT:
- return "DHCPV6_OPTION_RAPID_COMMIT"
- case DHCPV6_OPTION_USER_CLASS:
- return "DHCPV6_OPTION_USER_CLASS"
- case DHCPV6_OPTION_VENDOR_CLASS:
- return "DHCPV6_OPTION_VENDOR_CLASS"
- case DHCPV6_OPTION_VENDOR_OPTS:
- return "DHCPV6_OPTION_VENDOR_OPTS"
- case DHCPV6_OPTION_INTERFACE_ID:
- return "DHCPV6_OPTION_INTERFACE_ID"
- case DHCPV6_OPTION_RECONF_MSG:
- return "DHCPV6_OPTION_RECONF_MSG"
- case DHCPV6_OPTION_RECONF_ACCEPT:
- return "DHCPV6_OPTION_RECONF_ACCEPT"
- case DHCPV6_OPTION_IA_PD:
- return "DHCPV6_OPTION_IA_PD"
- case DHCPV6_OPTION_IAPREFIX:
- return "DHCPV6_OPTION_IAPREFIX"
- case DHCPV6_OPTION_INFORMATION_REFRESH_TIME:
- return "DHCPV6_OPTION_INFORMATION_REFRESH_TIME"
- case DHCPV6_OPTION_SOL_MAX_RT:
- return "DHCPV6_OPTION_SOL_MAX_RT"
- case DHCPV6_OPTION_INF_MAX_RT:
- return "DHCPV6_OPTION_INF_MAX_RT"
- case OPTION_DNS_SERVERS:
- return "OPTION_DNS_SERVERS"
- case OPTION_DOMAIN_LIST:
- return "OPTION_DOMAIN_LIST"
- case OPTION_SNTP_SERVERS:
- return "OPTION_SNTP_SERVERS"
- case OPTION_NTP_SERVERS6:
- return "OPTION_NTP_SERVERS6"
- case OPTION_NEW_POSIX_TIMEZONE:
- return "OPTION_NEW_POSIX_TIMEZONE"
- case OPTION_NEW_TZDB_TIMEZONE:
- return "OPTION_NEW_TZDB_TIMEZONE"
- }
- return "DHCPV6_OPTION_UNKNOWN"
- }
- // DHCPv6 message type
- func (p Packet) Type6() MessageType {
- return MessageType(p[0])
- }
- // DHCPv6 transaction ID
- func (p Packet) TID6() (uint32, error) {
- if !p.IsRelayMsg() {
- if len(p) < 4 {
- return 0, errors.Wrapf(errors.ErrInvalidFormat, "packet too short")
- }
- return binary.BigEndian.Uint32([]byte{0, p[1], p[2], p[3]}), nil
- }
- options := p.GetOption6s()
- for _, o := range options {
- if o.Code == DHCPV6_OPTION_RELAY_MSG {
- return Packet(o.Value).TID6()
- }
- }
- return 0, errors.Wrapf(errors.ErrInvalidFormat, "not a valid relay message")
- }
- func (p Packet) ClientID() ([]byte, error) {
- if !p.IsRelayMsg() {
- options := p.GetOption6s()
- for _, o := range options {
- if o.Code == DHCPV6_OPTION_CLIENTID {
- return o.Value, nil
- }
- }
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "clientID option not found")
- }
- options := p.GetOption6s()
- for _, o := range options {
- if o.Code == DHCPV6_OPTION_RELAY_MSG {
- return Packet(o.Value).ClientID()
- }
- }
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "not a valid relay message")
- }
- // DHCPv6 hop Count for relay message
- func (p Packet) HopCount() byte {
- return p[1]
- }
- // DHCPv6 link address for relay message
- func (p Packet) LinkAddr() net.IP {
- return net.IP(p[2:18])
- }
- // DHCPv6 peer address for relay message
- func (p Packet) PeerAddr() net.IP {
- return net.IP(p[18:34])
- }
- func (p Packet) IsRelayMsg() bool {
- return p.Type6() == DHCPV6_RELAY_FORW || p.Type6() == DHCPV6_RELAY_REPL
- }
- func (p *Packet) SetType6(hType MessageType) {
- (*p)[0] = byte(hType)
- }
- func (p *Packet) SetTID(tid uint32) {
- tidBytes := make([]byte, 4)
- binary.BigEndian.PutUint32(tidBytes, tid)
- (*p)[1] = tidBytes[1]
- (*p)[2] = tidBytes[2]
- (*p)[3] = tidBytes[3]
- }
- func (p *Packet) SetHopCount(hops byte) {
- (*p)[1] = hops
- }
- func (p *Packet) SetLinkAddr(linkAddr net.IP) {
- copy((*p)[2:18], linkAddr)
- }
- func (p *Packet) SetPeerAddr(peerAddr net.IP) {
- copy((*p)[18:34], peerAddr)
- }
- func NewPacket6(opCode MessageType, tid uint32) Packet {
- p := make(Packet, 4)
- p.SetType6(opCode)
- p.SetTID(tid)
- return p
- }
- func NewRelayPacket6() Packet {
- p := make(Packet, 34)
- p.SetType6(DHCPV6_RELAY_FORW)
- return p
- }
- type Option6 struct {
- Code OptionCode6
- Value []byte
- }
- // Appends a DHCP option to the end of a packet
- /*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | option-code | option-len |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | option-data |
- | (option-len octets) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- func optionToBytes(o Option6) []byte {
- buf := make([]byte, 4+len(o.Value))
- binary.BigEndian.PutUint16(buf[0:2], uint16(o.Code))
- binary.BigEndian.PutUint16(buf[2:4], uint16(len(o.Value)))
- copy(buf[4:], o.Value)
- return buf
- }
- func optionsToBytes(opts []Option6) []byte {
- buf := make([]byte, 0)
- for i := range opts {
- buf = append(buf, optionToBytes(opts[i])...)
- }
- return buf
- }
- func (p Packet) GetOption6s() []Option6 {
- offset := 4
- if p.IsRelayMsg() {
- offset = 16*2 + 2
- }
- return decodeDHCP6Options(p, offset)
- }
- func decodeDHCP6Options(p []byte, offset int) []Option6 {
- options := make([]Option6, 0)
- i := offset
- for i < len(p) {
- code := binary.BigEndian.Uint16(p[i : i+2])
- length := binary.BigEndian.Uint16(p[i+2 : i+4])
- value := make([]byte, length)
- copy(value, p[i+4:i+4+int(length)])
- options = append(options, Option6{
- Code: OptionCode6(code),
- Value: value,
- })
- i += 4 + int(length)
- }
- return options
- }
- func MakeDHCP6Reply(pkt Packet, conf *ResponseConfig) (Packet, error) {
- var msgType MessageType
- pktType := pkt.Type6()
- switch pktType {
- case DHCPV6_SOLICIT:
- msgType = DHCPV6_ADVERTISE
- case DHCPV6_REQUEST:
- msgType = DHCPV6_REPLY
- case DHCPV6_CONFIRM:
- msgType = DHCPV6_REPLY
- case DHCPV6_RENEW:
- msgType = DHCPV6_REPLY
- case DHCPV6_REBIND:
- msgType = DHCPV6_REPLY
- case DHCPV6_INFORMATION_REQUEST:
- msgType = DHCPV6_REPLY
- default:
- return nil, errors.Wrapf(errors.ErrNotSupported, "unsupported message type %d", pktType)
- }
- return makeDHCPReplyPacket6(pkt, conf, msgType)
- }
- const (
- DUID_TYPE_LINK_LAYER_ADDRESS = 3
- DUID_HARDWARE_TYPE_ETHERNET = 1
- )
- func makeServerId(serverMac net.HardwareAddr) []byte {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], uint16(DUID_TYPE_LINK_LAYER_ADDRESS))
- binary.BigEndian.PutUint16(buf[2:4], uint16(DUID_HARDWARE_TYPE_ETHERNET))
- buf = append(buf, serverMac[:6]...)
- return buf
- }
- func makeIAAddr(ip net.IP, preferLT, validLT uint32, opts []Option6) []byte {
- buf := make([]byte, 24)
- copy(buf[0:16], ip.To16())
- binary.BigEndian.PutUint32(buf[16:20], preferLT)
- binary.BigEndian.PutUint32(buf[20:24], validLT)
- buf = append(buf, optionsToBytes(opts)...)
- return buf
- }
- func decodeIAAddr(buf []byte) (net.IP, uint32, uint32, []Option6) {
- ipBuf := make([]byte, 16)
- copy(ipBuf, buf[0:16])
- ip := net.IP(ipBuf)
- preferLT := binary.BigEndian.Uint32(buf[16:20])
- validLT := binary.BigEndian.Uint32(buf[20:24])
- opts := decodeDHCP6Options(buf, 24)
- return ip, preferLT, validLT, opts
- }
- /*
- +---------------+------+--------------------------------------------+
- | Name | Code | Description |
- +---------------+------+--------------------------------------------+
- | Success | 0 | Success. |
- | | | |
- | UnspecFail | 1 | Failure, reason unspecified; this status |
- | | | code is sent by either a client or a |
- | | | server to indicate a failure not |
- | | | explicitly specified in this document. |
- | | | |
- | NoAddrsAvail | 2 | The server has no addresses available to |
- | | | assign to the IA(s). |
- | | | |
- | NoBinding | 3 | Client record (binding) unavailable. |
- | | | |
- | NotOnLink | 4 | The prefix for the address is not |
- | | | appropriate for the link to which the |
- | | | client is attached. |
- | | | |
- | UseMulticast | 5 | Sent by a server to a client to force the |
- | | | client to send messages to the server |
- | | | using the |
- | | | All_DHCP_Relay_Agents_and_Servers |
- | | | multicast address. |
- | | | |
- | NoPrefixAvail | 6 | The server has no prefixes available to |
- | | | assign to the IA_PD(s). |
- +---------------+------+--------------------------------------------+
- */
- type DHCP6StatusCode uint16
- const (
- Dhcp6StatusSuccess DHCP6StatusCode = 0
- Dhcp6StatusUnspecFail DHCP6StatusCode = 1
- Dhcp6StatusNoAddrsAvail DHCP6StatusCode = 2
- Dhcp6StatusNoBinding DHCP6StatusCode = 3
- Dhcp6StatusNotOnLink DHCP6StatusCode = 4
- Dhcp6StatusUseMulticast DHCP6StatusCode = 5
- Dhcp6StatusNoPrefixAvail DHCP6StatusCode = 6
- )
- func (code DHCP6StatusCode) Encode() []byte {
- var msg string
- switch code {
- case Dhcp6StatusSuccess:
- msg = "Success"
- case Dhcp6StatusUnspecFail:
- msg = "UnspecFail"
- case Dhcp6StatusNoAddrsAvail:
- msg = "NoAddrsAvail"
- case Dhcp6StatusNoBinding:
- msg = "NoBinding"
- case Dhcp6StatusNotOnLink:
- msg = "NotOnLink"
- case Dhcp6StatusUseMulticast:
- msg = "UseMulticast"
- case Dhcp6StatusNoPrefixAvail:
- msg = "NoPrefixAvail"
- }
- buf := make([]byte, 2)
- binary.BigEndian.PutUint16(buf, uint16(code))
- buf = append(buf, []byte(msg)...)
- return buf
- }
- func responseIANA(buf []byte, ip net.IP, preferLT, validLT uint32) ([]byte, DHCP6StatusCode) {
- // IA_NA structure: IAID (4 bytes) + T1 (4 bytes) + T2 (4 bytes)
- // Preserve the original IAID, T1, and T2 values from the client request
- opts := make([]Option6, 0)
- status := Dhcp6StatusSuccess
- resp := make([]byte, 12)
- if len(buf) < 12 {
- copy(resp, buf)
- // If buffer is too short, pad with zeros
- // padding := make([]byte, 12-len(buf))
- // copy(resp[len(buf):], padding)
- } else {
- // Log the IA_NA parameters for debugging
- iaID := binary.BigEndian.Uint32(buf[0:4])
- t1 := binary.BigEndian.Uint32(buf[4:8])
- t2 := binary.BigEndian.Uint32(buf[8:12])
- log.Debugf("responseIANA IA_NA IAID %d t1 %d t2 %d", iaID, t1, t2)
- if len(buf) > 12 {
- iaOpts := decodeDHCP6Options(buf, 12)
- for i := range iaOpts {
- if iaOpts[i].Code == DHCPV6_OPTION_IAADDR {
- oldIp, oldPreferLT, oldValidLT, _ := decodeIAAddr(iaOpts[i].Value)
- if !oldIp.Equal(ip) {
- // send NotOnLink
- opts = append(opts, Option6{
- Code: DHCPV6_OPTION_IAADDR,
- Value: makeIAAddr(oldIp, oldPreferLT, oldValidLT, []Option6{
- {
- Code: DHCPV6_OPTION_STATUS_CODE,
- Value: Dhcp6StatusNotOnLink.Encode(),
- },
- }),
- })
- if status == Dhcp6StatusSuccess {
- status = Dhcp6StatusNotOnLink
- }
- }
- }
- }
- }
- copy(resp, buf[:12])
- }
- opts = append(opts, Option6{
- Code: DHCPV6_OPTION_IAADDR,
- Value: makeIAAddr(ip, preferLT, validLT, []Option6{
- {
- Code: DHCPV6_OPTION_STATUS_CODE,
- Value: Dhcp6StatusSuccess.Encode(),
- },
- }),
- })
- resp = append(resp, optionsToBytes(opts)...)
- return resp, status
- }
- func makeIPv6s(ips []net.IP) []byte {
- buf := make([]byte, 0)
- for _, ip := range ips {
- ip6 := ip.To16()
- if ip6 == nil {
- continue
- }
- buf = append(buf, ip6...)
- }
- return buf
- }
- func decodeRequestOptions(value []byte) []OptionCode6 {
- var optCodes []OptionCode6
- for i := 0; i < len(value); i += 2 {
- optCodes = append(optCodes, OptionCode6(binary.BigEndian.Uint16(value[i:i+2])))
- }
- return optCodes
- }
- func makeDHCPReplyPacket6(pkt Packet, conf *ResponseConfig, msgType MessageType) (Packet, error) {
- tid, err := pkt.TID6()
- if err != nil {
- return nil, errors.Wrapf(err, "TID6")
- }
- originOpts := pkt.GetOption6s()
- getOption := func(opts []Option6, code OptionCode6) *Option6 {
- for _, o := range opts {
- if o.Code == code {
- return &o
- }
- }
- return nil
- }
- reqInfo := getOption(originOpts, DHCPV6_OPTION_ORO)
- if reqInfo != nil && len(reqInfo.Value) > 0 {
- reqOpts := decodeRequestOptions(reqInfo.Value)
- reqOptsStr := make([]string, len(reqOpts))
- for i, opt := range reqOpts {
- reqOptsStr[i] = opt.String()
- }
- log.Debugf("request options: %s", strings.Join(reqOptsStr, ","))
- }
- options := make([]Option6, 0)
- reqCliID := getOption(originOpts, DHCPV6_OPTION_CLIENTID)
- if reqCliID == nil {
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "clientID option not found")
- }
- // copy clientID
- options = append(options, Option6{
- Code: DHCPV6_OPTION_CLIENTID,
- Value: reqCliID.Value,
- })
- // serverID
- options = append(options, Option6{
- Code: DHCPV6_OPTION_SERVERID,
- Value: makeServerId(conf.InterfaceMac),
- })
- // Identity Association for Non-temporary Addresses Option
- ianaOpt := getOption(originOpts, DHCPV6_OPTION_IA_NA)
- if ianaOpt == nil {
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "IA_NA option not found")
- }
- // Calculate proper timing values for IA_NA
- validLifetime := uint32(conf.LeaseTime.Seconds()) // Valid lifetime should be longer than preferred
- preferredLifetime := validLifetime / 2
- ianaResp, status := responseIANA(ianaOpt.Value, conf.ClientIP6, preferredLifetime, validLifetime)
- options = append(options, Option6{
- Code: DHCPV6_OPTION_IA_NA,
- Value: ianaResp,
- })
- if len(conf.DNSServers6) > 0 {
- options = append(options, Option6{
- Code: OPTION_DNS_SERVERS,
- Value: makeIPv6s(conf.DNSServers6),
- })
- }
- if len(conf.NTPServers6) > 0 {
- options = append(options, Option6{
- Code: OPTION_SNTP_SERVERS,
- Value: makeIPv6s(conf.NTPServers6),
- })
- }
- // Handle rapid commit option for SOLICIT messages
- if pkt.Type6() == DHCPV6_SOLICIT {
- rapidCmtOpt := getOption(originOpts, DHCPV6_OPTION_RAPID_COMMIT)
- if rapidCmtOpt != nil {
- // Client requested rapid commit, respond with REPLY instead of ADVERTISE
- msgType = DHCPV6_REPLY
- options = append(options, Option6{
- Code: DHCPV6_OPTION_RAPID_COMMIT,
- })
- }
- }
- options = append(options, Option6{
- Code: DHCPV6_OPTION_STATUS_CODE,
- Value: status.Encode(),
- })
- resp := NewPacket6(msgType, tid)
- resp = append(resp, optionsToBytes(options)...)
- return resp, nil
- }
- func EncapDHCP6RelayMsg(pkt Packet) Packet {
- relayMsg := NewRelayPacket6()
- relayOpt := Option6{
- Code: DHCPV6_OPTION_RELAY_MSG,
- Value: pkt,
- }
- relayMsg = append(relayMsg, optionsToBytes([]Option6{relayOpt})...)
- return relayMsg
- }
- func DecapDHCP6RelayMsg(pkt Packet) (Packet, error) {
- options := pkt.GetOption6s()
- for _, o := range options {
- if o.Code == DHCPV6_OPTION_RELAY_MSG {
- return Packet(o.Value), nil
- }
- }
- return nil, errors.Wrapf(errors.ErrInvalidFormat, "relay message not found")
- }
|