package dhcpv6 import ( "errors" "fmt" "net" "testing" "github.com/insomniacslk/dhcp/iana" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) var ErrDummy = errors.New("dummy error") type MatchingAddressTestSuite struct { suite.Suite m mock.Mock ips []net.IP addrs []net.Addr } func (s *MatchingAddressTestSuite) InterfaceAddresses(name string) ([]net.Addr, error) { args := s.m.Called(name) if args.Get(0) == nil { return nil, args.Error(1) } if ifaddrs, ok := args.Get(0).([]net.Addr); ok { return ifaddrs, args.Error(1) } panic(fmt.Sprintf("assert: arguments: InterfaceAddresses(0) failed because object wasn't correct type: %v", args.Get(0))) } func (s *MatchingAddressTestSuite) Match(ip net.IP) bool { args := s.m.Called(ip) return args.Bool(0) } func (s *MatchingAddressTestSuite) SetupTest() { InterfaceAddresses = s.InterfaceAddresses s.ips = []net.IP{ net.ParseIP("2401:db00:3020:70e1:face:0:7e:0"), net.ParseIP("2803:6080:890c:847e::1"), net.ParseIP("fe80::4a57:ddff:fe04:d8e9"), } s.addrs = []net.Addr{} for _, ip := range s.ips { s.addrs = append(s.addrs, &net.IPNet{IP: ip}) } } func (s *MatchingAddressTestSuite) TestGetMatchingAddr() { // Check if error from InterfaceAddresses immediately returns error s.m.On("InterfaceAddresses", "eth0").Return(nil, ErrDummy).Once() _, err := getMatchingAddr("eth0", s.Match) s.Assert().Equal(ErrDummy, err) s.m.AssertExpectations(s.T()) // Check if the looping is stopped after finding a matching address s.m.On("InterfaceAddresses", "eth0").Return(s.addrs, nil).Once() s.m.On("Match", s.ips[0]).Return(false).Once() s.m.On("Match", s.ips[1]).Return(true).Once() ip, err := getMatchingAddr("eth0", s.Match) s.Require().NoError(err) s.Assert().Equal(s.ips[1], ip) s.m.AssertExpectations(s.T()) // Check if the looping skips not matching addresses s.m.On("InterfaceAddresses", "eth0").Return(s.addrs, nil).Once() s.m.On("Match", s.ips[0]).Return(false).Once() s.m.On("Match", s.ips[1]).Return(false).Once() s.m.On("Match", s.ips[2]).Return(true).Once() ip, err = getMatchingAddr("eth0", s.Match) s.Require().NoError(err) s.Assert().Equal(s.ips[2], ip) s.m.AssertExpectations(s.T()) // Check if the error is returned if no matching address is found s.m.On("InterfaceAddresses", "eth0").Return(s.addrs, nil).Once() s.m.On("Match", s.ips[0]).Return(false).Once() s.m.On("Match", s.ips[1]).Return(false).Once() s.m.On("Match", s.ips[2]).Return(false).Once() _, err = getMatchingAddr("eth0", s.Match) s.Assert().EqualError(err, "no matching address found for interface eth0") s.m.AssertExpectations(s.T()) } func (s *MatchingAddressTestSuite) TestGetLinkLocalAddr() { s.m.On("InterfaceAddresses", "eth0").Return(s.addrs, nil).Once() ip, err := GetLinkLocalAddr("eth0") s.Require().NoError(err) s.Assert().Equal(s.ips[2], ip) s.m.AssertExpectations(s.T()) } func (s *MatchingAddressTestSuite) TestGetGlobalAddr() { s.m.On("InterfaceAddresses", "eth0").Return(s.addrs, nil).Once() ip, err := GetGlobalAddr("eth0") s.Require().NoError(err) s.Assert().Equal(s.ips[0], ip) s.m.AssertExpectations(s.T()) } func TestMatchingAddressTestSuite(t *testing.T) { suite.Run(t, new(MatchingAddressTestSuite)) } func Test_ExtractMAC(t *testing.T) { //SOLICIT message wrapped in Relay-Forw var relayForwBytesDuidUUID = []byte{ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x8a, 0x07, 0xff, 0xfe, 0x56, 0xdc, 0xa4, 0x00, 0x12, 0x00, 0x06, 0x24, 0x8a, 0x07, 0x56, 0xdc, 0xa4, 0x00, 0x09, 0x00, 0x5a, 0x06, 0x7d, 0x9b, 0xca, 0x00, 0x01, 0x00, 0x12, 0x00, 0x04, 0xb7, 0xfd, 0x0a, 0x8c, 0x1b, 0x14, 0x10, 0xaa, 0xeb, 0x0a, 0x5b, 0x3f, 0xe8, 0x9d, 0x0f, 0x56, 0x00, 0x06, 0x00, 0x0a, 0x00, 0x17, 0x00, 0x18, 0x00, 0x17, 0x00, 0x18, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0xff, 0xff, 0x00, 0x03, 0x00, 0x28, 0x07, 0x56, 0xdc, 0xa4, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00, 0x15, 0x18, 0x00, 0x05, 0x00, 0x18, 0x26, 0x20, 0x01, 0x0d, 0xc0, 0x82, 0x90, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xa0, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x1d, 0x4c} packet, err := FromBytes(relayForwBytesDuidUUID) require.NoError(t, err) mac, err := ExtractMAC(packet) require.NoError(t, err) require.Equal(t, mac.String(), "24:8a:07:56:dc:a4") // MAC extracted from DUID-LL duid := &DUIDLL{ HWType: iana.HWTypeEthernet, LinkLayerAddr: []byte{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, } solicit, err := NewMessage(WithClientID(duid)) require.NoError(t, err) relay, err := EncapsulateRelay(solicit, MessageTypeRelayForward, net.IPv6zero, net.IPv6zero) require.NoError(t, err) mac, err = ExtractMAC(relay) require.NoError(t, err) require.Equal(t, mac.String(), "aa:aa:aa:aa:aa:aa") // MAC extracted from DUID-LLT solicit, err = NewMessage(WithClientID(&DUIDLLT{ HWType: iana.HWTypeEthernet, LinkLayerAddr: []byte{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, })) require.NoError(t, err) relay, err = EncapsulateRelay(solicit, MessageTypeRelayForward, net.IPv6zero, net.IPv6zero) require.NoError(t, err) mac, err = ExtractMAC(relay) require.NoError(t, err) require.Equal(t, mac.String(), "aa:aa:aa:aa:aa:aa") // no client ID solicit, err = NewMessage() require.NoError(t, err) _, err = ExtractMAC(solicit) require.Error(t, err) // DUID is not DuidLL or DuidLLT duiden := &DUIDEN{} solicit, err = NewMessage(WithClientID(duiden)) require.NoError(t, err) _, err = ExtractMAC(solicit) require.Error(t, err) }