mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/kube-vip/kube-vip.git
synced 2026-09-20 08:03:47 +08:00
feat(wireguard): qualify service tunnel IDs by protocol
Sanitisation maps '-' onto the '_' separator, so "a-b/c" and "a/b-c" shared one nftables chain, and TCP and UDP on the same port collided. ServicePortIDs appends the protocol and, when sanitisation changed the name or the ID grew too long, a hash of the raw name. It also returns the previous port-only ID so existing chains can be migrated. Signed-off-by: Marcel Fest <marcel.fest@telekom.de>
This commit is contained in:
39
pkg/wireguard/service_id.go
Normal file
39
pkg/wireguard/service_id.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kube-vip/kube-vip/pkg/utils"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
const maxServicePortIDLength = 50
|
||||
|
||||
// ServicePortIDs returns the protocol-qualified nftables identifier and the
|
||||
// prior port-only identifier that must be removed during migration.
|
||||
//
|
||||
// Sanitisation maps '-' onto the '_' separator, so "a-b/c" and "a/b-c" would
|
||||
// otherwise share a chain; a hash of the raw name keeps them distinct.
|
||||
func ServicePortIDs(namespace, name string, port v1.ServicePort) (string, string) {
|
||||
rawServiceID := fmt.Sprintf("%s_%s", namespace, name)
|
||||
serviceID := utils.SanitizeServiceID(rawServiceID)
|
||||
legacyID := fmt.Sprintf("%s_p%d", serviceID, port.Port)
|
||||
protocol := port.Protocol
|
||||
if protocol == "" {
|
||||
protocol = v1.ProtocolTCP
|
||||
}
|
||||
suffix := fmt.Sprintf("_p%d_%s", port.Port, strings.ToLower(string(protocol)))
|
||||
maxBase := maxServicePortIDLength - len(suffix)
|
||||
if serviceID != rawServiceID || len(serviceID) > maxBase {
|
||||
sum := sha256.Sum256([]byte(rawServiceID))
|
||||
hash := fmt.Sprintf("_%x", sum[:8])
|
||||
maxPrefix := maxBase - len(hash)
|
||||
if len(serviceID) > maxPrefix {
|
||||
serviceID = serviceID[:maxPrefix]
|
||||
}
|
||||
serviceID += hash
|
||||
}
|
||||
return serviceID + suffix, legacyID
|
||||
}
|
||||
33
pkg/wireguard/service_id_test.go
Normal file
33
pkg/wireguard/service_id_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func TestServicePortIDsKeepProtocolAndLongNamesDistinct(t *testing.T) {
|
||||
udp := v1.ServicePort{Port: 53, Protocol: v1.ProtocolUDP}
|
||||
udpID, legacyID := ServicePortIDs("default", "dns", udp)
|
||||
if udpID != "default_dns_p53_udp" || legacyID != "default_dns_p53" {
|
||||
t.Fatalf("ServicePortIDs() = %q, %q", udpID, legacyID)
|
||||
}
|
||||
tcpID, _ := ServicePortIDs("default", "dns", v1.ServicePort{Port: 53, Protocol: v1.ProtocolTCP})
|
||||
if tcpID == udpID {
|
||||
t.Fatal("TCP and UDP Services sharing a port received the same rule ID")
|
||||
}
|
||||
|
||||
longPrefix := strings.Repeat("a", 63)
|
||||
first, _ := ServicePortIDs(longPrefix, "first", udp)
|
||||
second, _ := ServicePortIDs(longPrefix, "second", udp)
|
||||
if len(first) > maxServicePortIDLength || first == second {
|
||||
t.Fatalf("long Service IDs = %q, %q", first, second)
|
||||
}
|
||||
|
||||
hyphenatedNamespace, _ := ServicePortIDs("a-b", "c", udp)
|
||||
hyphenatedName, _ := ServicePortIDs("a", "b-c", udp)
|
||||
if hyphenatedNamespace == hyphenatedName {
|
||||
t.Fatalf("distinct Services received the same rule ID %q", hyphenatedNamespace)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user