summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChris Koch <chrisko@google.com>2023-02-18 14:41:32 -0800
committerChris K <c@chrisko.ch>2023-02-18 23:57:24 -0800
commitb606c2152e1b91a556c42f126d5279348678682d (patch)
treea621015fb6b48c48ae4130beb49760328e15a039
parent573052511f5790667b95f4a801f7ed0680a66a83 (diff)
Recursive pretty-printing with indentation
Signed-off-by: Chris Koch <chrisko@google.com>
-rw-r--r--dhcpv6/dhcpv6.go1
-rw-r--r--dhcpv6/dhcpv6message.go38
-rw-r--r--dhcpv6/dhcpv6relay.go39
-rw-r--r--dhcpv6/option_4rd.go5
-rw-r--r--dhcpv6/option_dhcpv4_msg.go12
-rw-r--r--dhcpv6/option_iaaddress.go6
-rw-r--r--dhcpv6/option_iapd.go5
-rw-r--r--dhcpv6/option_nontemporaryaddress.go5
-rw-r--r--dhcpv6/option_relaymsg.go5
-rw-r--r--dhcpv6/option_temporaryaddress.go5
-rw-r--r--dhcpv6/option_vendor_opts.go5
-rw-r--r--dhcpv6/options.go29
12 files changed, 125 insertions, 30 deletions
diff --git a/dhcpv6/dhcpv6.go b/dhcpv6/dhcpv6.go
index 59d9733..8addba2 100644
--- a/dhcpv6/dhcpv6.go
+++ b/dhcpv6/dhcpv6.go
@@ -14,6 +14,7 @@ type DHCPv6 interface {
ToBytes() []byte
String() string
Summary() string
+ LongString(indent int) string
IsRelay() bool
// GetInnerMessage returns the innermost encapsulated DHCPv6 message.
diff --git a/dhcpv6/dhcpv6message.go b/dhcpv6/dhcpv6message.go
index e68284f..17f371a 100644
--- a/dhcpv6/dhcpv6message.go
+++ b/dhcpv6/dhcpv6message.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net"
+ "strings"
"time"
"github.com/insomniacslk/dhcp/iana"
@@ -549,22 +550,27 @@ func (m *Message) String() string {
// Summary prints all options associated with this message.
func (m *Message) Summary() string {
- ret := fmt.Sprintf(
- "Message\n"+
- " messageType=%s\n"+
- " transactionid=%s\n",
- m.MessageType,
- m.TransactionID,
- )
- ret += " options=["
- if len(m.Options.Options) > 0 {
- ret += "\n"
- }
- for _, opt := range m.Options.Options {
- ret += fmt.Sprintf(" %v\n", opt.String())
- }
- ret += " ]\n"
- return ret
+ return m.LongString(0)
+}
+
+// LongString prints all options associated with this message.
+func (m *Message) LongString(spaceIndent int) string {
+ indent := strings.Repeat(" ", spaceIndent)
+
+ var s strings.Builder
+ s.WriteString("Message{\n")
+ s.WriteString(indent)
+ s.WriteString(fmt.Sprintf(" MessageType=%s\n", m.MessageType))
+ s.WriteString(indent)
+ s.WriteString(fmt.Sprintf(" TransactionID=%s\n", m.TransactionID))
+ s.WriteString(indent)
+ s.WriteString(" Options: ")
+ s.WriteString(m.Options.Options.LongString(spaceIndent + 2))
+ s.WriteString("\n")
+ s.WriteString(indent)
+ s.WriteString("}")
+
+ return s.String()
}
// ToBytes returns the serialized version of this message as defined by RFC
diff --git a/dhcpv6/dhcpv6relay.go b/dhcpv6/dhcpv6relay.go
index ace35f7..5a29c87 100644
--- a/dhcpv6/dhcpv6relay.go
+++ b/dhcpv6/dhcpv6relay.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"net"
+ "strings"
"github.com/insomniacslk/dhcp/iana"
"github.com/u-root/uio/uio"
@@ -100,20 +101,30 @@ func (r *RelayMessage) String() string {
// Summary prints all options associated with this relay message.
func (r *RelayMessage) Summary() string {
- ret := fmt.Sprintf(
- "RelayMessage\n"+
- " messageType=%v\n"+
- " hopcount=%v\n"+
- " linkaddr=%v\n"+
- " peeraddr=%v\n"+
- " options=%v\n",
- r.Type(),
- r.HopCount,
- r.LinkAddr,
- r.PeerAddr,
- r.Options,
- )
- return ret
+ return r.LongString(0)
+}
+
+// LongString prints all options associated with this message.
+func (r *RelayMessage) LongString(spaceIndent int) string {
+ indent := strings.Repeat(" ", spaceIndent)
+
+ var s strings.Builder
+ s.WriteString(indent)
+ s.WriteString("RelayMessage{\n")
+ s.WriteString(indent)
+ s.WriteString(fmt.Sprintf(" MessageType=%s\n", r.MessageType))
+ s.WriteString(indent)
+ s.WriteString(fmt.Sprintf(" HopCount=%d\n", r.HopCount))
+ s.WriteString(indent)
+ s.WriteString(fmt.Sprintf(" LinkAddr=%s\n", r.LinkAddr))
+ s.WriteString(indent)
+ s.WriteString(fmt.Sprintf(" PeerAddr=%s\n", r.PeerAddr))
+ s.WriteString(indent)
+ s.WriteString(" Options: ")
+ s.WriteString(r.Options.Options.LongString(spaceIndent + 2))
+ s.WriteString("\n}")
+
+ return s.String()
}
// ToBytes returns the serialized version of this relay message as defined by
diff --git a/dhcpv6/option_4rd.go b/dhcpv6/option_4rd.go
index 317f13a..2faea25 100644
--- a/dhcpv6/option_4rd.go
+++ b/dhcpv6/option_4rd.go
@@ -27,6 +27,11 @@ func (op *Opt4RD) String() string {
return fmt.Sprintf("%s: {Options=%v}", op.Code(), op.Options)
}
+// LongString returns a multi-line human-readable representation of the option
+func (op *Opt4RD) LongString(indentSpace int) string {
+ return fmt.Sprintf("%s: Options=%v", op.Code(), op.Options.LongString(indentSpace))
+}
+
// ParseOpt4RD builds an Opt4RD structure from a sequence of bytes.
// The input data does not include option code and length bytes
func ParseOpt4RD(data []byte) (*Opt4RD, error) {
diff --git a/dhcpv6/option_dhcpv4_msg.go b/dhcpv6/option_dhcpv4_msg.go
index 2cf988a..ad29353 100644
--- a/dhcpv6/option_dhcpv4_msg.go
+++ b/dhcpv6/option_dhcpv4_msg.go
@@ -2,6 +2,7 @@ package dhcpv6
import (
"fmt"
+ "strings"
"github.com/insomniacslk/dhcp/dhcpv4"
)
@@ -28,6 +29,17 @@ func (op *OptDHCPv4Msg) String() string {
return fmt.Sprintf("%s: %v", op.Code(), op.Msg)
}
+// LongString returns a multi-line string representation of DHCPv4 data.
+func (op *OptDHCPv4Msg) LongString(indent int) string {
+ summary := op.Msg.Summary()
+ ind := strings.Repeat(" ", indent+2)
+ if strings.Contains(summary, "\n") {
+ summary = strings.Replace(summary, "\n ", "\n"+ind, -1)
+ }
+ ind = strings.Repeat(" ", indent)
+ return fmt.Sprintf("%s: {%v%s}", op.Code(), summary, ind)
+}
+
// ParseOptDHCPv4Msg builds an OptDHCPv4Msg structure
// from a sequence of bytes. The input data does not include option code and length
// bytes.
diff --git a/dhcpv6/option_iaaddress.go b/dhcpv6/option_iaaddress.go
index c107b83..072ba65 100644
--- a/dhcpv6/option_iaaddress.go
+++ b/dhcpv6/option_iaaddress.go
@@ -63,6 +63,12 @@ func (op *OptIAAddress) String() string {
op.Code(), op.IPv6Addr, op.PreferredLifetime, op.ValidLifetime, op.Options)
}
+// LongString returns a multi-line string representation of the OptIAAddress data.
+func (op *OptIAAddress) LongString(indent int) string {
+ return fmt.Sprintf("%s: {IP=%v PreferredLifetime=%v ValidLifetime=%v Options=%v}",
+ op.Code(), op.IPv6Addr, op.PreferredLifetime, op.ValidLifetime, op.Options.LongString(indent))
+}
+
// ParseOptIAAddress builds an OptIAAddress structure from a sequence
// of bytes. The input data does not include option code and length
// bytes.
diff --git a/dhcpv6/option_iapd.go b/dhcpv6/option_iapd.go
index c71b0f6..6296103 100644
--- a/dhcpv6/option_iapd.go
+++ b/dhcpv6/option_iapd.go
@@ -74,6 +74,11 @@ func (op *OptIAPD) String() string {
op.Code(), op.IaId, op.T1, op.T2, op.Options)
}
+// LongString returns a multi-line string representation of the OptIAPD data
+func (op *OptIAPD) LongString(indentSpace int) string {
+ return fmt.Sprintf("%s: IAID=%#x T1=%v T2=%v Options=%v", op.Code(), op.IaId, op.T1, op.T2, op.Options.LongString(indentSpace))
+}
+
// ParseOptIAPD builds an OptIAPD structure from a sequence of bytes.
// The input data does not include option code and length bytes.
func ParseOptIAPD(data []byte) (*OptIAPD, error) {
diff --git a/dhcpv6/option_nontemporaryaddress.go b/dhcpv6/option_nontemporaryaddress.go
index 9232bb5..76f6f4c 100644
--- a/dhcpv6/option_nontemporaryaddress.go
+++ b/dhcpv6/option_nontemporaryaddress.go
@@ -97,6 +97,11 @@ func (op *OptIANA) String() string {
op.Code(), op.IaId, op.T1, op.T2, op.Options)
}
+// LongString returns a multi-line string representation of IANA data.
+func (op *OptIANA) LongString(indentSpace int) string {
+ return fmt.Sprintf("%s: IAID=%#x T1=%s T2=%s Options=%s", op.Code(), op.IaId, op.T1, op.T2, op.Options.LongString(indentSpace))
+}
+
// ParseOptIANA builds an OptIANA structure from a sequence of bytes. The
// input data does not include option code and length bytes.
func ParseOptIANA(data []byte) (*OptIANA, error) {
diff --git a/dhcpv6/option_relaymsg.go b/dhcpv6/option_relaymsg.go
index 5e1d902..216f53b 100644
--- a/dhcpv6/option_relaymsg.go
+++ b/dhcpv6/option_relaymsg.go
@@ -28,6 +28,11 @@ func (op *optRelayMsg) String() string {
return fmt.Sprintf("%s: %v", op.Code(), op.Msg)
}
+// LongString returns a multi-line string representation of the relay message data.
+func (op *optRelayMsg) LongString(indent int) string {
+ return fmt.Sprintf("%s: %v", op.Code(), op.Msg.LongString(indent))
+}
+
// build an optRelayMsg structure from a sequence of bytes.
// The input data does not include option code and length bytes.
func parseOptRelayMsg(data []byte) (*optRelayMsg, error) {
diff --git a/dhcpv6/option_temporaryaddress.go b/dhcpv6/option_temporaryaddress.go
index 624b4f9..4a79bac 100644
--- a/dhcpv6/option_temporaryaddress.go
+++ b/dhcpv6/option_temporaryaddress.go
@@ -33,6 +33,11 @@ func (op *OptIATA) String() string {
return fmt.Sprintf("%s: {IAID=%#x, Options=%v}", op.Code(), op.IaId, op.Options)
}
+// LongString returns a multi-line string representation of IATA data.
+func (op *OptIATA) LongString(indentSpace int) string {
+ return fmt.Sprintf("%s: IAID=%#x Options=%v", op.Code(), op.IaId, op.Options.LongString(indentSpace))
+}
+
// ParseOptIATA builds an OptIATA structure from a sequence of bytes. The
// input data does not include option code and length bytes.
func ParseOptIATA(data []byte) (*OptIATA, error) {
diff --git a/dhcpv6/option_vendor_opts.go b/dhcpv6/option_vendor_opts.go
index 74a4b70..11811c0 100644
--- a/dhcpv6/option_vendor_opts.go
+++ b/dhcpv6/option_vendor_opts.go
@@ -33,6 +33,11 @@ func (op *OptVendorOpts) String() string {
return fmt.Sprintf("%s: {EnterpriseNumber=%v VendorOptions=%v}", op.Code(), op.EnterpriseNumber, op.VendorOpts)
}
+// LongString returns a string representation of the VendorOpts data
+func (op *OptVendorOpts) LongString(indent int) string {
+ return fmt.Sprintf("%s: EnterpriseNumber=%v VendorOptions=%s", op.Code(), op.EnterpriseNumber, op.VendorOpts.LongString(indent))
+}
+
// ParseOptVendorOpts builds an OptVendorOpts structure from a sequence of bytes.
// The input data does not include option code and length bytes.
func ParseOptVendorOpts(data []byte) (*OptVendorOpts, error) {
diff --git a/dhcpv6/options.go b/dhcpv6/options.go
index 8bf1321..308fc2c 100644
--- a/dhcpv6/options.go
+++ b/dhcpv6/options.go
@@ -2,6 +2,7 @@ package dhcpv6
import (
"fmt"
+ "strings"
"github.com/u-root/uio/uio"
)
@@ -119,9 +120,37 @@ func ParseOption(code OptionCode, optData []byte) (Option, error) {
return opt, nil
}
+type longStringer interface {
+ LongString(spaceIndent int) string
+}
+
// Options is a collection of options.
type Options []Option
+// LongString prints options with indentation of at least spaceIndent spaces.
+func (o Options) LongString(spaceIndent int) string {
+ indent := strings.Repeat(" ", spaceIndent)
+ var s strings.Builder
+ if len(o) == 0 {
+ s.WriteString("[]")
+ } else {
+ s.WriteString("[\n")
+ for _, opt := range o {
+ s.WriteString(indent)
+ s.WriteString(" ")
+ if ls, ok := opt.(longStringer); ok {
+ s.WriteString(ls.LongString(spaceIndent + 2))
+ } else {
+ s.WriteString(opt.String())
+ }
+ s.WriteString("\n")
+ }
+ s.WriteString(indent)
+ s.WriteString("]")
+ }
+ return s.String()
+}
+
// Get returns all options matching the option code.
func (o Options) Get(code OptionCode) []Option {
var ret []Option