diff --git a/cmd/kgctl/showconf.go b/cmd/kgctl/showconf.go index 8152c02..8c5259a 100644 --- a/cmd/kgctl/showconf.go +++ b/cmd/kgctl/showconf.go @@ -289,9 +289,16 @@ func translatePeer(peer *wireguard.Peer) *v1alpha1.Peer { aips = append(aips, aip.String()) } var endpoint *v1alpha1.PeerEndpoint - if peer.Endpoint != nil && peer.Endpoint.Port > 0 && peer.Endpoint.IP != nil { + if peer.Endpoint != nil && peer.Endpoint.Port > 0 && (peer.Endpoint.IP != nil || peer.Endpoint.DNS != "") { + var ip string + if peer.Endpoint.IP != nil { + ip = peer.Endpoint.IP.String() + } endpoint = &v1alpha1.PeerEndpoint{ - IP: peer.Endpoint.IP.String(), + DNSOrIP: v1alpha1.DNSOrIP{ + DNS: peer.Endpoint.DNS, + IP: ip, + }, Port: peer.Endpoint.Port, } } diff --git a/pkg/k8s/apis/kilo/v1alpha1/types.go b/pkg/k8s/apis/kilo/v1alpha1/types.go index c05ef5c..26197bf 100644 --- a/pkg/k8s/apis/kilo/v1alpha1/types.go +++ b/pkg/k8s/apis/kilo/v1alpha1/types.go @@ -19,9 +19,11 @@ import ( "errors" "fmt" "net" + "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation" ) const ( @@ -81,12 +83,22 @@ type PeerSpec struct { // PeerEndpoint represents a WireGuard enpoint, which is a ip:port tuple. type PeerEndpoint struct { - // IP must be a valid IP address. - IP string `json:"ip"` + DNSOrIP // Port must be a valid port number. Port uint32 `json:"port"` } +// DNSOrIP represents either a DNS name or an IP address. +// IPs, as they are more specific, are preferred. +type DNSOrIP struct { + // DNS must be a valid RFC 1123 subdomain. + // +optional + DNS string `json:"dns,omitempty"` + // IP must be a valid IP address. + // +optional + IP string `json:"ip,omitempty"` +} + // PeerName is the peer resource's FQDN. var PeerName = PeerPlural + "." + GroupName @@ -127,10 +139,18 @@ func (p *Peer) Validate() error { } } if p.Spec.Endpoint != nil { - if net.ParseIP(p.Spec.Endpoint.IP) == nil { + if p.Spec.Endpoint.IP == "" && p.Spec.Endpoint.DNS == "" { + return errors.New("either an endpoint DNS name IP address must be given") + } + if p.Spec.Endpoint.DNS != "" { + if errs := validation.IsDNS1123Subdomain(p.Spec.Endpoint.DNS); len(errs) != 0 { + return errors.New(strings.Join(errs, "; ")) + } + } + if p.Spec.Endpoint.IP != "" && net.ParseIP(p.Spec.Endpoint.IP) == nil { return fmt.Errorf("failed to parse %q as a valid IP address", p.Spec.Endpoint.IP) } - if p.Spec.Endpoint.Port == 0 { + if 1 > p.Spec.Endpoint.Port || p.Spec.Endpoint.Port > 65535 { return fmt.Errorf("port must be a valid UDP port number, got %d", p.Spec.Endpoint.Port) } } diff --git a/pkg/k8s/apis/kilo/v1alpha1/zz_generated.deepcopy.go b/pkg/k8s/apis/kilo/v1alpha1/zz_generated.deepcopy.go index 0528206..af9c00b 100644 --- a/pkg/k8s/apis/kilo/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/k8s/apis/kilo/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,22 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DNSOrIP) DeepCopyInto(out *DNSOrIP) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSOrIP. +func (in *DNSOrIP) DeepCopy() *DNSOrIP { + if in == nil { + return nil + } + out := new(DNSOrIP) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Peer) DeepCopyInto(out *Peer) { *out = *in @@ -52,6 +68,7 @@ func (in *Peer) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PeerEndpoint) DeepCopyInto(out *PeerEndpoint) { *out = *in + out.DNSOrIP = in.DNSOrIP return } diff --git a/pkg/k8s/backend.go b/pkg/k8s/backend.go index 553a93d..c02ae39 100644 --- a/pkg/k8s/backend.go +++ b/pkg/k8s/backend.go @@ -325,10 +325,13 @@ func translatePeer(peer *v1alpha1.Peer) *mesh.Peer { } else { ip = ip.To16() } - if peer.Spec.Endpoint.Port > 0 && ip != nil { + if peer.Spec.Endpoint.Port > 0 && (ip != nil || peer.Spec.Endpoint.DNS != "") { endpoint = &wireguard.Endpoint{ - DNSOrIP: wireguard.DNSOrIP{IP: ip}, - Port: peer.Spec.Endpoint.Port, + DNSOrIP: wireguard.DNSOrIP{ + DNS: peer.Spec.Endpoint.DNS, + IP: ip, + }, + Port: peer.Spec.Endpoint.Port, } } } @@ -464,8 +467,15 @@ func (pb *peerBackend) Set(name string, peer *mesh.Peer) error { p.Spec.AllowedIPs[i] = peer.AllowedIPs[i].String() } if peer.Endpoint != nil { + var ip string + if peer.Endpoint.IP != nil { + ip = peer.Endpoint.IP.String() + } p.Spec.Endpoint = &v1alpha1.PeerEndpoint{ - IP: peer.Endpoint.IP.String(), + DNSOrIP: v1alpha1.DNSOrIP{ + IP: ip, + DNS: peer.Endpoint.DNS, + }, Port: peer.Endpoint.Port, } } diff --git a/pkg/k8s/backend_test.go b/pkg/k8s/backend_test.go index d91d02d..5ffb15d 100644 --- a/pkg/k8s/backend_test.go +++ b/pkg/k8s/backend_test.go @@ -240,17 +240,30 @@ func TestTranslatePeer(t *testing.T) { name: "invalid endpoint ip", spec: v1alpha1.PeerSpec{ Endpoint: &v1alpha1.PeerEndpoint{ - IP: "foo", + DNSOrIP: v1alpha1.DNSOrIP{ + IP: "foo", + }, Port: mesh.DefaultKiloPort, }, }, out: &mesh.Peer{}, }, { - name: "valid endpoint", + name: "only endpoint port", spec: v1alpha1.PeerSpec{ Endpoint: &v1alpha1.PeerEndpoint{ - IP: "10.0.0.1", + Port: mesh.DefaultKiloPort, + }, + }, + out: &mesh.Peer{}, + }, + { + name: "valid endpoint ip", + spec: v1alpha1.PeerSpec{ + Endpoint: &v1alpha1.PeerEndpoint{ + DNSOrIP: v1alpha1.DNSOrIP{ + IP: "10.0.0.1", + }, Port: mesh.DefaultKiloPort, }, }, @@ -263,6 +276,25 @@ func TestTranslatePeer(t *testing.T) { }, }, }, + { + name: "valid endpoint DNS", + spec: v1alpha1.PeerSpec{ + Endpoint: &v1alpha1.PeerEndpoint{ + DNSOrIP: v1alpha1.DNSOrIP{ + DNS: "example.com", + }, + Port: mesh.DefaultKiloPort, + }, + }, + out: &mesh.Peer{ + Peer: wireguard.Peer{ + Endpoint: &wireguard.Endpoint{ + DNSOrIP: wireguard.DNSOrIP{DNS: "example.com"}, + Port: mesh.DefaultKiloPort, + }, + }, + }, + }, { name: "empty key", spec: v1alpha1.PeerSpec{ diff --git a/pkg/mesh/topology.go b/pkg/mesh/topology.go index 4c3e2e7..9a68835 100644 --- a/pkg/mesh/topology.go +++ b/pkg/mesh/topology.go @@ -19,11 +19,12 @@ import ( "net" "sort" + "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" + "github.com/squat/kilo/pkg/encapsulation" "github.com/squat/kilo/pkg/iptables" "github.com/squat/kilo/pkg/wireguard" - "github.com/vishvananda/netlink" - "golang.org/x/sys/unix" ) const kiloTableIndex = 1107