Skip to content

Commit

Permalink
Add IPSec mechanism
Browse files Browse the repository at this point in the history
Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>
  • Loading branch information
glazychev-art committed Nov 25, 2022
1 parent b2f49be commit e73f351
Show file tree
Hide file tree
Showing 20 changed files with 1,542 additions and 41 deletions.
11 changes: 9 additions & 2 deletions pkg/networkservice/chains/forwarder/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@ import (
"context"
"net"
"net/url"
"sync"
"time"

"git.fd.io/govpp.git/api"
"github.com/google/uuid"

"github.com/networkservicemesh/api/pkg/api/networkservice"
ipsecapi "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/ipsec"

"github.com/networkservicemesh/sdk/pkg/networkservice/chains/client"
"github.com/networkservicemesh/sdk/pkg/networkservice/chains/endpoint"
"github.com/networkservicemesh/sdk/pkg/networkservice/common/authorize"
Expand All @@ -54,6 +57,7 @@ import (
"github.com/networkservicemesh/sdk-kernel/pkg/kernel/networkservice/ethernetcontext"

"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/connectioncontext/mtu"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/ipsec"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/kernel"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/memif"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/vlan"
Expand Down Expand Up @@ -103,6 +107,7 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, vppConn
registryclient.WithDialOptions(opts.dialOpts...))

rv := &xconnectNSServer{}
pinholeMutex := new(sync.Mutex)
additionalFunctionality := []networkservice.NetworkServiceServer{
recvfd.NewServer(),
sendfd.NewServer(),
Expand All @@ -122,8 +127,9 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, vppConn
kernel.MECHANISM: kernel.NewServer(vppConn),
vxlan.MECHANISM: vxlan.NewServer(vppConn, tunnelIP, opts.vxlanOpts...),
wireguard.MECHANISM: wireguard.NewServer(vppConn, tunnelIP),
ipsecapi.MECHANISM: ipsec.NewServer(vppConn, tunnelIP),
}),
pinhole.NewServer(vppConn),
pinhole.NewServer(vppConn, pinhole.WithSharedMutex(pinholeMutex)),
connect.NewServer(
client.NewClient(ctx,
client.WithoutRefresh(),
Expand All @@ -146,9 +152,10 @@ func NewServer(ctx context.Context, tokenGenerator token.GeneratorFunc, vppConn
kernel.NewClient(vppConn),
vxlan.NewClient(vppConn, tunnelIP, opts.vxlanOpts...),
wireguard.NewClient(vppConn, tunnelIP),
ipsec.NewClient(vppConn, tunnelIP),
vlan.NewClient(vppConn, opts.domain2Device),
filtermechanisms.NewClient(),
pinhole.NewClient(vppConn),
pinhole.NewClient(vppConn, pinhole.WithSharedMutex(pinholeMutex)),
recvfd.NewClient(),
nsmonitor.NewClient(ctx),
sendfd.NewClient(),
Expand Down
117 changes: 117 additions & 0 deletions pkg/networkservice/mechanisms/ipsec/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) 2022 Cisco and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 ipsec

import (
"context"
"net"

"git.fd.io/govpp.git/api"
"github.com/golang/protobuf/ptypes/empty"
"github.com/pkg/errors"
"google.golang.org/grpc"

"github.com/networkservicemesh/api/pkg/api/networkservice"
"github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/cls"
ipsecMech "github.com/networkservicemesh/api/pkg/api/networkservice/mechanisms/ipsec"
"github.com/networkservicemesh/api/pkg/api/networkservice/payload"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/chain"
"github.com/networkservicemesh/sdk/pkg/networkservice/core/next"
"github.com/networkservicemesh/sdk/pkg/networkservice/utils/metadata"
"github.com/networkservicemesh/sdk/pkg/tools/postpone"

"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/mechanisms/ipsec/mtu"
"github.com/networkservicemesh/sdk-vpp/pkg/networkservice/pinhole"
)

type ipsecClient struct {
vppConn api.Connection
tunnelIP net.IP
}

// NewClient - returns a new client for the IPSec remote mechanism
func NewClient(vppConn api.Connection, tunnelIP net.IP) networkservice.NetworkServiceClient {
return chain.NewNetworkServiceClient(
&ipsecClient{
vppConn: vppConn,
tunnelIP: tunnelIP,
},
mtu.NewClient(vppConn, tunnelIP),
)
}

func (i *ipsecClient) Request(ctx context.Context, request *networkservice.NetworkServiceRequest, opts ...grpc.CallOption) (*networkservice.Connection, error) {
if request.GetConnection().GetPayload() != payload.IP {
return next.Client(ctx).Request(ctx, request, opts...)
}

rsaKey, err := generateRSAKey()
if err != nil {
return nil, err
}
publicKey, err := createCertBase64(rsaKey, metadata.IsClient(i))
if err != nil {
return nil, err
}
// If we already have a key we can reuse it
// else create a new one and store it after successful interface creation
if mechanism := ipsecMech.ToMechanism(request.GetConnection().GetMechanism()); mechanism != nil {
// If there is a key in mechanism then we can use it
publicKey = mechanism.SrcPublicKey()
}
mechanism := &networkservice.Mechanism{
Cls: cls.REMOTE,
Type: ipsecMech.MECHANISM,
Parameters: make(map[string]string),
}
ipsecMech.ToMechanism(mechanism).
SetSrcPublicKey(publicKey).
SetSrcIP(i.tunnelIP).
SetSrcPort(ikev2DefaultPort)

request.MechanismPreferences = append(request.MechanismPreferences, mechanism)

// Store extra IPPort entry to allow IKE protocol - https://www.rfc-editor.org/rfc/rfc5996
pinhole.StoreExtra(ctx, metadata.IsClient(i), pinhole.NewIPPort(i.tunnelIP.String(), 500))

postponeCtxFunc := postpone.ContextWithValues(ctx)

conn, err := next.Client(ctx).Request(ctx, request, opts...)
if err != nil {
return nil, err
}

if err = create(ctx, conn, i.vppConn, rsaKey, metadata.IsClient(i)); err != nil {
closeCtx, cancelClose := postponeCtxFunc()
defer cancelClose()

if _, closeErr := i.Close(closeCtx, conn, opts...); closeErr != nil {
err = errors.Wrapf(err, "connection closed with error: %s", closeErr.Error())
}

return nil, err
}

return conn, nil
}

func (i *ipsecClient) Close(ctx context.Context, conn *networkservice.Connection, opts ...grpc.CallOption) (*empty.Empty, error) {
if mechanism := ipsecMech.ToMechanism(conn.GetMechanism()); mechanism != nil {
delInterface(ctx, conn, i.vppConn, metadata.IsClient(i))
}
return next.Client(ctx).Close(ctx, conn, opts...)
}
Loading

0 comments on commit e73f351

Please sign in to comment.