ce7cb702218693d08ea6d83464d2457c9250027c
This commit is contained in:
commit
34c5f8963c
1 changed files with 145336 additions and 0 deletions
118
services/oci-l4-relay-wan-controller/oci.go
Normal file
118
services/oci-l4-relay-wan-controller/oci.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/oracle/oci-go-sdk/v65/common"
|
||||
"github.com/oracle/oci-go-sdk/v65/core"
|
||||
)
|
||||
|
||||
type networkSecurityGroupClient interface {
|
||||
UpdateNetworkSecurityGroupSecurityRules(context.Context, core.UpdateNetworkSecurityGroupSecurityRulesRequest) (core.UpdateNetworkSecurityGroupSecurityRulesResponse, error)
|
||||
}
|
||||
|
||||
type ociReconciler struct {
|
||||
client networkSecurityGroupClient
|
||||
networkSecurityGroup string
|
||||
securityRule string
|
||||
wireguardDestinationPort int
|
||||
wireguardURL string
|
||||
recoveryTimeout time.Duration
|
||||
probeWireGuard func(context.Context, string, time.Duration) error
|
||||
}
|
||||
|
||||
func newOCIReconciler(cfg config) (*ociReconciler, error) {
|
||||
provider := common.NewRawConfigurationProvider(
|
||||
cfg.ociTenancy,
|
||||
cfg.ociUser,
|
||||
cfg.ociRegion,
|
||||
cfg.ociFingerprint,
|
||||
cfg.ociPrivateKey,
|
||||
nil,
|
||||
)
|
||||
client, err := core.NewVirtualNetworkClientWithConfigurationProvider(provider)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create OCI virtual network client: %w", err)
|
||||
}
|
||||
return &ociReconciler{
|
||||
client: &client,
|
||||
networkSecurityGroup: cfg.networkSecurityGroup,
|
||||
securityRule: cfg.securityRule,
|
||||
wireguardDestinationPort: cfg.wireguardPort,
|
||||
wireguardURL: cfg.wireguardURL,
|
||||
recoveryTimeout: cfg.recoveryTimeout,
|
||||
probeWireGuard: waitForWireGuard,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *ociReconciler) Reconcile(ctx context.Context, source net.IP) error {
|
||||
if !validPublicIPv4(source) {
|
||||
return fmt.Errorf("refuse invalid WAN source %q", source)
|
||||
}
|
||||
port := r.wireguardDestinationPort
|
||||
protocol := "17"
|
||||
description := "Home WireGuard peer"
|
||||
sourceCIDR := source.String() + "/32"
|
||||
response, err := r.client.UpdateNetworkSecurityGroupSecurityRules(ctx, core.UpdateNetworkSecurityGroupSecurityRulesRequest{
|
||||
NetworkSecurityGroupId: common.String(r.networkSecurityGroup),
|
||||
UpdateNetworkSecurityGroupSecurityRulesDetails: core.UpdateNetworkSecurityGroupSecurityRulesDetails{
|
||||
SecurityRules: []core.UpdateSecurityRuleDetails{{
|
||||
Direction: core.UpdateSecurityRuleDetailsDirectionIngress,
|
||||
Id: common.String(r.securityRule),
|
||||
Protocol: common.String(protocol),
|
||||
Description: common.String(description),
|
||||
Source: common.String(sourceCIDR),
|
||||
SourceType: core.UpdateSecurityRuleDetailsSourceTypeCidrBlock,
|
||||
IsStateless: common.Bool(false),
|
||||
UdpOptions: &core.UdpOptions{DestinationPortRange: &core.PortRange{Min: common.Int(port), Max: common.Int(port)}},
|
||||
}},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("update WireGuard NSG source: %w", err)
|
||||
}
|
||||
if err := verifyUpdatedRule(response.SecurityRules, r.securityRule, sourceCIDR, port); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.probeWireGuard(ctx, r.wireguardURL, r.recoveryTimeout); err != nil {
|
||||
return fmt.Errorf("verify WireGuard connectivity: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyUpdatedRule(rules []core.SecurityRule, id, source string, port int) error {
|
||||
if len(rules) != 1 {
|
||||
return fmt.Errorf("OCI returned %d updated rules, want 1", len(rules))
|
||||
}
|
||||
rule := rules[0]
|
||||
if stringValue(rule.Id) != id || stringValue(rule.Source) != source ||
|
||||
stringValue(rule.Protocol) != "17" || rule.Direction != core.SecurityRuleDirectionIngress ||
|
||||
rule.SourceType != core.SecurityRuleSourceTypeCidrBlock || boolValue(rule.IsStateless) ||
|
||||
rule.UdpOptions == nil || rule.UdpOptions.DestinationPortRange == nil ||
|
||||
intValue(rule.UdpOptions.DestinationPortRange.Min) != port ||
|
||||
intValue(rule.UdpOptions.DestinationPortRange.Max) != port {
|
||||
return fmt.Errorf("OCI returned an unexpected WireGuard rule")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stringValue(value *string) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
func boolValue(value *bool) bool {
|
||||
return value != nil && *value
|
||||
}
|
||||
|
||||
func intValue(value *int) int {
|
||||
if value == nil {
|
||||
return 0
|
||||
}
|
||||
return *value
|
||||
}
|
||||
Loading…
Reference in a new issue