diff --git a/go/hidden_path_srv/internal/registration/BUILD.bazel b/go/hidden_path_srv/internal/registration/BUILD.bazel index c32172a4ba..aeff81f0ac 100644 --- a/go/hidden_path_srv/internal/registration/BUILD.bazel +++ b/go/hidden_path_srv/internal/registration/BUILD.bazel @@ -25,17 +25,30 @@ go_library( go_test( name = "go_default_test", - srcs = ["validator_test.go"], + srcs = [ + "handler_test.go", + "validator_test.go", + ], embed = [":go_default_library"], deps = [ + "//go/hidden_path_srv/internal/registration/mock_registration:go_default_library", "//go/lib/addr:go_default_library", "//go/lib/common:go_default_library", + "//go/lib/ctrl/ack:go_default_library", "//go/lib/ctrl/path_mgmt:go_default_library", "//go/lib/ctrl/seg:go_default_library", "//go/lib/hiddenpath:go_default_library", "//go/lib/infra:go_default_library", + "//go/lib/infra/messenger:go_default_library", + "//go/lib/infra/mock_infra:go_default_library", + "//go/lib/infra/modules/seghandler:go_default_library", + "//go/lib/infra/modules/seghandler/mock_seghandler:go_default_library", + "//go/lib/log:go_default_library", + "//go/lib/snet:go_default_library", + "//go/lib/spath:go_default_library", "//go/lib/xtest:go_default_library", "//go/lib/xtest/graph:go_default_library", + "//go/lib/xtest/matchers:go_default_library", "//go/proto:go_default_library", "@com_github_golang_mock//gomock:go_default_library", "@com_github_stretchr_testify//assert:go_default_library", diff --git a/go/hidden_path_srv/internal/registration/handler.go b/go/hidden_path_srv/internal/registration/handler.go index 6011a88905..166785740b 100644 --- a/go/hidden_path_srv/internal/registration/handler.go +++ b/go/hidden_path_srv/internal/registration/handler.go @@ -65,7 +65,7 @@ func (h *hpSegRegHandler) handle(logger log.Logger) (*infra.HandlerResult, error ctx := h.request.Context() hpSegReg, ok := h.request.Message.(*path_mgmt.HPSegReg) if !ok { - logger.Error("[hpSegRegHandler] wrong message type, expected path_mgmt.HPSegReg", + logger.Error("[hpSegRegHandler] Wrong message type, expected path_mgmt.HPSegReg", "msg", h.request.Message, "type", common.TypeOf(h.request.Message)) return infra.MetricsErrInternal, nil } @@ -83,7 +83,13 @@ func (h *hpSegRegHandler) handle(logger log.Logger) (*infra.HandlerResult, error logger.Debug("[hpSegRegHandler] Received HPSegRecs", "src", h.request.Peer, "data", hpSegReg.HPSegRecs) - snetPeer := h.request.Peer.(*snet.Addr) + snetPeer, ok := h.request.Peer.(*snet.Addr) + if !ok { + logger.Error("[hpSegRegHandler] Invalid peer address type, expected *snet.Addr", nil, + "peer", h.request.Peer, "type", common.TypeOf(h.request.Peer)) + sendAck(proto.Ack_ErrCode_reject, messenger.AckRejectFailedToParse) + return infra.MetricsErrInvalid, nil + } peerPath, err := snetPeer.GetPath() if err != nil { logger.Error("[hpSegRegHandler] Failed to initialize path", "err", err) diff --git a/go/hidden_path_srv/internal/registration/handler_test.go b/go/hidden_path_srv/internal/registration/handler_test.go new file mode 100644 index 0000000000..ec6313e6d0 --- /dev/null +++ b/go/hidden_path_srv/internal/registration/handler_test.go @@ -0,0 +1,203 @@ +// Copyright 2019 ETH Zurich +// +// 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 registration_test + +import ( + "context" + "errors" + "net" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + "github.com/scionproto/scion/go/hidden_path_srv/internal/registration" + "github.com/scionproto/scion/go/hidden_path_srv/internal/registration/mock_registration" + "github.com/scionproto/scion/go/lib/addr" + "github.com/scionproto/scion/go/lib/common" + "github.com/scionproto/scion/go/lib/ctrl/ack" + "github.com/scionproto/scion/go/lib/ctrl/path_mgmt" + "github.com/scionproto/scion/go/lib/ctrl/seg" + "github.com/scionproto/scion/go/lib/infra" + "github.com/scionproto/scion/go/lib/infra/messenger" + "github.com/scionproto/scion/go/lib/infra/mock_infra" + "github.com/scionproto/scion/go/lib/infra/modules/seghandler" + "github.com/scionproto/scion/go/lib/infra/modules/seghandler/mock_seghandler" + "github.com/scionproto/scion/go/lib/log" + "github.com/scionproto/scion/go/lib/snet" + "github.com/scionproto/scion/go/lib/spath" + "github.com/scionproto/scion/go/lib/xtest/matchers" + "github.com/scionproto/scion/go/proto" +) + +func TestSegReg(t *testing.T) { + log.Root().SetHandler(log.DiscardHandler()) + newTestGraph(t, gomock.NewController(t)) + tests := map[string]func(*testing.T, context.Context, infra.Handler, *mocks){ + "valid request": func(t *testing.T, ctx context.Context, handler infra.Handler, m *mocks) { + msg := &path_mgmt.HPSegReg{ + HPSegRecs: &path_mgmt.HPSegRecs{ + GroupId: group.Id.ToMsg(), + Recs: []*seg.Meta{seg110_133}, + }, + } + peer := &snet.Addr{ + Host: addr.NewSVCUDPAppAddr(addr.SvcBS), + } + req := infra.NewRequest(ctx, msg, nil, peer, 0) + ack := ack.Ack{ + Err: proto.Ack_ErrCode_ok, + ErrDesc: "", + } + segments := seghandler.Segments{ + Segs: msg.HPSegRecs.Recs, + HPGroupID: group.Id, + } + m.validator.EXPECT().Validate(msg, peer.IA).Return(nil) + m.verifier.EXPECT().Verify(gomock.Any(), segments, peer) + m.rw.EXPECT().SendAckReply(gomock.Any(), &matchers.AckMsg{Ack: ack}) + res := handler.Handle(req) + assert.Equal(t, infra.MetricsResultOk, res) + }, + "wrong message type": func(t *testing.T, ctx context.Context, + handler infra.Handler, m *mocks) { + + req := infra.NewRequest(ctx, &path_mgmt.HPSegReq{}, nil, nil, 0) + res := handler.Handle(req) + assert.Equal(t, infra.MetricsErrInternal, res) + }, + "no messenger": func(t *testing.T, ctx context.Context, + handler infra.Handler, m *mocks) { + + req := infra.NewRequest(context.Background(), + &path_mgmt.HPSegReg{}, nil, nil, 0) + res := handler.Handle(req) + assert.Equal(t, infra.MetricsErrInternal, res) + }, + "corrupt segment data": func(t *testing.T, ctx context.Context, + handler infra.Handler, m *mocks) { + + segment := seg110_133.Segment.ShallowCopy() + segment.RawSData = common.RawBytes("abc") + req := infra.NewRequest(ctx, &path_mgmt.HPSegReg{ + HPSegRecs: &path_mgmt.HPSegRecs{ + Recs: []*seg.Meta{{ + Segment: segment, + }}, + }, + }, nil, nil, 0) + ack := ack.Ack{ + Err: proto.Ack_ErrCode_reject, + ErrDesc: messenger.AckRejectFailedToParse, + } + m.rw.EXPECT().SendAckReply(gomock.Any(), &matchers.AckMsg{Ack: ack}) + res := handler.Handle(req) + assert.Equal(t, infra.MetricsErrInvalid, res) + }, + "invalid peer address type": func(t *testing.T, ctx context.Context, + handler infra.Handler, m *mocks) { + + msg := &path_mgmt.HPSegReg{ + HPSegRecs: &path_mgmt.HPSegRecs{ + Recs: []*seg.Meta{seg110_133}, + }, + } + peer := &net.IPNet{} + req := infra.NewRequest(ctx, msg, nil, peer, 0) + ack := ack.Ack{ + Err: proto.Ack_ErrCode_reject, + ErrDesc: messenger.AckRejectFailedToParse, + } + m.rw.EXPECT().SendAckReply(gomock.Any(), &matchers.AckMsg{Ack: ack}) + res := handler.Handle(req) + assert.Equal(t, infra.MetricsErrInvalid, res) + }, + "invalid peer hop field": func(t *testing.T, ctx context.Context, + handler infra.Handler, m *mocks) { + + msg := &path_mgmt.HPSegReg{ + HPSegRecs: &path_mgmt.HPSegRecs{ + Recs: []*seg.Meta{seg110_133}, + }, + } + peer := &snet.Addr{ + Path: &spath.Path{}, + } + req := infra.NewRequest(ctx, msg, nil, peer, 0) + ack := ack.Ack{ + Err: proto.Ack_ErrCode_reject, + ErrDesc: messenger.AckRejectFailedToParse, + } + m.rw.EXPECT().SendAckReply(gomock.Any(), &matchers.AckMsg{Ack: ack}) + res := handler.Handle(req) + assert.Equal(t, infra.MetricsErrInvalid, res) + }, + "group validation fails": func(t *testing.T, ctx context.Context, + handler infra.Handler, m *mocks) { + + msg := &path_mgmt.HPSegReg{ + HPSegRecs: &path_mgmt.HPSegRecs{ + GroupId: group.Id.ToMsg(), + Recs: []*seg.Meta{seg110_133}, + }, + } + peer := &snet.Addr{ + Host: addr.NewSVCUDPAppAddr(addr.SvcBS), + } + req := infra.NewRequest(ctx, msg, nil, peer, 0) + ack := ack.Ack{ + Err: proto.Ack_ErrCode_reject, + ErrDesc: "dummy", + } + m.validator.EXPECT().Validate(msg, peer.IA).Return(errors.New("dummy")) + m.rw.EXPECT().SendAckReply(gomock.Any(), &matchers.AckMsg{Ack: ack}) + res := handler.Handle(req) + assert.Equal(t, infra.MetricsErrInvalid, res) + }, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mocks := createMocks(ctrl) + ctx := infra.NewContextWithResponseWriter( + context.Background(), mocks.rw) + handler := registration.NewSegRegHandler( + mocks.validator, + seghandler.Handler{ + Verifier: mocks.verifier, + Storage: mocks.storage, + }, + ) + test(t, ctx, handler, mocks) + }) + } +} + +type mocks struct { + validator *mock_registration.MockValidator + verifier *mock_seghandler.MockVerifier + storage *mock_seghandler.MockStorage + rw *mock_infra.MockResponseWriter +} + +func createMocks(ctrl *gomock.Controller) *mocks { + return &mocks{ + validator: mock_registration.NewMockValidator(ctrl), + verifier: mock_seghandler.NewMockVerifier(ctrl), + storage: mock_seghandler.NewMockStorage(ctrl), + rw: mock_infra.NewMockResponseWriter(ctrl), + } +} diff --git a/go/hidden_path_srv/internal/registration/mock_registration/BUILD.bazel b/go/hidden_path_srv/internal/registration/mock_registration/BUILD.bazel new file mode 100644 index 0000000000..01021a1215 --- /dev/null +++ b/go/hidden_path_srv/internal/registration/mock_registration/BUILD.bazel @@ -0,0 +1,13 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["registration.go"], + importpath = "github.com/scionproto/scion/go/hidden_path_srv/internal/registration/mock_registration", + visibility = ["//go/hidden_path_srv:__subpackages__"], + deps = [ + "//go/lib/addr:go_default_library", + "//go/lib/ctrl/path_mgmt:go_default_library", + "@com_github_golang_mock//gomock:go_default_library", + ], +) diff --git a/go/hidden_path_srv/internal/registration/mock_registration/registration.go b/go/hidden_path_srv/internal/registration/mock_registration/registration.go new file mode 100644 index 0000000000..217f50bd20 --- /dev/null +++ b/go/hidden_path_srv/internal/registration/mock_registration/registration.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/scionproto/scion/go/hidden_path_srv/internal/registration (interfaces: Validator) + +// Package mock_registration is a generated GoMock package. +package mock_registration + +import ( + gomock "github.com/golang/mock/gomock" + addr "github.com/scionproto/scion/go/lib/addr" + path_mgmt "github.com/scionproto/scion/go/lib/ctrl/path_mgmt" + reflect "reflect" +) + +// MockValidator is a mock of Validator interface +type MockValidator struct { + ctrl *gomock.Controller + recorder *MockValidatorMockRecorder +} + +// MockValidatorMockRecorder is the mock recorder for MockValidator +type MockValidatorMockRecorder struct { + mock *MockValidator +} + +// NewMockValidator creates a new mock instance +func NewMockValidator(ctrl *gomock.Controller) *MockValidator { + mock := &MockValidator{ctrl: ctrl} + mock.recorder = &MockValidatorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockValidator) EXPECT() *MockValidatorMockRecorder { + return m.recorder +} + +// Validate mocks base method +func (m *MockValidator) Validate(arg0 *path_mgmt.HPSegReg, arg1 addr.IA) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validate", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Validate indicates an expected call of Validate +func (mr *MockValidatorMockRecorder) Validate(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockValidator)(nil).Validate), arg0, arg1) +} diff --git a/tools/gomocks b/tools/gomocks index 37ba4a49e9..8668b9be33 100755 --- a/tools/gomocks +++ b/tools/gomocks @@ -36,6 +36,7 @@ MOCK_TARGETS = [ "BeaconInserter,BeaconProvider,SegmentProvider"), (SCION_PACKAGE_PREFIX + "/go/beacon_srv/internal/keepalive", "IfStatePusher,RevDropper"), (SCION_PACKAGE_PREFIX + "/go/beacon_srv/internal/revocation", "Store"), + (SCION_PACKAGE_PREFIX + "/go/hidden_path_srv/internal/registration", "Validator"), (SCION_PACKAGE_PREFIX + "/go/lib/ctrl/seg", "Signer"), (SCION_PACKAGE_PREFIX + "/go/lib/infra", "ASInspector,Messenger,ResponseWriter,TrustStore,Verifier"),