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 }