summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6
diff options
context:
space:
mode:
authorAndrea Barberio <insomniac@slackware.it>2017-12-06 20:29:55 +0000
committerAndrea Barberio <insomniac@slackware.it>2017-12-06 20:29:55 +0000
commit3874bd73f93d2abdfba04aa5821d62c37acd1f2f (patch)
treebbed5dd3ec2aaa5ebb28e076bc387487f39e4c6f /dhcpv6
parent70a90992790d76f3a5d27fbbef985cdf1ef46a80 (diff)
Added support for DHCP relay and refactored into multiple files
Diffstat (limited to 'dhcpv6')
-rw-r--r--dhcpv6/dhcpv6.go197
-rw-r--r--dhcpv6/dhcpv6message.go180
-rw-r--r--dhcpv6/dhcpv6relay.go50
-rw-r--r--dhcpv6/types.go9
4 files changed, 247 insertions, 189 deletions
diff --git a/dhcpv6/dhcpv6.go b/dhcpv6/dhcpv6.go
index dcd1ff0..7667821 100644
--- a/dhcpv6/dhcpv6.go
+++ b/dhcpv6/dhcpv6.go
@@ -1,76 +1,16 @@
package dhcpv6
import (
- "crypto/rand"
- "encoding/binary"
"fmt"
"github.com/insomniacslk/dhcp/dhcpv6/options"
- "github.com/insomniacslk/dhcp/iana"
- "log"
- "net"
- "time"
)
-const MessageHeaderSize = 4
-const RelayMessageHeaderSize = 34
-
type DHCPv6 interface {
Type() MessageType
ToBytes() []byte
Summary() string
}
-type DHCPv6Message struct {
- messageType MessageType
- transactionID uint32 // only 24 bits are used though
- options []options.Option
-}
-
-type DHCPv6RelayMessage struct {
- messageType MessageType
- hopCount uint8
- linkAddr net.IP
- peerAddr net.IP
-}
-
-func BytesToTransactionID(data []byte) (*uint32, error) {
- // return a uint32 from a sequence of bytes, representing a transaction ID.
- // Transaction IDs are three-bytes long. If the provided data is shorter than
- // 3 bytes, it return an error. If longer, will use the first three bytes
- // only.
- if len(data) < 3 {
- return nil, fmt.Errorf("Invalid transaction ID: less than 3 bytes")
- }
- buf := make([]byte, 4)
- copy(buf[1:4], data[:3])
- tid := binary.BigEndian.Uint32(buf)
- return &tid, nil
-}
-
-func GenerateTransactionID() (*uint32, error) {
- var tid *uint32
- for {
- tidBytes := make([]byte, 4)
- n, err := rand.Read(tidBytes)
- if n != 4 {
- return nil, fmt.Errorf("Invalid random sequence: shorter than 4 bytes")
- }
- tid, err = BytesToTransactionID(tidBytes)
- if err != nil {
- return nil, err
- }
- if tid == nil {
- return nil, fmt.Errorf("Error: got a nil Transaction ID")
- }
- // retry until != 0
- // TODO add retry limit
- if *tid != 0 {
- break
- }
- }
- return tid, nil
-}
-
func FromBytes(data []byte) (DHCPv6, error) {
var (
isRelay = false
@@ -81,7 +21,7 @@ func FromBytes(data []byte) (DHCPv6, error) {
isRelay = true
}
if isRelay {
- headerSize = RelayMessageHeaderSize
+ headerSize = RelayHeaderSize
} else {
headerSize = MessageHeaderSize
}
@@ -89,14 +29,20 @@ func FromBytes(data []byte) (DHCPv6, error) {
return nil, fmt.Errorf("Invalid header size: shorter than %v bytes", headerSize)
}
if isRelay {
- return nil, fmt.Errorf("Relay messages not implemented yet")
+ d := DHCPv6Relay{
+ messageType: messageType,
+ hopCount: uint8(data[1]),
+ linkAddr: append(data[2:18]),
+ peerAddr: append(data[18:34]),
+ }
+ return &d, nil
} else {
tid, err := BytesToTransactionID(data[1:4])
if err != nil {
return nil, err
}
d := DHCPv6Message{
- messageType: MessageType(data[0]),
+ messageType: messageType,
transactionID: *tid,
}
options, err := options.FromBytes(data[4:])
@@ -119,128 +65,3 @@ func NewMessage() (*DHCPv6Message, error) {
}
return &d, nil
}
-
-// Return a time integer suitable for DUID-LLT, i.e. the current time counted in
-// seconds since January 1st, 2000, midnight UTC, modulo 2^32
-func GetTime() uint32 {
- now := time.Since(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))
- return uint32((now.Nanoseconds() / 1000000000) % 0xffffffff)
-}
-
-// Create a new SOLICIT message with DUID-LLT, using the given network
-// interface's hardware address and current time
-func NewSolicitForInterface(ifname string) (*DHCPv6Message, error) {
- d, err := NewMessage()
- if err != nil {
- return nil, err
- }
- d.SetMessage(SOLICIT)
- iface, err := net.InterfaceByName(ifname)
- if err != nil {
- return nil, err
- }
- cid := options.OptClientId{}
- cid.SetClientID(options.Duid{
- Type: options.DUID_LLT,
- HwType: iana.HwTypeEthernet,
- Time: GetTime(),
- LinkLayerAddr: iface.HardwareAddr,
- })
-
- d.AddOption(&cid)
- oro := options.OptRequestedOption{}
- oro.SetRequestedOptions([]options.OptionCode{
- options.DNS_RECURSIVE_NAME_SERVER,
- options.DOMAIN_SEARCH_LIST,
- })
- d.AddOption(&oro)
- d.AddOption(&options.OptElapsedTime{})
- // FIXME use real values for IA_NA
- iaNa := options.OptIANA{}
- iaNa.SetIAID([4]byte{0x27, 0xfe, 0x8f, 0x95})
- iaNa.SetT1(0xe10)
- iaNa.SetT2(0x1518)
- d.AddOption(&iaNa)
- return d, nil
-}
-
-func (d *DHCPv6Message) Type() MessageType {
- return d.messageType
-}
-
-func (d *DHCPv6Message) SetMessage(messageType MessageType) {
- if MessageToString[messageType] == "" {
- log.Printf("Warning: unknown DHCPv6 message type: %v", messageType)
- }
- d.messageType = messageType
-}
-
-func (d *DHCPv6Message) MessageToString() string {
- if m := MessageToString[d.messageType]; m != "" {
- return m
- }
- return "Invalid"
-}
-
-func (d *DHCPv6Message) TransactionID() uint32 {
- return d.transactionID
-}
-
-func (d *DHCPv6Message) SetTransactionID(tid uint32) {
- ttid := tid & 0x00ffffff
- if ttid != tid {
- log.Printf("Warning: truncating transaction ID that is longer than 24 bits: %v", tid)
- }
- d.transactionID = ttid
-}
-
-func (d *DHCPv6Message) Options() []options.Option {
- return d.options
-}
-
-func (d *DHCPv6Message) SetOptions(options []options.Option) {
- d.options = options
-}
-
-func (d *DHCPv6Message) AddOption(option options.Option) {
- d.options = append(d.options, option)
-}
-
-func (d *DHCPv6Message) String() string {
- return fmt.Sprintf("DHCPv6Message(messageType=%v transactionID=0x%06x, %d options)",
- d.MessageToString(), d.TransactionID(), len(d.options),
- )
-}
-
-func (d *DHCPv6Message) Summary() string {
- ret := fmt.Sprintf(
- "DHCPv6Message\n"+
- " messageType=%v\n"+
- " transactionid=0x%06x\n",
- d.MessageToString(),
- d.TransactionID(),
- )
- ret += " options=["
- if len(d.options) > 0 {
- ret += "\n"
- }
- for _, opt := range d.options {
- ret += fmt.Sprintf(" %v\n", opt.String())
- }
- ret += " ]\n"
- return ret
-}
-
-// Convert a DHCPv6Message structure into its binary representation, suitable for being
-// sent over the network
-func (d *DHCPv6Message) ToBytes() []byte {
- var ret []byte
- ret = append(ret, byte(d.messageType))
- tidBytes := make([]byte, 4)
- binary.BigEndian.PutUint32(tidBytes, d.transactionID)
- ret = append(ret, tidBytes[1:4]...) // discard the first byte
- for _, opt := range d.options {
- ret = append(ret, opt.ToBytes()...)
- }
- return ret
-}
diff --git a/dhcpv6/dhcpv6message.go b/dhcpv6/dhcpv6message.go
new file mode 100644
index 0000000..4461c50
--- /dev/null
+++ b/dhcpv6/dhcpv6message.go
@@ -0,0 +1,180 @@
+package dhcpv6
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+ "github.com/insomniacslk/dhcp/dhcpv6/options"
+ "github.com/insomniacslk/dhcp/iana"
+ "log"
+ "net"
+ "time"
+)
+
+const MessageHeaderSize = 4
+
+type DHCPv6Message struct {
+ messageType MessageType
+ transactionID uint32 // only 24 bits are used though
+ options []options.Option
+}
+
+func BytesToTransactionID(data []byte) (*uint32, error) {
+ // return a uint32 from a sequence of bytes, representing a transaction ID.
+ // Transaction IDs are three-bytes long. If the provided data is shorter than
+ // 3 bytes, it return an error. If longer, will use the first three bytes
+ // only.
+ if len(data) < 3 {
+ return nil, fmt.Errorf("Invalid transaction ID: less than 3 bytes")
+ }
+ buf := make([]byte, 4)
+ copy(buf[1:4], data[:3])
+ tid := binary.BigEndian.Uint32(buf)
+ return &tid, nil
+}
+
+func GenerateTransactionID() (*uint32, error) {
+ var tid *uint32
+ for {
+ tidBytes := make([]byte, 4)
+ n, err := rand.Read(tidBytes)
+ if n != 4 {
+ return nil, fmt.Errorf("Invalid random sequence: shorter than 4 bytes")
+ }
+ tid, err = BytesToTransactionID(tidBytes)
+ if err != nil {
+ return nil, err
+ }
+ if tid == nil {
+ return nil, fmt.Errorf("Error: got a nil Transaction ID")
+ }
+ // retry until != 0
+ // TODO add retry limit
+ if *tid != 0 {
+ break
+ }
+ }
+ return tid, nil
+}
+
+// Return a time integer suitable for DUID-LLT, i.e. the current time counted in
+// seconds since January 1st, 2000, midnight UTC, modulo 2^32
+func GetTime() uint32 {
+ now := time.Since(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))
+ return uint32((now.Nanoseconds() / 1000000000) % 0xffffffff)
+}
+
+// Create a new SOLICIT message with DUID-LLT, using the given network
+// interface's hardware address and current time
+func NewSolicitForInterface(ifname string) (*DHCPv6Message, error) {
+ d, err := NewMessage()
+ if err != nil {
+ return nil, err
+ }
+ d.SetMessage(SOLICIT)
+ iface, err := net.InterfaceByName(ifname)
+ if err != nil {
+ return nil, err
+ }
+ cid := options.OptClientId{}
+ cid.SetClientID(options.Duid{
+ Type: options.DUID_LLT,
+ HwType: iana.HwTypeEthernet,
+ Time: GetTime(),
+ LinkLayerAddr: iface.HardwareAddr,
+ })
+
+ d.AddOption(&cid)
+ oro := options.OptRequestedOption{}
+ oro.SetRequestedOptions([]options.OptionCode{
+ options.DNS_RECURSIVE_NAME_SERVER,
+ options.DOMAIN_SEARCH_LIST,
+ })
+ d.AddOption(&oro)
+ d.AddOption(&options.OptElapsedTime{})
+ // FIXME use real values for IA_NA
+ iaNa := options.OptIANA{}
+ iaNa.SetIAID([4]byte{0x27, 0xfe, 0x8f, 0x95})
+ iaNa.SetT1(0xe10)
+ iaNa.SetT2(0x1518)
+ d.AddOption(&iaNa)
+ return d, nil
+}
+
+func (d *DHCPv6Message) Type() MessageType {
+ return d.messageType
+}
+
+func (d *DHCPv6Message) SetMessage(messageType MessageType) {
+ if d.MessageTypeToString() == "" {
+ log.Printf("Warning: unknown DHCPv6 message type: %v", messageType)
+ }
+ d.messageType = messageType
+}
+
+func (d *DHCPv6Message) MessageTypeToString() string {
+ return MessageTypeToString(d.messageType)
+}
+
+func (d *DHCPv6Message) TransactionID() uint32 {
+ return d.transactionID
+}
+
+func (d *DHCPv6Message) SetTransactionID(tid uint32) {
+ ttid := tid & 0x00ffffff
+ if ttid != tid {
+ log.Printf("Warning: truncating transaction ID that is longer than 24 bits: %v", tid)
+ }
+ d.transactionID = ttid
+}
+
+func (d *DHCPv6Message) Options() []options.Option {
+ return d.options
+}
+
+func (d *DHCPv6Message) SetOptions(options []options.Option) {
+ d.options = options
+}
+
+func (d *DHCPv6Message) AddOption(option options.Option) {
+ d.options = append(d.options, option)
+}
+
+func (d *DHCPv6Message) String() string {
+ return fmt.Sprintf("DHCPv6Message(messageType=%v transactionID=0x%06x, %d options)",
+ d.MessageTypeToString(), d.TransactionID(), len(d.options),
+ )
+}
+
+func (d *DHCPv6Message) Summary() string {
+ ret := fmt.Sprintf(
+ "DHCPv6Message\n"+
+ " messageType=%v\n"+
+ " transactionid=0x%06x\n",
+ d.MessageTypeToString(),
+ d.TransactionID(),
+ )
+ ret += " options=["
+ if len(d.options) > 0 {
+ ret += "\n"
+ }
+ for _, opt := range d.options {
+ ret += fmt.Sprintf(" %v\n", opt.String())
+ }
+ ret += " ]\n"
+ return ret
+}
+
+// Convert a DHCPv6Message structure into its binary representation, suitable for being
+// sent over the network
+func (d *DHCPv6Message) ToBytes() []byte {
+ var ret []byte
+ ret = append(ret, byte(d.messageType))
+ tidBytes := make([]byte, 4)
+ binary.BigEndian.PutUint32(tidBytes, d.transactionID)
+ ret = append(ret, tidBytes[1:4]...) // discard the first byte
+ for _, opt := range d.options {
+ ret = append(ret, opt.ToBytes()...)
+ }
+ return ret
+}
diff --git a/dhcpv6/dhcpv6relay.go b/dhcpv6/dhcpv6relay.go
new file mode 100644
index 0000000..25cf658
--- /dev/null
+++ b/dhcpv6/dhcpv6relay.go
@@ -0,0 +1,50 @@
+package dhcpv6
+
+import (
+ "fmt"
+ "net"
+)
+
+const RelayHeaderSize = 34
+
+type DHCPv6Relay struct {
+ messageType MessageType
+ hopCount uint8
+ linkAddr net.IP
+ peerAddr net.IP
+ payload []byte // TODO implement relay payload
+}
+
+func (r *DHCPv6Relay) Type() MessageType {
+ return r.messageType
+}
+
+func (r *DHCPv6Relay) MessageTypeToString() string {
+ return MessageTypeToString(r.messageType)
+}
+
+func (r *DHCPv6Relay) Summary() string {
+ ret := fmt.Sprintf(
+ "DHCPv6Relay\n"+
+ " messageType=%v\n"+
+ " hopcount=%v\n"+
+ " linkaddr=%v\n"+
+ " peeraddr=%v\n",
+ r.MessageTypeToString(),
+ r.hopCount,
+ r.linkAddr,
+ r.peerAddr,
+ )
+ return ret
+}
+
+func (r *DHCPv6Relay) ToBytes() []byte {
+ ret := make([]byte, RelayHeaderSize)
+ ret[0] = byte(r.messageType)
+ ret[1] = byte(r.hopCount)
+ copy(ret[2:18], r.peerAddr)
+ copy(ret[18:34], r.linkAddr)
+ ret = append(ret, r.payload...)
+
+ return ret
+}
diff --git a/dhcpv6/types.go b/dhcpv6/types.go
index 370243e..e0ea6f0 100644
--- a/dhcpv6/types.go
+++ b/dhcpv6/types.go
@@ -25,7 +25,14 @@ const (
LEASEQUERY_DATA
)
-var MessageToString = map[MessageType]string{
+func MessageTypeToString(t MessageType) string {
+ if m := MessageTypeToStringMap[t]; m != "" {
+ return m
+ }
+ return "Unknown"
+}
+
+var MessageTypeToStringMap = map[MessageType]string{
SOLICIT: "SOLICIT",
ADVERTISE: "ADVERTISE",
REQUEST: "REQUEST",