go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/wireguardplugin/descriptor/peer.go (about)

     1  //  Copyright (c) 2020 Doc.ai and/or its affiliates.
     2  //
     3  //  Licensed under the Apache License, Version 2.0 (the "License");
     4  //  you may not use this file except in compliance with the License.
     5  //  You may obtain a copy of the License at:
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //  Unless required by applicable law or agreed to in writing, software
    10  //  distributed under the License is distributed on an "AS IS" BASIS,
    11  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //  See the License for the specific language governing permissions and
    13  //  limitations under the License.
    14  
    15  package descriptor
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  
    21  	"github.com/pkg/errors"
    22  	"go.ligato.io/cn-infra/v2/logging"
    23  	"go.ligato.io/cn-infra/v2/utils/addrs"
    24  	"google.golang.org/protobuf/proto"
    25  
    26  	"go.ligato.io/vpp-agent/v3/pkg/models"
    27  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    28  	vpp_ifdescriptor "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor"
    29  	"go.ligato.io/vpp-agent/v3/plugins/vpp/wireguardplugin/wgidx"
    30  
    31  	"go.ligato.io/vpp-agent/v3/plugins/vpp/wireguardplugin/descriptor/adapter"
    32  	"go.ligato.io/vpp-agent/v3/plugins/vpp/wireguardplugin/vppcalls"
    33  	wg "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/wireguard"
    34  )
    35  
    36  const (
    37  	// PeerDescriptorName is the name of the descriptor for VPP wg peer.
    38  	PeerDescriptorName = "vpp-wg-peer"
    39  
    40  	// Length of wireguard public-key in base64. It should be equal 32 in binary
    41  	PeerKeyLen = 44
    42  
    43  	// MaxU16
    44  	MaxU16 = 0xFFFF
    45  )
    46  
    47  // A list of errors:
    48  var (
    49  	// ErrWgPeerKeyLen is returned when public-key length has wrong size.
    50  	ErrWgPeerKeyLen = errors.New("Invalid wireguard peer public-key length")
    51  
    52  	// ErrWgPeerWithoutInterface is returned when wireguard interface name is empty.
    53  	ErrWgPeerWithoutInterface = errors.New("Wireguard interface is not defined")
    54  
    55  	// ErrWgPeerPKeepalive is returned when persistent keepalive exceeds max value.
    56  	ErrWgPeerPKeepalive = errors.New("Persistent keepalive exceeds the limits")
    57  
    58  	// ErrWgPeerPort is returned when udp-port exceeds max value.
    59  	ErrWgPeerPort = errors.New("Invalid wireguard peer port")
    60  
    61  	// ErrWgPeerEndpointMissing is returned when endpoint address was not set or set to an empty string.
    62  	ErrWgPeerEndpointMissing = errors.Errorf("Missing endpoint address for wireguard peer")
    63  
    64  	// ErrWgSrcAddrBad is returned when endpoint address was not set to valid IP address.
    65  	ErrWgPeerEndpointBad = errors.New("Invalid wireguard peer endpoint")
    66  
    67  	// ErrWgPeerAllowedIPs is returned when one of allowedIp address was not set to valid IP address.
    68  	ErrWgPeerAllowedIPs = errors.New("Invalid wireguard peer allowedIps")
    69  )
    70  
    71  // WgPeerDescriptor teaches KVScheduler how to configure VPP wg peer.
    72  type WgPeerDescriptor struct {
    73  	log       logging.Logger
    74  	wgHandler vppcalls.WgVppAPI
    75  }
    76  
    77  // NewWgPeerDescriptor creates a new instance of the wireguard interface descriptor.
    78  func NewWgPeerDescriptor(wgHandler vppcalls.WgVppAPI, log logging.PluginLogger) *WgPeerDescriptor {
    79  	return &WgPeerDescriptor{
    80  		wgHandler: wgHandler,
    81  		log:       log.NewLogger("wg-peer-descriptor"),
    82  	}
    83  }
    84  
    85  // GetDescriptor returns descriptor suitable for registration (via adapter) with
    86  // the KVScheduler.
    87  func (d *WgPeerDescriptor) GetDescriptor() *adapter.PeerDescriptor {
    88  	return &adapter.PeerDescriptor{
    89  		Name:                 PeerDescriptorName,
    90  		NBKeyPrefix:          wg.ModelPeer.KeyPrefix(),
    91  		ValueTypeName:        wg.ModelPeer.ProtoName(),
    92  		KeySelector:          wg.ModelPeer.IsKeyValid,
    93  		KeyLabel:             wg.ModelPeer.StripKeyPrefix,
    94  		ValueComparator:      d.EquivalentWgPeers,
    95  		Validate:             d.Validate,
    96  		Create:               d.Create,
    97  		Delete:               d.Delete,
    98  		Retrieve:             d.Retrieve,
    99  		RetrieveDependencies: []string{vpp_ifdescriptor.InterfaceDescriptorName},
   100  		WithMetadata:         true,
   101  	}
   102  }
   103  
   104  func (d *WgPeerDescriptor) EquivalentWgPeers(key string, oldPeer, newPeer *wg.Peer) bool {
   105  	// compare base fields
   106  	return proto.Equal(oldPeer, newPeer)
   107  }
   108  
   109  func (d *WgPeerDescriptor) Validate(key string, peer *wg.Peer) (err error) {
   110  	if len(peer.PublicKey) != PeerKeyLen {
   111  		return kvs.NewInvalidValueError(ErrWgPeerKeyLen, "public_key")
   112  	}
   113  	if peer.WgIfName == "" {
   114  		return kvs.NewInvalidValueError(ErrWgPeerWithoutInterface, "wg_if_name")
   115  	}
   116  	if peer.PersistentKeepalive > MaxU16 {
   117  		return kvs.NewInvalidValueError(ErrWgPeerPKeepalive, "persistent_keepalive")
   118  	}
   119  	if peer.Endpoint == "" {
   120  		return kvs.NewInvalidValueError(ErrWgPeerEndpointMissing, "endpoint")
   121  	}
   122  	if net.ParseIP(peer.Endpoint).IsUnspecified() {
   123  		return kvs.NewInvalidValueError(ErrWgPeerEndpointBad, "endpoint")
   124  	}
   125  	if peer.Port > MaxU16 {
   126  		return kvs.NewInvalidValueError(ErrWgPeerPort, "port")
   127  	}
   128  
   129  	for _, allowedIp := range peer.AllowedIps {
   130  		_, _, err := addrs.ParseIPWithPrefix(allowedIp)
   131  		if err != nil {
   132  			return kvs.NewInvalidValueError(ErrWgPeerAllowedIPs, "allowed_ips")
   133  		}
   134  	}
   135  	return nil
   136  }
   137  
   138  // Create adds a new wireguard peer.
   139  func (d *WgPeerDescriptor) Create(key string, peer *wg.Peer) (metadata *wgidx.WgMetadata, err error) {
   140  	var vppWgIndex uint32
   141  	vppWgIndex, err = d.wgHandler.AddPeer(peer)
   142  	if err != nil {
   143  		d.log.Error(err)
   144  		return nil, err
   145  	}
   146  
   147  	metadata = &wgidx.WgMetadata{
   148  		Index: vppWgIndex,
   149  	}
   150  	return metadata, err
   151  }
   152  
   153  // Delete removes VPP wg peers.
   154  func (d *WgPeerDescriptor) Delete(key string, peer *wg.Peer, metadata *wgidx.WgMetadata) error {
   155  	if metadata == nil {
   156  		return fmt.Errorf("failed to delete peer - metadata is nil")
   157  	}
   158  	err := d.wgHandler.RemovePeer(metadata.Index)
   159  	if err != nil {
   160  		d.log.Error(err)
   161  	}
   162  	return err
   163  }
   164  
   165  // Retrieve returns all wg peers.
   166  func (d *WgPeerDescriptor) Retrieve(correlate []adapter.PeerKVWithMetadata) (dump []adapter.PeerKVWithMetadata, err error) {
   167  	peers, err := d.wgHandler.DumpWgPeers()
   168  	if err != nil {
   169  		d.log.Error(err)
   170  		return dump, err
   171  	}
   172  	for _, peer := range peers {
   173  		dump = append(dump, adapter.PeerKVWithMetadata{
   174  			Key:    models.Key(peer),
   175  			Value:  peer,
   176  			Origin: kvs.FromNB,
   177  		})
   178  	}
   179  
   180  	return dump, nil
   181  }