summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6/option_relaymsg_test.go
blob: dd82d28e50ae6cedee4fd019a60e36f234a49f7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package dhcpv6

import (
	"reflect"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestRelayMsgParseOptRelayMsg(t *testing.T) {
	opt, err := ParseOptRelayMsg([]byte{
		1,                // MessageTypeSolicit
		0xaa, 0xbb, 0xcc, // transaction ID
		0, 8, // option: elapsed time
		0, 2, // option length
		0, 0, // option value
	})
	if err != nil {
		t.Fatal(err)
	}
	if code := opt.Code(); code != OptionRelayMsg {
		t.Fatalf("Invalid option code. Expected OptionRelayMsg (%v), got %v",
			OptionRelayMsg, code,
		)
	}
}

func TestRelayMsgOptionsFromBytes(t *testing.T) {
	var opts Options
	err := opts.FromBytes([]byte{
		0, 9, // option: relay message
		0, 10, // relayed message length
		1,                // MessageTypeSolicit
		0xaa, 0xbb, 0xcc, // transaction ID
		0, 8, // option: elapsed time
		0, 2, // option length
		0, 0, // option value
	})
	if err != nil {
		t.Fatal(err)
	}
	if len(opts) != 1 {
		t.Fatalf("Invalid number of options. Expected 1, got %v", len(opts))
	}
	opt := opts[0]
	if code := opt.Code(); code != OptionRelayMsg {
		t.Fatalf("Invalid option code. Expected OptionRelayMsg (%v), got %v",
			OptionRelayMsg, code,
		)
	}
}

func TestRelayMsgParseOptRelayMsgSingleEncapsulation(t *testing.T) {
	d, err := FromBytes([]byte{
		12,                                             // RELAY-FORW
		0,                                              // hop count
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // linkAddr
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, // peerAddr
		0, 9, // option: relay message
		0, 10, // relayed message length
		1,                // MessageTypeSolicit
		0xaa, 0xbb, 0xcc, // transaction ID
		0, 8, // option: elapsed time
		0, 2, // option length
		0x11, 0x22, // option value
	})
	if err != nil {
		t.Fatal(err)
	}
	r, ok := d.(*RelayMessage)
	if !ok {
		t.Fatalf("Invalid DHCPv6 type. Expected RelayMessage, got %v",
			reflect.TypeOf(d),
		)
	}
	if mType := r.Type(); mType != MessageTypeRelayForward {
		t.Fatalf("Invalid messge type for relay. Expected %v, got %v", MessageTypeRelayForward, mType)
	}
	if len(r.Options) != 1 {
		t.Fatalf("Invalid number of options. Expected 1, got %v", len(r.Options))
	}
	if code := r.Options[0].Code(); code != OptionRelayMsg {
		t.Fatalf("Invalid option code. Expected OptionRelayMsg (%v), got %v",
			OptionRelayMsg, code,
		)
	}
	opt := r.Options[0]
	ro, ok := opt.(*OptRelayMsg)
	if !ok {
		t.Fatalf("Invalid option type. Expected OptRelayMsg, got %v",
			reflect.TypeOf(ro),
		)
	}
	innerDHCP, ok := ro.RelayMessage().(*Message)
	if !ok {
		t.Fatalf("Invalid relay message type. Expected Message, got %v",
			reflect.TypeOf(innerDHCP),
		)
	}
	if dType := innerDHCP.Type(); dType != MessageTypeSolicit {
		t.Fatalf("Invalid inner DHCP type. Expected MessageTypeSolicit (%v), got %v",
			MessageTypeSolicit, dType,
		)
	}
	xid := TransactionID{0xaa, 0xbb, 0xcc}
	if tID := innerDHCP.TransactionID; tID != xid {
		t.Fatalf("Invalid inner DHCP transaction ID. Expected 0xaabbcc, got %v", tID)
	}
	if len(innerDHCP.Options) != 1 {
		t.Fatalf("Invalid inner DHCP options length. Expected 1, got %v", len(innerDHCP.Options))
	}
	innerOpt := innerDHCP.Options[0]
	eto, ok := innerOpt.(*OptElapsedTime)
	if !ok {
		t.Fatalf("Invalid inner option type. Expected OptElapsedTime, got %v",
			reflect.TypeOf(innerOpt),
		)
	}
	if eTime := eto.ElapsedTime; eTime != 0x1122 {
		t.Fatalf("Invalid elapsed time. Expected 0x1122, got 0x%04x", eTime)
	}
}

func TestSample(t *testing.T) {
	// Nested relay message. This test only checks if it parses correctly, but
	// could/should be extended to check all the fields like done in other tests
	buf := []byte{
		12,                                             // relay
		1,                                              // hop count
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // linkAddr
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // peerAddr
		// relay msg
		0, 9, // opt relay msg
		0, 66, // opt len
		// relay fwd
		12,                                             // relay
		0,                                              // hop count
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // linkAddr
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // peerAddr
		// opt interface ID
		0, 18, // interface id
		0, 6, // opt len
		0xba, 0xbe, 0xb1, 0xb0, 0xbe, 0xbe, // opt value
		// relay msg
		0, 9, // relay msg
		0, 18, // msg len
		// dhcpv6 msg
		1,                // solicit
		0xaa, 0xbb, 0xcc, // transaction ID
		// client ID
		0, 1, // opt client id
		0, 10, // opt len
		0, 3, // duid type
		0, 1, // hw type
		5, 6, 7, 8, 9, 10, // duid value
	}
	_, err := FromBytes(buf)
	if err != nil {
		t.Fatal(err)
	}
}

func TestRelayMsgParseOptRelayMsgTooShort(t *testing.T) {
	_, err := ParseOptRelayMsg([]byte{
		1,                // MessageTypeSolicit
		0xaa, 0xbb, 0xcc, // transaction ID
		0, 8, // option: elapsed time
		// no length/value for elapsed time option
	})
	require.Error(t, err, "ParseOptRelayMsg() should return an error if the encapsulated message is invalid")
}

func TestRelayMsgString(t *testing.T) {
	opt, err := ParseOptRelayMsg([]byte{
		1,                // MessageTypeSolicit
		0xaa, 0xbb, 0xcc, // transaction ID
		0, 8, // option: elapsed time
		0, 2, // option length
		0, 0, // option value
	})
	require.NoError(t, err)
	require.Contains(
		t,
		opt.String(),
		"relaymsg=Message",
		"String() should contain the relaymsg contents",
	)
}