From 75c8ca65d7ace9df76eb10190b512ef8c3ba535e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 27 Nov 2023 21:13:53 +0400 Subject: [PATCH] feat: implement ingress firewall rules Fixes #4421 Signed-off-by: Andrey Smirnov --- Dockerfile | 2 +- api/resource/definitions/enums/enums.proto | 2 + .../pkg/adapters/network/nftables_rule.go | 2 +- .../pkg/controllers/network/nftables_chain.go | 7 +- .../network/nftables_chain_config.go | 187 +++++++++++++ .../network/nftables_chain_test.go | 47 +++- .../runtime/v1alpha2/v1alpha2_controller.go | 1 + .../resource/definitions/enums/enums.pb.go | 262 +++++++++--------- pkg/machinery/config/config/config.go | 1 + pkg/machinery/config/config/helpers.go | 39 +++ pkg/machinery/config/config/network.go | 66 +++++ pkg/machinery/config/config/runtime.go | 20 -- pkg/machinery/config/container/container.go | 5 + pkg/machinery/config/encoder/encoder.go | 5 + .../types/network/deep_copy.generated.go | 27 ++ .../types/network/default_action_config.go | 62 +++++ .../network/default_action_config_test.go | 54 ++++ pkg/machinery/config/types/network/network.go | 8 + .../config/types/network/port_range.go | 102 +++++++ .../config/types/network/port_range_test.go | 124 +++++++++ .../config/types/network/rule_config.go | 154 ++++++++++ .../config/types/network/rule_config_test.go | 199 +++++++++++++ .../network/testdata/defaultactionconfig.yaml | 3 + .../types/network/testdata/ruleconfig.yaml | 12 + .../config/types/runtime/event_sink_test.go | 8 - .../config/types/runtime/kmsg_log_test.go | 13 +- .../types/siderolink/siderolink_test.go | 19 +- pkg/machinery/config/types/types.go | 1 + pkg/machinery/nethelpers/default_action.go | 16 ++ .../nethelpers/defaultaction_enumer.go | 61 ++++ pkg/machinery/nethelpers/protocol.go | 6 +- pkg/machinery/nethelpers/protocol_enumer.go | 26 +- .../resources/network/nftables_chain.go | 17 +- website/content/v1.6/reference/api.md | 2 + 34 files changed, 1368 insertions(+), 192 deletions(-) create mode 100644 internal/app/machined/pkg/controllers/network/nftables_chain_config.go create mode 100644 pkg/machinery/config/config/helpers.go create mode 100644 pkg/machinery/config/config/network.go create mode 100644 pkg/machinery/config/types/network/deep_copy.generated.go create mode 100644 pkg/machinery/config/types/network/default_action_config.go create mode 100644 pkg/machinery/config/types/network/default_action_config_test.go create mode 100644 pkg/machinery/config/types/network/network.go create mode 100644 pkg/machinery/config/types/network/port_range.go create mode 100644 pkg/machinery/config/types/network/port_range_test.go create mode 100644 pkg/machinery/config/types/network/rule_config.go create mode 100644 pkg/machinery/config/types/network/rule_config_test.go create mode 100644 pkg/machinery/config/types/network/testdata/defaultactionconfig.yaml create mode 100644 pkg/machinery/config/types/network/testdata/ruleconfig.yaml create mode 100644 pkg/machinery/nethelpers/default_action.go create mode 100644 pkg/machinery/nethelpers/defaultaction_enumer.go diff --git a/Dockerfile b/Dockerfile index 10733a437eb..cb309d045fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -292,7 +292,7 @@ COPY --from=generate-build /api/inspect/*.pb.go /pkg/machinery/api/inspect/ COPY --from=go-generate /src/pkg/flannel/ /pkg/flannel/ COPY --from=go-generate /src/pkg/imager/profile/ /pkg/imager/profile/ COPY --from=go-generate /src/pkg/machinery/resources/ /pkg/machinery/resources/ -COPY --from=go-generate /src/pkg/machinery/config/types/v1alpha1/ /pkg/machinery/config/types/v1alpha1/ +COPY --from=go-generate /src/pkg/machinery/config/types/ /pkg/machinery/config/types/ COPY --from=go-generate /src/pkg/machinery/nethelpers/ /pkg/machinery/nethelpers/ COPY --from=go-generate /src/pkg/machinery/extensions/ /pkg/machinery/extensions/ COPY --from=embed-abbrev / / diff --git a/api/resource/definitions/enums/enums.proto b/api/resource/definitions/enums/enums.proto index 161692a1941..e2c2f86628c 100755 --- a/api/resource/definitions/enums/enums.proto +++ b/api/resource/definitions/enums/enums.proto @@ -259,8 +259,10 @@ enum NethelpersPrimaryReselect { // NethelpersProtocol is a inet protocol. enum NethelpersProtocol { NETHELPERS_PROTOCOL_UNSPECIFIED = 0; + PROTOCOL_ICMP = 1; PROTOCOL_TCP = 6; PROTOCOL_UDP = 17; + PROTOCOL_ICM_PV6 = 58; } // NethelpersRouteFlag wraps RTM_F_* constants. diff --git a/internal/app/machined/pkg/adapters/network/nftables_rule.go b/internal/app/machined/pkg/adapters/network/nftables_rule.go index a63dc26f444..a1e0305a9f1 100644 --- a/internal/app/machined/pkg/adapters/network/nftables_rule.go +++ b/internal/app/machined/pkg/adapters/network/nftables_rule.go @@ -91,7 +91,7 @@ func (set NfTablesSet) SetElements() []nftables.SetElement { for _, p := range set.Ports { from := binaryutil.BigEndian.PutUint16(p[0]) - to := binaryutil.BigEndian.PutUint16(p[1]) + to := binaryutil.BigEndian.PutUint16(p[1] + 1) elements = append(elements, nftables.SetElement{ diff --git a/internal/app/machined/pkg/controllers/network/nftables_chain.go b/internal/app/machined/pkg/controllers/network/nftables_chain.go index ae00a22eaf4..936642b4680 100644 --- a/internal/app/machined/pkg/controllers/network/nftables_chain.go +++ b/internal/app/machined/pkg/controllers/network/nftables_chain.go @@ -148,8 +148,11 @@ func (ctrl *NfTablesChainController) Run(ctx context.Context, r controller.Runti return fmt.Errorf("error adding nftables set for chain %s: %w", nfChain.Name, err) } - lookup.SetID = setID - lookup.SetName = setName + lookupOp := *lookup + lookupOp.SetID = setID + lookupOp.SetName = setName + + compiledRule[i] = &lookupOp } } diff --git a/internal/app/machined/pkg/controllers/network/nftables_chain_config.go b/internal/app/machined/pkg/controllers/network/nftables_chain_config.go new file mode 100644 index 00000000000..d7de836b9f9 --- /dev/null +++ b/internal/app/machined/pkg/controllers/network/nftables_chain_config.go @@ -0,0 +1,187 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package network + +import ( + "cmp" + "context" + "fmt" + "slices" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/gen/optional" + "github.com/siderolabs/gen/xslices" + "github.com/siderolabs/go-pointer" + "go.uber.org/zap" + + v1alpha1runtime "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/nethelpers" + "github.com/siderolabs/talos/pkg/machinery/resources/config" + "github.com/siderolabs/talos/pkg/machinery/resources/network" +) + +// NfTablesChainConfigController generates configuration for kmsg log delivery. +type NfTablesChainConfigController struct { + V1Alpha1Mode v1alpha1runtime.Mode +} + +// Name implements controller.Controller interface. +func (ctrl *NfTablesChainConfigController) Name() string { + return "network.NfTablesChainConfigController" +} + +// Inputs implements controller.Controller interface. +func (ctrl *NfTablesChainConfigController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: config.NamespaceName, + Type: config.MachineConfigType, + ID: optional.Some(config.V1Alpha1ID), + Kind: controller.InputWeak, + }, + } +} + +// Outputs implements controller.Controller interface. +func (ctrl *NfTablesChainConfigController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: network.NfTablesChainType, + Kind: controller.OutputShared, + }, + } +} + +// Run implements controller.Controller interface. +// +//nolint:gocyclo +func (ctrl *NfTablesChainConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) (err error) { + for { + select { + case <-ctx.Done(): + return nil + case <-r.EventCh(): + } + + cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error getting machine config: %w", err) + } + + r.StartTrackingOutputs() + + if cfg != nil { + if err = safe.WriterModify(ctx, r, network.NewNfTablesChain(network.NamespaceName, "ingress"), + func(chain *network.NfTablesChain) error { + spec := chain.TypedSpec() + + spec.Type = nethelpers.ChainTypeFilter + spec.Hook = nethelpers.ChainHookInput + spec.Priority = nethelpers.ChainPriorityFilter + + // preamble + spec.Rules = []network.NfTablesRule{ + // trusted interfaces: loopback, siderolink and kubespan + { + MatchIIfName: &network.NfTablesIfNameMatch{ + InterfaceName: "lo", + Operator: nethelpers.OperatorEqual, + }, + Verdict: pointer.To(nethelpers.VerdictAccept), + }, + { + MatchIIfName: &network.NfTablesIfNameMatch{ + InterfaceName: constants.SideroLinkName, + Operator: nethelpers.OperatorEqual, + }, + Verdict: pointer.To(nethelpers.VerdictAccept), + }, + { + MatchIIfName: &network.NfTablesIfNameMatch{ + InterfaceName: constants.KubeSpanLinkName, + Operator: nethelpers.OperatorEqual, + }, + Verdict: pointer.To(nethelpers.VerdictAccept), + }, + } + + defaultAction := cfg.Config().NetworkRules().DefaultAction() + + if defaultAction == nethelpers.DefaultActionBlock { + // allow ICMP and ICMPv6 explicitly + spec.Rules = append(spec.Rules, + network.NfTablesRule{ + MatchLayer4: &network.NfTablesLayer4Match{ + Protocol: nethelpers.ProtocolICMP, + }, + Verdict: pointer.To(nethelpers.VerdictAccept), + }, + network.NfTablesRule{ + MatchLayer4: &network.NfTablesLayer4Match{ + Protocol: nethelpers.ProtocolICMPv6, + }, + Verdict: pointer.To(nethelpers.VerdictAccept), + }, + ) + } + + for _, rule := range cfg.Config().NetworkRules().Rules() { + portRanges := rule.PortRanges() + + // sort port ranges, machine config validation ensures that there are no overlaps + slices.SortFunc(portRanges, func(a, b [2]uint16) int { + return cmp.Compare(a[0], b[0]) + }) + + // if default accept, drop anything that doesn't match the rule + verdict := nethelpers.VerdictDrop + + if defaultAction == nethelpers.DefaultActionBlock { + verdict = nethelpers.VerdictAccept + } + + spec.Rules = append(spec.Rules, + network.NfTablesRule{ + MatchSourceAddress: &network.NfTablesAddressMatch{ + IncludeSubnets: rule.Subnets(), + ExcludeSubnets: rule.ExceptSubnets(), + Invert: defaultAction == nethelpers.DefaultActionAccept, + }, + MatchLayer4: &network.NfTablesLayer4Match{ + Protocol: rule.Protocol(), + MatchDestinationPort: &network.NfTablesPortMatch{ + Ranges: xslices.Map(portRanges, func(pr [2]uint16) network.PortRange { + return network.PortRange{Lo: pr[0], Hi: pr[1]} + }), + }, + }, + Verdict: pointer.To(verdict), + }, + ) + } + + if defaultAction == nethelpers.DefaultActionBlock { + // drop everything else + spec.Rules = append(spec.Rules, + network.NfTablesRule{ + Verdict: pointer.To(nethelpers.VerdictDrop), + }, + ) + } + + return nil + }); err != nil { + return err + } + } + + if err = safe.CleanupOutputs[*network.NfTablesChain](ctx, r); err != nil { + return err + } + } +} diff --git a/internal/app/machined/pkg/controllers/network/nftables_chain_test.go b/internal/app/machined/pkg/controllers/network/nftables_chain_test.go index 28c64c38588..d58b84b564d 100644 --- a/internal/app/machined/pkg/controllers/network/nftables_chain_test.go +++ b/internal/app/machined/pkg/controllers/network/nftables_chain_test.go @@ -277,8 +277,51 @@ func (s *NfTablesChainSuite) TestL4Match() { s.checkNftOutput(`table inet talos-test { chain test-tcp { type filter hook input priority filter; policy accept; - ip daddr { 10.0.0.0/8 } tcp dport { 1023-1024, 1027-1028 } drop - ip6 daddr { 2001::/16 } tcp dport { 1023-1024, 1027-1028 } drop + ip daddr { 10.0.0.0/8 } tcp dport { 1023-1025, 1027-1029 } drop + ip6 daddr { 2001::/16 } tcp dport { 1023-1025, 1027-1029 } drop + } +}`) +} + +func (s *NfTablesChainSuite) TestL4Match2() { + chain := network.NewNfTablesChain(network.NamespaceName, "test-tcp") + chain.TypedSpec().Type = nethelpers.ChainTypeFilter + chain.TypedSpec().Hook = nethelpers.ChainHookInput + chain.TypedSpec().Priority = nethelpers.ChainPriorityFilter + chain.TypedSpec().Rules = []network.NfTablesRule{ + { + MatchSourceAddress: &network.NfTablesAddressMatch{ + IncludeSubnets: []netip.Prefix{ + netip.MustParsePrefix("10.0.0.0/8"), + }, + Invert: true, + }, + MatchLayer4: &network.NfTablesLayer4Match{ + Protocol: nethelpers.ProtocolTCP, + MatchDestinationPort: &network.NfTablesPortMatch{ + Ranges: []network.PortRange{ + { + Lo: 1023, + Hi: 1023, + }, + { + Lo: 1024, + Hi: 1024, + }, + }, + }, + }, + Verdict: pointer.To(nethelpers.VerdictDrop), + }, + } + + s.Require().NoError(s.State().Create(s.Ctx(), chain)) + + s.checkNftOutput(`table inet talos-test { + chain test-tcp { + type filter hook input priority filter; policy accept; + ip saddr != { 10.0.0.0/8 } tcp dport { 1023, 1024 } drop + meta nfproto ipv6 tcp dport { 1023, 1024 } drop } }`) } diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go index a6c831bd729..a05962102b0 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go @@ -201,6 +201,7 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error &network.LinkMergeController{}, &network.LinkSpecController{}, &network.LinkStatusController{}, + &network.NfTablesChainConfigController{}, &network.NfTablesChainController{}, &network.NodeAddressController{}, &network.OperatorConfigController{ diff --git a/pkg/machinery/api/resource/definitions/enums/enums.pb.go b/pkg/machinery/api/resource/definitions/enums/enums.pb.go index 92374ebb0bf..48c5737e96c 100644 --- a/pkg/machinery/api/resource/definitions/enums/enums.pb.go +++ b/pkg/machinery/api/resource/definitions/enums/enums.pb.go @@ -1313,21 +1313,27 @@ type NethelpersProtocol int32 const ( NethelpersProtocol_NETHELPERS_PROTOCOL_UNSPECIFIED NethelpersProtocol = 0 + NethelpersProtocol_PROTOCOL_ICMP NethelpersProtocol = 1 NethelpersProtocol_PROTOCOL_TCP NethelpersProtocol = 6 NethelpersProtocol_PROTOCOL_UDP NethelpersProtocol = 17 + NethelpersProtocol_PROTOCOL_ICM_PV6 NethelpersProtocol = 58 ) // Enum value maps for NethelpersProtocol. var ( NethelpersProtocol_name = map[int32]string{ 0: "NETHELPERS_PROTOCOL_UNSPECIFIED", + 1: "PROTOCOL_ICMP", 6: "PROTOCOL_TCP", 17: "PROTOCOL_UDP", + 58: "PROTOCOL_ICM_PV6", } NethelpersProtocol_value = map[string]int32{ "NETHELPERS_PROTOCOL_UNSPECIFIED": 0, + "PROTOCOL_ICMP": 1, "PROTOCOL_TCP": 6, "PROTOCOL_UDP": 17, + "PROTOCOL_ICM_PV6": 58, } ) @@ -2258,134 +2264,136 @@ var file_resource_definitions_enums_enums_proto_rawDesc = []byte{ 0x41, 0x52, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, 0x42, 0x45, 0x54, 0x54, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x52, 0x49, 0x4d, 0x41, 0x52, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, - 0x45, 0x10, 0x02, 0x2a, 0x5d, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, - 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x23, 0x0a, 0x1f, 0x4e, 0x45, 0x54, - 0x48, 0x45, 0x4c, 0x50, 0x45, 0x52, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, - 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x54, 0x43, 0x50, 0x10, 0x06, - 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x55, 0x44, 0x50, - 0x10, 0x11, 0x2a, 0xdf, 0x01, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, - 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x6c, 0x61, 0x67, 0x12, 0x24, 0x0a, 0x20, 0x4e, 0x45, - 0x54, 0x48, 0x45, 0x4c, 0x50, 0x45, 0x52, 0x53, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x46, 0x4c, - 0x41, 0x47, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x11, 0x0a, 0x0c, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x59, - 0x10, 0x80, 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x43, 0x4c, 0x4f, - 0x4e, 0x45, 0x44, 0x10, 0x80, 0x04, 0x12, 0x13, 0x0a, 0x0e, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, - 0x45, 0x51, 0x55, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x10, 0x80, 0x08, 0x12, 0x11, 0x0a, 0x0c, 0x52, - 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x46, 0x49, 0x58, 0x10, 0x80, 0x10, 0x12, 0x17, - 0x0a, 0x12, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x4c, 0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x5f, 0x54, - 0x41, 0x42, 0x4c, 0x45, 0x10, 0x80, 0x20, 0x12, 0x14, 0x0a, 0x0f, 0x52, 0x4f, 0x55, 0x54, 0x45, - 0x5f, 0x46, 0x49, 0x42, 0x5f, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x10, 0x80, 0x40, 0x12, 0x13, 0x0a, - 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x80, - 0x80, 0x01, 0x12, 0x10, 0x0a, 0x0a, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x50, - 0x10, 0x80, 0x80, 0x02, 0x2a, 0xd2, 0x03, 0x0a, 0x17, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, - 0x65, 0x72, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, - 0x4c, 0x5f, 0x52, 0x45, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, - 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4b, 0x45, 0x52, 0x4e, 0x45, 0x4c, 0x10, - 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x42, 0x4f, - 0x4f, 0x54, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x49, 0x43, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, - 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x52, 0x41, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, - 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4d, 0x52, 0x54, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, - 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x5a, 0x45, 0x42, 0x52, 0x41, 0x10, 0x0b, - 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x42, 0x49, 0x52, - 0x44, 0x10, 0x0c, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, - 0x44, 0x4e, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, - 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x58, 0x4f, 0x52, 0x50, 0x10, 0x0e, 0x12, 0x10, 0x0a, - 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4e, 0x54, 0x4b, 0x10, 0x0f, 0x12, - 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x44, 0x48, 0x43, 0x50, - 0x10, 0x10, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4d, - 0x52, 0x54, 0x44, 0x10, 0x11, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, - 0x4c, 0x5f, 0x4b, 0x45, 0x45, 0x50, 0x41, 0x4c, 0x49, 0x56, 0x45, 0x44, 0x10, 0x12, 0x12, 0x12, - 0x0a, 0x0e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x42, 0x41, 0x42, 0x45, 0x4c, - 0x10, 0x2a, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4f, - 0x50, 0x45, 0x4e, 0x52, 0x10, 0x63, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, - 0x4f, 0x4c, 0x5f, 0x42, 0x47, 0x50, 0x10, 0xba, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x52, 0x4f, - 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x49, 0x53, 0x49, 0x53, 0x10, 0xbb, 0x01, 0x12, 0x12, 0x0a, - 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4f, 0x53, 0x50, 0x46, 0x10, 0xbc, - 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x52, 0x49, - 0x50, 0x10, 0xbd, 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, - 0x5f, 0x45, 0x49, 0x47, 0x52, 0x50, 0x10, 0xc0, 0x01, 0x2a, 0xf1, 0x01, 0x0a, 0x13, 0x4e, 0x65, - 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x49, 0x43, 0x41, - 0x53, 0x54, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x4f, 0x43, - 0x41, 0x4c, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x52, 0x4f, - 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x41, 0x4e, 0x59, 0x43, 0x41, 0x53, 0x54, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x43, 0x41, 0x53, 0x54, 0x10, 0x05, 0x12, 0x12, - 0x0a, 0x0e, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x4c, 0x41, 0x43, 0x4b, 0x48, 0x4f, 0x4c, 0x45, - 0x10, 0x06, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x52, 0x45, 0x41, - 0x43, 0x48, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x50, 0x52, 0x4f, 0x48, 0x49, 0x42, 0x49, 0x54, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x54, 0x48, 0x52, 0x4f, 0x57, 0x10, 0x09, 0x12, 0x0c, 0x0a, 0x08, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x41, 0x54, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x58, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x10, 0x0b, 0x2a, 0x61, 0x0a, - 0x16, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x69, - 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x41, 0x42, 0x4c, 0x45, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0d, 0x54, 0x41, 0x42, - 0x4c, 0x45, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0xfd, 0x01, 0x12, 0x0f, 0x0a, - 0x0a, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x10, 0xfe, 0x01, 0x12, 0x10, - 0x0a, 0x0b, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0xff, 0x01, - 0x2a, 0x6a, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x53, 0x63, - 0x6f, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x47, 0x4c, 0x4f, - 0x42, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x53, - 0x49, 0x54, 0x45, 0x10, 0xc8, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, - 0x4c, 0x49, 0x4e, 0x4b, 0x10, 0xfd, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x43, 0x4f, 0x50, 0x45, - 0x5f, 0x48, 0x4f, 0x53, 0x54, 0x10, 0xfe, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x43, 0x4f, 0x50, - 0x45, 0x5f, 0x4e, 0x4f, 0x57, 0x48, 0x45, 0x52, 0x45, 0x10, 0xff, 0x01, 0x2a, 0x78, 0x0a, 0x16, - 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x56, 0x4c, 0x41, 0x4e, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x27, 0x0a, 0x23, 0x4e, 0x45, 0x54, 0x48, 0x45, 0x4c, - 0x50, 0x45, 0x52, 0x53, 0x5f, 0x56, 0x4c, 0x41, 0x4e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, + 0x45, 0x10, 0x02, 0x2a, 0x86, 0x01, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, + 0x72, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x23, 0x0a, 0x1f, 0x4e, 0x45, + 0x54, 0x48, 0x45, 0x4c, 0x50, 0x45, 0x52, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x19, 0x0a, 0x13, 0x56, 0x4c, 0x41, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, - 0x38, 0x30, 0x32, 0x31, 0x5f, 0x51, 0x10, 0x80, 0x82, 0x02, 0x12, 0x1a, 0x0a, 0x14, 0x56, 0x4c, - 0x41, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x38, 0x30, 0x32, 0x31, 0x5f, - 0x41, 0x44, 0x10, 0xa8, 0x91, 0x02, 0x2a, 0x53, 0x0a, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x70, - 0x61, 0x6e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, - 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x2a, 0x88, 0x01, 0x0a, 0x12, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4c, 0x61, 0x79, - 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x44, 0x45, 0x46, - 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, - 0x5f, 0x43, 0x4d, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, - 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x10, 0x02, 0x12, - 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, - 0x4f, 0x52, 0x10, 0x03, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4d, - 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, - 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x2a, 0x4b, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, - 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x34, 0x10, 0x00, 0x12, 0x12, 0x0a, - 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x36, 0x10, - 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x56, 0x49, - 0x50, 0x10, 0x02, 0x2a, 0x9b, 0x02, 0x0a, 0x13, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x4d, - 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4d, - 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, - 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, - 0x47, 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, - 0x1d, 0x0a, 0x19, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, - 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x12, 0x19, - 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, - 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, - 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x42, 0x4f, 0x4f, - 0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, - 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, - 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x54, 0x49, - 0x4e, 0x47, 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, - 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x50, 0x47, 0x52, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, - 0x08, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, - 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, - 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x49, 0x43, 0x4d, 0x50, + 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x54, + 0x43, 0x50, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, + 0x5f, 0x55, 0x44, 0x50, 0x10, 0x11, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, + 0x4f, 0x4c, 0x5f, 0x49, 0x43, 0x4d, 0x5f, 0x50, 0x56, 0x36, 0x10, 0x3a, 0x2a, 0xdf, 0x01, 0x0a, + 0x13, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x46, 0x6c, 0x61, 0x67, 0x12, 0x24, 0x0a, 0x20, 0x4e, 0x45, 0x54, 0x48, 0x45, 0x4c, 0x50, 0x45, + 0x52, 0x53, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x46, 0x4c, 0x41, 0x47, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0c, 0x52, 0x4f, + 0x55, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x59, 0x10, 0x80, 0x02, 0x12, 0x11, 0x0a, + 0x0c, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x80, 0x04, + 0x12, 0x13, 0x0a, 0x0e, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x49, + 0x5a, 0x45, 0x10, 0x80, 0x08, 0x12, 0x11, 0x0a, 0x0c, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x50, + 0x52, 0x45, 0x46, 0x49, 0x58, 0x10, 0x80, 0x10, 0x12, 0x17, 0x0a, 0x12, 0x52, 0x4f, 0x55, 0x54, + 0x45, 0x5f, 0x4c, 0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x80, + 0x20, 0x12, 0x14, 0x0a, 0x0f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x46, 0x49, 0x42, 0x5f, 0x4d, + 0x41, 0x54, 0x43, 0x48, 0x10, 0x80, 0x40, 0x12, 0x13, 0x0a, 0x0d, 0x52, 0x4f, 0x55, 0x54, 0x45, + 0x5f, 0x4f, 0x46, 0x46, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x80, 0x80, 0x01, 0x12, 0x10, 0x0a, 0x0a, + 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x50, 0x10, 0x80, 0x80, 0x02, 0x2a, 0xd2, + 0x03, 0x0a, 0x17, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x52, + 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x10, 0x00, 0x12, + 0x15, 0x0a, 0x11, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x52, 0x45, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, + 0x4f, 0x4c, 0x5f, 0x4b, 0x45, 0x52, 0x4e, 0x45, 0x4c, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x50, + 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x10, 0x03, 0x12, 0x13, + 0x0a, 0x0f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x49, + 0x43, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, + 0x52, 0x41, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, + 0x5f, 0x4d, 0x52, 0x54, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, + 0x4f, 0x4c, 0x5f, 0x5a, 0x45, 0x42, 0x52, 0x41, 0x10, 0x0b, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, + 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x42, 0x49, 0x52, 0x44, 0x10, 0x0c, 0x12, 0x15, 0x0a, + 0x11, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x44, 0x4e, 0x52, 0x4f, 0x55, 0x54, + 0x45, 0x44, 0x10, 0x0d, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, + 0x5f, 0x58, 0x4f, 0x52, 0x50, 0x10, 0x0e, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, + 0x43, 0x4f, 0x4c, 0x5f, 0x4e, 0x54, 0x4b, 0x10, 0x0f, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, + 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x10, 0x10, 0x12, 0x11, 0x0a, 0x0d, + 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4d, 0x52, 0x54, 0x44, 0x10, 0x11, 0x12, + 0x17, 0x0a, 0x13, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4b, 0x45, 0x45, 0x50, + 0x41, 0x4c, 0x49, 0x56, 0x45, 0x44, 0x10, 0x12, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x52, 0x4f, 0x54, + 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x42, 0x41, 0x42, 0x45, 0x4c, 0x10, 0x2a, 0x12, 0x12, 0x0a, 0x0e, + 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x52, 0x10, 0x63, + 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x42, 0x47, 0x50, + 0x10, 0xba, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, + 0x49, 0x53, 0x49, 0x53, 0x10, 0xbb, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x54, 0x4f, + 0x43, 0x4f, 0x4c, 0x5f, 0x4f, 0x53, 0x50, 0x46, 0x10, 0xbc, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x50, + 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x52, 0x49, 0x50, 0x10, 0xbd, 0x01, 0x12, 0x13, + 0x0a, 0x0e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x45, 0x49, 0x47, 0x52, 0x50, + 0x10, 0xc0, 0x01, 0x2a, 0xf1, 0x01, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, + 0x72, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x49, 0x43, 0x41, 0x53, 0x54, 0x10, 0x01, 0x12, 0x0e, + 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x12, + 0x0a, 0x0e, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x52, 0x4f, 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, + 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x4e, 0x59, 0x43, 0x41, + 0x53, 0x54, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x55, 0x4c, + 0x54, 0x49, 0x43, 0x41, 0x53, 0x54, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x42, 0x4c, 0x41, 0x43, 0x4b, 0x48, 0x4f, 0x4c, 0x45, 0x10, 0x06, 0x12, 0x14, 0x0a, 0x10, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x52, 0x45, 0x41, 0x43, 0x48, 0x41, 0x42, 0x4c, 0x45, + 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x48, 0x49, + 0x42, 0x49, 0x54, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x48, + 0x52, 0x4f, 0x57, 0x10, 0x09, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x41, + 0x54, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x58, 0x5f, 0x52, 0x45, + 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x10, 0x0b, 0x2a, 0x61, 0x0a, 0x16, 0x4e, 0x65, 0x74, 0x68, 0x65, + 0x6c, 0x70, 0x65, 0x72, 0x73, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, + 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, + 0x43, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0d, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x44, 0x45, 0x46, + 0x41, 0x55, 0x4c, 0x54, 0x10, 0xfd, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x41, 0x42, 0x4c, 0x45, + 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x10, 0xfe, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x54, 0x41, 0x42, 0x4c, + 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0xff, 0x01, 0x2a, 0x6a, 0x0a, 0x0f, 0x4e, 0x65, + 0x74, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x73, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x10, 0x0a, + 0x0c, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x10, 0x00, 0x12, + 0x0f, 0x0a, 0x0a, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x53, 0x49, 0x54, 0x45, 0x10, 0xc8, 0x01, + 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x10, 0xfd, + 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x48, 0x4f, 0x53, 0x54, 0x10, + 0xfe, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x43, 0x4f, 0x50, 0x45, 0x5f, 0x4e, 0x4f, 0x57, 0x48, + 0x45, 0x52, 0x45, 0x10, 0xff, 0x01, 0x2a, 0x78, 0x0a, 0x16, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x6c, + 0x70, 0x65, 0x72, 0x73, 0x56, 0x4c, 0x41, 0x4e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, + 0x12, 0x27, 0x0a, 0x23, 0x4e, 0x45, 0x54, 0x48, 0x45, 0x4c, 0x50, 0x45, 0x52, 0x53, 0x5f, 0x56, + 0x4c, 0x41, 0x4e, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x13, 0x56, 0x4c, 0x41, + 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x38, 0x30, 0x32, 0x31, 0x5f, 0x51, + 0x10, 0x80, 0x82, 0x02, 0x12, 0x1a, 0x0a, 0x14, 0x56, 0x4c, 0x41, 0x4e, 0x5f, 0x50, 0x52, 0x4f, + 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x38, 0x30, 0x32, 0x31, 0x5f, 0x41, 0x44, 0x10, 0xa8, 0x91, 0x02, + 0x2a, 0x53, 0x0a, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x70, 0x61, 0x6e, 0x50, 0x65, 0x65, 0x72, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, + 0x0d, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x50, 0x10, 0x01, + 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, + 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x2a, 0x88, 0x01, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, + 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, + 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x43, 0x4d, 0x44, 0x4c, 0x49, + 0x4e, 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x50, + 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, + 0x46, 0x49, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x20, + 0x0a, 0x1c, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, + 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, + 0x2a, 0x4b, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, + 0x44, 0x48, 0x43, 0x50, 0x34, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, + 0x54, 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x36, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, + 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x56, 0x49, 0x50, 0x10, 0x02, 0x2a, 0x9b, 0x02, + 0x0a, 0x13, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, + 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, + 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, + 0x45, 0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x4d, + 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x49, 0x4e, 0x53, + 0x54, 0x41, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x41, 0x43, + 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x54, + 0x45, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, + 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, + 0x47, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, + 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, + 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, + 0x45, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, + 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, + 0x47, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x12, 0x1b, + 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, + 0x55, 0x50, 0x47, 0x52, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x42, 0x4a, 0x5a, 0x48, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, + 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, + 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/machinery/config/config/config.go b/pkg/machinery/config/config/config.go index 76b21580c1b..2b8829a4c4f 100644 --- a/pkg/machinery/config/config/config.go +++ b/pkg/machinery/config/config/config.go @@ -12,4 +12,5 @@ type Config interface { Cluster() ClusterConfig SideroLink() SideroLinkConfig Runtime() RuntimeConfig + NetworkRules() NetworkRuleConfig } diff --git a/pkg/machinery/config/config/helpers.go b/pkg/machinery/config/config/helpers.go new file mode 100644 index 00000000000..00d19ee38d1 --- /dev/null +++ b/pkg/machinery/config/config/helpers.go @@ -0,0 +1,39 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package config + +func findFirstValue[T any, R comparable](documents []T, getter func(T) R) R { + var zeroR R + + for _, document := range documents { + if value := getter(document); value != zeroR { + return value + } + } + + return zeroR +} + +func aggregateValues[T any, R any](documents []T, getter func(T) []R) []R { + var result []R + + for _, document := range documents { + result = append(result, getter(document)...) + } + + return result +} + +func filterDocuments[T any, R any](documents []R) []T { + var result []T + + for _, document := range documents { + if document, ok := any(document).(T); ok { + result = append(result, document) + } + } + + return result +} diff --git a/pkg/machinery/config/config/network.go b/pkg/machinery/config/config/network.go new file mode 100644 index 00000000000..a67aa753523 --- /dev/null +++ b/pkg/machinery/config/config/network.go @@ -0,0 +1,66 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package config + +import ( + "net/netip" + + "github.com/siderolabs/talos/pkg/machinery/nethelpers" +) + +// NetworkRuleConfig defines the interface to access network firewall configuration. +type NetworkRuleConfig interface { + NetworkRuleConfigRules + NetworkRuleConfigDefaultAction +} + +// NetworkRuleConfigRules defines the interface to access network firewall configuration. +type NetworkRuleConfigRules interface { + Rules() []NetworkRule +} + +// NetworkRuleConfigDefaultAction defines the interface to access network firewall configuration. +type NetworkRuleConfigDefaultAction interface { + DefaultAction() nethelpers.DefaultAction +} + +// NetworkRuleConfigSignal is used to signal documents which implement either of the NetworkRuleConfig interfaces. +type NetworkRuleConfigSignal interface { + NetworkRuleConfigSignal() +} + +// NetworkRule defines a network firewall rule. +type NetworkRule interface { + Protocol() nethelpers.Protocol + PortRanges() [][2]uint16 + Subnets() []netip.Prefix + ExceptSubnets() []netip.Prefix +} + +// WrapNetworkRuleConfigList wraps a list of NetworkConfig into a single NetworkConfig aggregating the results. +func WrapNetworkRuleConfigList(configs ...NetworkRuleConfigSignal) NetworkRuleConfig { + return networkRuleConfigWrapper(configs) +} + +type networkRuleConfigWrapper []NetworkRuleConfigSignal + +func (w networkRuleConfigWrapper) DefaultAction() nethelpers.DefaultAction { + // DefaultAction zero value is 'accept' which is the default config value as well. + return findFirstValue( + filterDocuments[NetworkRuleConfigDefaultAction](w), + func(c NetworkRuleConfigDefaultAction) nethelpers.DefaultAction { + return c.DefaultAction() + }, + ) +} + +func (w networkRuleConfigWrapper) Rules() []NetworkRule { + return aggregateValues( + filterDocuments[NetworkRuleConfigRules](w), + func(c NetworkRuleConfigRules) []NetworkRule { + return c.Rules() + }, + ) +} diff --git a/pkg/machinery/config/config/runtime.go b/pkg/machinery/config/config/runtime.go index 35ca359013a..3f75581087b 100644 --- a/pkg/machinery/config/config/runtime.go +++ b/pkg/machinery/config/config/runtime.go @@ -30,23 +30,3 @@ func (w runtimeConfigWrapper) KmsgLogURLs() []*url.URL { return c.KmsgLogURLs() }) } - -func findFirstValue[T any, R any](documents []T, getter func(T) *R) *R { - for _, document := range documents { - if value := getter(document); value != nil { - return value - } - } - - return nil -} - -func aggregateValues[T any, R any](documents []T, getter func(T) []R) []R { - var result []R - - for _, document := range documents { - result = append(result, getter(document)...) - } - - return result -} diff --git a/pkg/machinery/config/container/container.go b/pkg/machinery/config/container/container.go index 9a0ebd760fa..8226a48096c 100644 --- a/pkg/machinery/config/container/container.go +++ b/pkg/machinery/config/container/container.go @@ -155,6 +155,11 @@ func (container *Container) Runtime() config.RuntimeConfig { return config.WrapRuntimeConfigList(findMatchingDocs[config.RuntimeConfig](container.documents)...) } +// NetworkRules implements config.Config interface. +func (container *Container) NetworkRules() config.NetworkRuleConfig { + return config.WrapNetworkRuleConfigList(findMatchingDocs[config.NetworkRuleConfigSignal](container.documents)...) +} + // Bytes returns source YAML representation (if available) or does default encoding. func (container *Container) Bytes() ([]byte, error) { if !container.readonly { diff --git a/pkg/machinery/config/encoder/encoder.go b/pkg/machinery/config/encoder/encoder.go index 80c8f6f34a3..c18ea469853 100644 --- a/pkg/machinery/config/encoder/encoder.go +++ b/pkg/machinery/config/encoder/encoder.go @@ -5,6 +5,7 @@ package encoder import ( + "encoding" "reflect" "sort" "strings" @@ -134,6 +135,10 @@ func toYamlNode(in interface{}, options *Options) (*yaml.Node, error) { in = res } + if _, ok := in.(encoding.TextMarshaler); ok && !isNil(reflect.ValueOf(in)) { + return node, node.Encode(in) + } + v := reflect.ValueOf(in) if v.Kind() == reflect.Ptr { v = v.Elem() diff --git a/pkg/machinery/config/types/network/deep_copy.generated.go b/pkg/machinery/config/types/network/deep_copy.generated.go new file mode 100644 index 00000000000..6af50d5e546 --- /dev/null +++ b/pkg/machinery/config/types/network/deep_copy.generated.go @@ -0,0 +1,27 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Code generated by "deep-copy -type DefaultActionConfigV1Alpha1 -type RuleConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. + +package network + +// DeepCopy generates a deep copy of *DefaultActionConfigV1Alpha1. +func (o *DefaultActionConfigV1Alpha1) DeepCopy() *DefaultActionConfigV1Alpha1 { + var cp DefaultActionConfigV1Alpha1 = *o + return &cp +} + +// DeepCopy generates a deep copy of *RuleConfigV1Alpha1. +func (o *RuleConfigV1Alpha1) DeepCopy() *RuleConfigV1Alpha1 { + var cp RuleConfigV1Alpha1 = *o + if o.PortSelector.Ports != nil { + cp.PortSelector.Ports = make([]PortRange, len(o.PortSelector.Ports)) + copy(cp.PortSelector.Ports, o.PortSelector.Ports) + } + if o.Ingress != nil { + cp.Ingress = make([]IngressRule, len(o.Ingress)) + copy(cp.Ingress, o.Ingress) + } + return &cp +} diff --git a/pkg/machinery/config/types/network/default_action_config.go b/pkg/machinery/config/types/network/default_action_config.go new file mode 100644 index 00000000000..af0b916950f --- /dev/null +++ b/pkg/machinery/config/types/network/default_action_config.go @@ -0,0 +1,62 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package network + +import ( + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/internal/registry" + "github.com/siderolabs/talos/pkg/machinery/config/types/meta" + "github.com/siderolabs/talos/pkg/machinery/nethelpers" +) + +// DefaultActionConfig is a default action config document kind. +const DefaultActionConfig = "NetworkDefaultActionConfig" + +func init() { + registry.Register(DefaultActionConfig, func(version string) config.Document { + switch version { + case "v1alpha1": + return &DefaultActionConfigV1Alpha1{} + default: + return nil + } + }) +} + +// Check interfaces. +var ( + _ config.NetworkRuleConfigDefaultAction = &DefaultActionConfigV1Alpha1{} + _ config.NetworkRuleConfigSignal = &DefaultActionConfigV1Alpha1{} +) + +// DefaultActionConfigV1Alpha1 is a event sink config document. +type DefaultActionConfigV1Alpha1 struct { + meta.Meta `yaml:",inline"` + + Ingress nethelpers.DefaultAction `yaml:"ingress"` +} + +// NewDefaultActionConfigV1Alpha1 creates a new DefaultActionConfig config document. +func NewDefaultActionConfigV1Alpha1() *DefaultActionConfigV1Alpha1 { + return &DefaultActionConfigV1Alpha1{ + Meta: meta.Meta{ + MetaKind: DefaultActionConfig, + MetaAPIVersion: "v1alpha1", + }, + } +} + +// Clone implements config.Document interface. +func (s *DefaultActionConfigV1Alpha1) Clone() config.Document { + return s.DeepCopy() +} + +// NetworkRuleConfigSignal implements config.NetworkRuleConfigSignal interface. +func (s *DefaultActionConfigV1Alpha1) NetworkRuleConfigSignal() {} + +// DefaultAction implements config.NetworkRuleConfigDefaultAction interface. +func (s *DefaultActionConfigV1Alpha1) DefaultAction() nethelpers.DefaultAction { + return s.Ingress +} diff --git a/pkg/machinery/config/types/network/default_action_config_test.go b/pkg/machinery/config/types/network/default_action_config_test.go new file mode 100644 index 00000000000..b89591cc3cd --- /dev/null +++ b/pkg/machinery/config/types/network/default_action_config_test.go @@ -0,0 +1,54 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package network_test + +import ( + _ "embed" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/siderolabs/talos/pkg/machinery/config/configloader" + "github.com/siderolabs/talos/pkg/machinery/config/encoder" + "github.com/siderolabs/talos/pkg/machinery/config/types/meta" + "github.com/siderolabs/talos/pkg/machinery/config/types/network" + "github.com/siderolabs/talos/pkg/machinery/nethelpers" +) + +//go:embed testdata/defaultactionconfig.yaml +var expectedDefaultActionConfigDocument []byte + +func TestDefaultActionConfigMarshalStability(t *testing.T) { + t.Parallel() + + cfg := network.NewDefaultActionConfigV1Alpha1() + cfg.Ingress = nethelpers.DefaultActionBlock + + marshaled, err := encoder.NewEncoder(cfg).Encode() + require.NoError(t, err) + + t.Log(string(marshaled)) + + assert.Equal(t, expectedDefaultActionConfigDocument, marshaled) +} + +func TestDefaultActionConfigUnmarshal(t *testing.T) { + t.Parallel() + + provider, err := configloader.NewFromBytes(expectedDefaultActionConfigDocument) + require.NoError(t, err) + + docs := provider.Documents() + require.Len(t, docs, 1) + + assert.Equal(t, &network.DefaultActionConfigV1Alpha1{ + Meta: meta.Meta{ + MetaAPIVersion: "v1alpha1", + MetaKind: network.DefaultActionConfig, + }, + Ingress: nethelpers.DefaultActionBlock, + }, docs[0]) +} diff --git a/pkg/machinery/config/types/network/network.go b/pkg/machinery/config/types/network/network.go new file mode 100644 index 00000000000..0210ac9a642 --- /dev/null +++ b/pkg/machinery/config/types/network/network.go @@ -0,0 +1,8 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package network provides Talos network config documents. +package network + +//go:generate deep-copy -type DefaultActionConfigV1Alpha1 -type RuleConfigV1Alpha1 -pointer-receiver -header-file ../../../../../hack/boilerplate.txt -o deep_copy.generated.go . diff --git a/pkg/machinery/config/types/network/port_range.go b/pkg/machinery/config/types/network/port_range.go new file mode 100644 index 00000000000..da343ab29ac --- /dev/null +++ b/pkg/machinery/config/types/network/port_range.go @@ -0,0 +1,102 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package network provides Talos network config documents. +package network + +import ( + "cmp" + "fmt" + "slices" + "strconv" + "strings" +) + +// PortRange is a port range. +type PortRange struct { + Lo uint16 + Hi uint16 +} + +// UnmarshalYAML is a custom unmarshaller for `PortRange`. +func (pr *PortRange) UnmarshalYAML(unmarshal func(any) error) error { + var port uint16 + + if err := unmarshal(&port); err == nil { + pr.Lo = port + pr.Hi = port + + return nil + } + + var rangeStr string + + if err := unmarshal(&rangeStr); err != nil { + return err + } + + lo, hi, ok := strings.Cut(rangeStr, "-") + if !ok { + return fmt.Errorf("invalid port range: %q", rangeStr) + } + + prLo, err := strconv.ParseUint(lo, 10, 16) + if err != nil { + return fmt.Errorf("invalid port range: %q", rangeStr) + } + + prHi, err := strconv.ParseUint(hi, 10, 16) + if err != nil { + return fmt.Errorf("invalid port range: %q", rangeStr) + } + + pr.Lo, pr.Hi = uint16(prLo), uint16(prHi) + + return nil +} + +// MarshalYAML is a custom marshaller for `PortRange`. +func (pr PortRange) MarshalYAML() (any, error) { + if pr.Lo == pr.Hi { + return pr.Lo, nil + } + + return fmt.Sprintf("%d-%d", pr.Lo, pr.Hi), nil +} + +// String implements fmt.Stringer interface. +func (pr PortRange) String() string { + return fmt.Sprintf("%d-%d", pr.Lo, pr.Hi) +} + +// PortRanges is a slice of port ranges. +type PortRanges []PortRange + +// Validate the port ranges. +func (prs PortRanges) Validate() error { + clone := slices.Clone(prs) + slices.SortFunc(clone, func(a, b PortRange) int { + return cmp.Compare(a.Lo, b.Lo) + }) + + for i, pr := range clone { + if pr.Lo > pr.Hi { + return fmt.Errorf("invalid port range: %s", pr) + } + + if i > 0 { + prev := clone[i-1] + + if pr.Lo == prev.Lo { + return fmt.Errorf("invalid port range: %s", pr) + } + + if pr.Lo <= prev.Hi { + return fmt.Errorf("invalid port range: %s", pr) + } + } + } + + return nil +} diff --git a/pkg/machinery/config/types/network/port_range_test.go b/pkg/machinery/config/types/network/port_range_test.go new file mode 100644 index 00000000000..79b42917e0b --- /dev/null +++ b/pkg/machinery/config/types/network/port_range_test.go @@ -0,0 +1,124 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package network_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" + + "github.com/siderolabs/talos/pkg/machinery/config/types/network" +) + +func TestPortRange(t *testing.T) { + t.Run("MarshalYAML", func(t *testing.T) { + for _, test := range []struct { + name string + pr network.PortRange + + expected string + }{ + { + name: "single port", + pr: network.PortRange{Lo: 80, Hi: 80}, + + expected: "80\n", + }, + { + name: "port range", + pr: network.PortRange{Lo: 80, Hi: 443}, + + expected: "80-443\n", + }, + } { + t.Run(test.name, func(t *testing.T) { + marshaled, err := yaml.Marshal(test.pr) + require.NoError(t, err) + + assert.Equal(t, test.expected, string(marshaled)) + }) + } + }) + + t.Run("UnmarshalYAML", func(t *testing.T) { + for _, test := range []struct { + name string + yaml string + + expected network.PortRange + }{ + { + name: "single port", + yaml: "80\n", + + expected: network.PortRange{Lo: 80, Hi: 80}, + }, + { + name: "port range", + yaml: "80-443\n", + + expected: network.PortRange{Lo: 80, Hi: 443}, + }, + } { + t.Run(test.name, func(t *testing.T) { + var pr network.PortRange + + err := yaml.Unmarshal([]byte(test.yaml), &pr) + require.NoError(t, err) + + assert.Equal(t, test.expected, pr) + }) + } + }) +} + +func TestPortRanges(t *testing.T) { + t.Run("Validate", func(t *testing.T) { + for _, test := range []struct { + name string + prs network.PortRanges + + expectedError string + }{ + { + name: "empty", + prs: network.PortRanges{}, + }, + { + name: "valid", + prs: network.PortRanges{{Lo: 80, Hi: 80}, {Lo: 443, Hi: 443}, {Lo: 8080, Hi: 8081}}, + }, + { + name: "inversion", + prs: network.PortRanges{{Lo: 8081, Hi: 8080}}, + + expectedError: "invalid port range: 8081-8080", + }, + { + name: "overlap", + prs: network.PortRanges{{Lo: 1000, Hi: 2000}, {Lo: 80, Hi: 80}, {Lo: 1500, Hi: 2500}}, + + expectedError: "invalid port range: 1500-2500", + }, + { + name: "duplicate", + prs: network.PortRanges{{Lo: 1000, Hi: 1000}, {Lo: 80, Hi: 80}, {Lo: 1000, Hi: 1000}}, + + expectedError: "invalid port range: 1000-1000", + }, + } { + t.Run(test.name, func(t *testing.T) { + err := test.prs.Validate() + if test.expectedError != "" { + require.EqualError(t, err, test.expectedError) + } else { + require.NoError(t, err) + } + }) + } + }) +} diff --git a/pkg/machinery/config/types/network/rule_config.go b/pkg/machinery/config/types/network/rule_config.go new file mode 100644 index 00000000000..d3995e62a13 --- /dev/null +++ b/pkg/machinery/config/types/network/rule_config.go @@ -0,0 +1,154 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package network + +import ( + "fmt" + "net/netip" + + "github.com/siderolabs/gen/value" + "github.com/siderolabs/gen/xslices" + + "github.com/siderolabs/talos/pkg/machinery/config/config" + "github.com/siderolabs/talos/pkg/machinery/config/internal/registry" + "github.com/siderolabs/talos/pkg/machinery/config/types/meta" + "github.com/siderolabs/talos/pkg/machinery/config/validation" + "github.com/siderolabs/talos/pkg/machinery/nethelpers" +) + +// RuleConfigKind is a rule config document kind. +const RuleConfigKind = "NetworkRuleConfig" + +func init() { + registry.Register(RuleConfigKind, func(version string) config.Document { + switch version { + case "v1alpha1": + return &RuleConfigV1Alpha1{} + default: + return nil + } + }) +} + +// Check interfaces. +var ( + _ config.NetworkRuleConfigRules = &RuleConfigV1Alpha1{} + _ config.NetworkRuleConfigSignal = &RuleConfigV1Alpha1{} + _ config.NamedDocument = &RuleConfigV1Alpha1{} + _ config.Validator = &RuleConfigV1Alpha1{} +) + +// RuleConfigV1Alpha1 is a network firewall rule config document. +type RuleConfigV1Alpha1 struct { + meta.Meta `yaml:",inline"` + MetaName string `yaml:"name"` + + PortSelector RulePortSelector `yaml:"portSelector"` + Ingress IngressConfig `yaml:"ingress"` +} + +// RulePortSelector is a port selector for the network rule. +type RulePortSelector struct { + Ports PortRanges `yaml:"ports"` + Protocol nethelpers.Protocol `yaml:"protocol"` +} + +// IngressConfig is a ingress config. +type IngressConfig []IngressRule + +// IngressRule is a ingress rule. +type IngressRule struct { + Subnet netip.Prefix `yaml:"subnet"` + Except netip.Prefix `yaml:"except,omitempty"` +} + +// NewRuleConfigV1Alpha1 creates a new RuleConfig config document. +func NewRuleConfigV1Alpha1() *RuleConfigV1Alpha1 { + return &RuleConfigV1Alpha1{ + Meta: meta.Meta{ + MetaKind: RuleConfigKind, + MetaAPIVersion: "v1alpha1", + }, + } +} + +// Name implements config.NamedDocument interface. +func (s *RuleConfigV1Alpha1) Name() string { + return s.MetaName +} + +// Clone implements config.Document interface. +func (s *RuleConfigV1Alpha1) Clone() config.Document { + return s.DeepCopy() +} + +// Validate implements config.Validator interface. +func (s *RuleConfigV1Alpha1) Validate(validation.RuntimeMode, ...validation.Option) ([]string, error) { + if s.MetaName == "" { + return nil, fmt.Errorf("name is required") + } + + if len(s.PortSelector.Ports) == 0 { + return nil, fmt.Errorf("portSelector.ports is required") + } + + if err := s.PortSelector.Ports.Validate(); err != nil { + return nil, err + } + + for _, rule := range s.Ingress { + if !rule.Subnet.IsValid() { + return nil, fmt.Errorf("invalid subnet: %s", rule.Subnet) + } + + if !value.IsZero(rule.Except) && !rule.Except.IsValid() { + return nil, fmt.Errorf("invalid except: %s", rule.Except) + } + } + + return nil, nil +} + +// NetworkRuleConfigSignal implements config.NetworkRuleConfigSignal interface. +func (s *RuleConfigV1Alpha1) NetworkRuleConfigSignal() {} + +// Rules implements config.NetworkRuleConfigRules interface. +func (s *RuleConfigV1Alpha1) Rules() []config.NetworkRule { + return []config.NetworkRule{s} +} + +// Protocol implements config.NetworkRule interface. +func (s *RuleConfigV1Alpha1) Protocol() nethelpers.Protocol { + return s.PortSelector.Protocol +} + +// PortRanges implements config.NetworkRule interface. +func (s *RuleConfigV1Alpha1) PortRanges() [][2]uint16 { + return xslices.Map(s.PortSelector.Ports, func(pr PortRange) [2]uint16 { + return [2]uint16{pr.Lo, pr.Hi} + }) +} + +// Subnets implements config.NetworkRule interface. +func (s *RuleConfigV1Alpha1) Subnets() []netip.Prefix { + return xslices.Map(s.Ingress, func(rule IngressRule) netip.Prefix { + return rule.Subnet + }) +} + +// ExceptSubnets implements config.NetworkRule interface. +func (s *RuleConfigV1Alpha1) ExceptSubnets() []netip.Prefix { + return xslices.Map( + xslices.Filter( + s.Ingress, + func(rule IngressRule) bool { + return rule.Except.IsValid() + }, + ), + func(rule IngressRule) netip.Prefix { + return rule.Except + }, + ) +} diff --git a/pkg/machinery/config/types/network/rule_config_test.go b/pkg/machinery/config/types/network/rule_config_test.go new file mode 100644 index 00000000000..1605155ffa8 --- /dev/null +++ b/pkg/machinery/config/types/network/rule_config_test.go @@ -0,0 +1,199 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package network_test + +import ( + _ "embed" + "net/netip" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/siderolabs/talos/pkg/machinery/config/configloader" + "github.com/siderolabs/talos/pkg/machinery/config/encoder" + "github.com/siderolabs/talos/pkg/machinery/config/types/meta" + "github.com/siderolabs/talos/pkg/machinery/config/types/network" + "github.com/siderolabs/talos/pkg/machinery/nethelpers" +) + +//go:embed testdata/ruleconfig.yaml +var expectedRuleConfigDocument []byte + +func TestRuleConfigMarshalStability(t *testing.T) { + t.Parallel() + + cfg := network.NewRuleConfigV1Alpha1() + cfg.MetaName = "test" + + cfg.PortSelector = network.RulePortSelector{ + Protocol: nethelpers.ProtocolUDP, + Ports: network.PortRanges{ + {Lo: 53, Hi: 53}, + {Lo: 8000, Hi: 9000}, + }, + } + + cfg.Ingress = network.IngressConfig{ + { + Subnet: netip.MustParsePrefix("192.168.0.0/16"), + Except: netip.MustParsePrefix("192.168.0.3/32"), + }, + { + Subnet: netip.MustParsePrefix("2001::/16"), + }, + } + + marshaled, err := encoder.NewEncoder(cfg).Encode() + require.NoError(t, err) + + t.Log(string(marshaled)) + + assert.Equal(t, expectedRuleConfigDocument, marshaled) +} + +func TestRuleConfigUnmarshal(t *testing.T) { + t.Parallel() + + provider, err := configloader.NewFromBytes(expectedRuleConfigDocument) + require.NoError(t, err) + + docs := provider.Documents() + require.Len(t, docs, 1) + + assert.Equal(t, &network.RuleConfigV1Alpha1{ + Meta: meta.Meta{ + MetaAPIVersion: "v1alpha1", + MetaKind: network.RuleConfigKind, + }, + MetaName: "test", + PortSelector: network.RulePortSelector{ + Protocol: nethelpers.ProtocolUDP, + Ports: network.PortRanges{ + {Lo: 53, Hi: 53}, + {Lo: 8000, Hi: 9000}, + }, + }, + Ingress: network.IngressConfig{ + { + Subnet: netip.MustParsePrefix("192.168.0.0/16"), + Except: netip.MustParsePrefix("192.168.0.3/32"), + }, + { + Subnet: netip.MustParsePrefix("2001::/16"), + }, + }, + }, docs[0]) +} + +func TestRuleConfigValidate(t *testing.T) { + t.Parallel() + + for _, test := range []struct { + name string + cfg func() *network.RuleConfigV1Alpha1 + + expectedError string + expectedWarnings []string + }{ + { + name: "empty", + cfg: network.NewRuleConfigV1Alpha1, + + expectedError: "name is required", + }, + { + name: "no ports", + cfg: func() *network.RuleConfigV1Alpha1 { + cfg := network.NewRuleConfigV1Alpha1() + cfg.MetaName = "-" + + return cfg + }, + + expectedError: "portSelector.ports is required", + }, + { + name: "invalid port range", + cfg: func() *network.RuleConfigV1Alpha1 { + cfg := network.NewRuleConfigV1Alpha1() + cfg.MetaName = "-" + cfg.PortSelector.Ports = network.PortRanges{ + {Lo: 80, Hi: 80}, + {Lo: 80, Hi: 79}, + } + + return cfg + }, + + expectedError: "invalid port range: 80-79", + }, + { + name: "invalid subnet", + cfg: func() *network.RuleConfigV1Alpha1 { + cfg := network.NewRuleConfigV1Alpha1() + cfg.MetaName = "--" + cfg.PortSelector.Ports = network.PortRanges{ + {Lo: 80, Hi: 80}, + } + cfg.Ingress = network.IngressConfig{ + {}, + } + + return cfg + }, + + expectedError: "invalid subnet: invalid Prefix", + }, + { + name: "valid", + cfg: func() *network.RuleConfigV1Alpha1 { + cfg := network.NewRuleConfigV1Alpha1() + cfg.MetaName = "--" + cfg.PortSelector.Ports = network.PortRanges{ + {Lo: 80, Hi: 80}, + {Lo: 6443, Hi: 6444}, + } + cfg.Ingress = network.IngressConfig{ + { + Subnet: netip.MustParsePrefix("192.168.0.0/16"), + Except: netip.MustParsePrefix("192.168.3.0/24"), + }, + { + Subnet: netip.MustParsePrefix("2001::/16"), + }, + } + + return cfg + }, + }, + } { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + warnings, err := test.cfg().Validate(validationMode{}) + + assert.Equal(t, test.expectedWarnings, warnings) + + if test.expectedError != "" { + assert.EqualError(t, err, test.expectedError) + } else { + assert.NoError(t, err) + } + }) + } +} + +type validationMode struct{} + +func (validationMode) String() string { + return "" +} + +func (validationMode) RequiresInstall() bool { + return false +} diff --git a/pkg/machinery/config/types/network/testdata/defaultactionconfig.yaml b/pkg/machinery/config/types/network/testdata/defaultactionconfig.yaml new file mode 100644 index 00000000000..b306fde3746 --- /dev/null +++ b/pkg/machinery/config/types/network/testdata/defaultactionconfig.yaml @@ -0,0 +1,3 @@ +apiVersion: v1alpha1 +kind: NetworkDefaultActionConfig +ingress: block diff --git a/pkg/machinery/config/types/network/testdata/ruleconfig.yaml b/pkg/machinery/config/types/network/testdata/ruleconfig.yaml new file mode 100644 index 00000000000..dce08527f3d --- /dev/null +++ b/pkg/machinery/config/types/network/testdata/ruleconfig.yaml @@ -0,0 +1,12 @@ +apiVersion: v1alpha1 +kind: NetworkRuleConfig +name: test +portSelector: + ports: + - 53 + - 8000-9000 + protocol: udp +ingress: + - subnet: 192.168.0.0/16 + except: 192.168.0.3/32 + - subnet: 2001::/16 diff --git a/pkg/machinery/config/types/runtime/event_sink_test.go b/pkg/machinery/config/types/runtime/event_sink_test.go index 3cb34a4495a..50abb0f09e9 100644 --- a/pkg/machinery/config/types/runtime/event_sink_test.go +++ b/pkg/machinery/config/types/runtime/event_sink_test.go @@ -85,14 +85,6 @@ func TestEventSinkValidate(t *testing.T) { } } -func must[T any](t T, err error) T { - if err != nil { - panic(err) - } - - return t -} - type validationMode struct{} func (validationMode) String() string { diff --git a/pkg/machinery/config/types/runtime/kmsg_log_test.go b/pkg/machinery/config/types/runtime/kmsg_log_test.go index 3902f34012b..486283e47e4 100644 --- a/pkg/machinery/config/types/runtime/kmsg_log_test.go +++ b/pkg/machinery/config/types/runtime/kmsg_log_test.go @@ -9,6 +9,7 @@ import ( "net/url" "testing" + "github.com/siderolabs/gen/ensure" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,7 +23,7 @@ var expectedKmsgLogDocument []byte func TestKmsgLogMarshalStability(t *testing.T) { cfg := runtime.NewKmsgLogV1Alpha1() cfg.MetaName = "apiSink" - cfg.KmsgLogURL.URL = must(url.Parse("https://kmsglog.api/logs")) + cfg.KmsgLogURL.URL = ensure.Value(url.Parse("https://kmsglog.api/logs")) marshaled, err := encoder.NewEncoder(cfg).Encode() require.NoError(t, err) @@ -64,7 +65,7 @@ func TestKmsgLogValidate(t *testing.T) { cfg: func() *runtime.KmsgLogV1Alpha1 { cfg := runtime.NewKmsgLogV1Alpha1() cfg.MetaName = "name2" - cfg.KmsgLogURL.URL = must(url.Parse("https://some.destination/path")) + cfg.KmsgLogURL.URL = ensure.Value(url.Parse("https://some.destination/path")) return cfg }, @@ -76,7 +77,7 @@ func TestKmsgLogValidate(t *testing.T) { cfg: func() *runtime.KmsgLogV1Alpha1 { cfg := runtime.NewKmsgLogV1Alpha1() cfg.MetaName = "name5" - cfg.KmsgLogURL.URL = must(url.Parse("tcp://some.destination:34/path")) + cfg.KmsgLogURL.URL = ensure.Value(url.Parse("tcp://some.destination:34/path")) return cfg }, @@ -88,7 +89,7 @@ func TestKmsgLogValidate(t *testing.T) { cfg: func() *runtime.KmsgLogV1Alpha1 { cfg := runtime.NewKmsgLogV1Alpha1() cfg.MetaName = "name6" - cfg.KmsgLogURL.URL = must(url.Parse("tcp://some.destination/")) + cfg.KmsgLogURL.URL = ensure.Value(url.Parse("tcp://some.destination/")) return cfg }, @@ -100,7 +101,7 @@ func TestKmsgLogValidate(t *testing.T) { cfg: func() *runtime.KmsgLogV1Alpha1 { cfg := runtime.NewKmsgLogV1Alpha1() cfg.MetaName = "name3" - cfg.KmsgLogURL.URL = must(url.Parse("tcp://10.2.3.4:5000/")) + cfg.KmsgLogURL.URL = ensure.Value(url.Parse("tcp://10.2.3.4:5000/")) return cfg }, @@ -110,7 +111,7 @@ func TestKmsgLogValidate(t *testing.T) { cfg: func() *runtime.KmsgLogV1Alpha1 { cfg := runtime.NewKmsgLogV1Alpha1() cfg.MetaName = "name4" - cfg.KmsgLogURL.URL = must(url.Parse("udp://10.2.3.4:5000/")) + cfg.KmsgLogURL.URL = ensure.Value(url.Parse("udp://10.2.3.4:5000/")) return cfg }, diff --git a/pkg/machinery/config/types/siderolink/siderolink_test.go b/pkg/machinery/config/types/siderolink/siderolink_test.go index 830ccb21acf..e86daab2242 100644 --- a/pkg/machinery/config/types/siderolink/siderolink_test.go +++ b/pkg/machinery/config/types/siderolink/siderolink_test.go @@ -9,6 +9,7 @@ import ( "net/url" "testing" + "github.com/siderolabs/gen/ensure" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -20,7 +21,7 @@ func TestRedact(t *testing.T) { t.Parallel() cfg := siderolink.NewConfigV1Alpha1() - cfg.APIUrlConfig.URL = must(url.Parse("https://siderolink.api/join?jointoken=secret&user=alice")) + cfg.APIUrlConfig.URL = ensure.Value(url.Parse("https://siderolink.api/join?jointoken=secret&user=alice")) assert.Equal(t, "https://siderolink.api/join?jointoken=secret&user=alice", cfg.SideroLink().APIUrl().String()) @@ -36,7 +37,7 @@ func TestMarshalStability(t *testing.T) { t.Parallel() cfg := siderolink.NewConfigV1Alpha1() - cfg.APIUrlConfig.URL = must(url.Parse("https://siderolink.api/join?jointoken=secret&user=alice")) + cfg.APIUrlConfig.URL = ensure.Value(url.Parse("https://siderolink.api/join?jointoken=secret&user=alice")) marshaled, err := encoder.NewEncoder(cfg).Encode() require.NoError(t, err) @@ -64,7 +65,7 @@ func TestValidate(t *testing.T) { name: "wrong scheme", cfg: func() *siderolink.ConfigV1Alpha1 { cfg := siderolink.NewConfigV1Alpha1() - cfg.APIUrlConfig.URL = must(url.Parse("http://siderolink.api/")) + cfg.APIUrlConfig.URL = ensure.Value(url.Parse("http://siderolink.api/")) return cfg }, @@ -75,7 +76,7 @@ func TestValidate(t *testing.T) { name: "extra path", cfg: func() *siderolink.ConfigV1Alpha1 { cfg := siderolink.NewConfigV1Alpha1() - cfg.APIUrlConfig.URL = must(url.Parse("grpc://siderolink.api/path?jointoken=foo")) + cfg.APIUrlConfig.URL = ensure.Value(url.Parse("grpc://siderolink.api/path?jointoken=foo")) return cfg }, @@ -86,7 +87,7 @@ func TestValidate(t *testing.T) { name: "valid", cfg: func() *siderolink.ConfigV1Alpha1 { cfg := siderolink.NewConfigV1Alpha1() - cfg.APIUrlConfig.URL = must(url.Parse("https://siderolink.api:434/?jointoken=foo")) + cfg.APIUrlConfig.URL = ensure.Value(url.Parse("https://siderolink.api:434/?jointoken=foo")) return cfg }, @@ -110,14 +111,6 @@ func TestValidate(t *testing.T) { } } -func must[T any](t T, err error) T { - if err != nil { - panic(err) - } - - return t -} - type validationMode struct{} func (validationMode) String() string { diff --git a/pkg/machinery/config/types/types.go b/pkg/machinery/config/types/types.go index 79a37f51e28..fdcbfa75cf9 100644 --- a/pkg/machinery/config/types/types.go +++ b/pkg/machinery/config/types/types.go @@ -6,6 +6,7 @@ package types import ( + _ "github.com/siderolabs/talos/pkg/machinery/config/types/network" // import config types to register them _ "github.com/siderolabs/talos/pkg/machinery/config/types/runtime" // import config types to register them _ "github.com/siderolabs/talos/pkg/machinery/config/types/siderolink" // import config types to register them _ "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" // import config types to register them diff --git a/pkg/machinery/nethelpers/default_action.go b/pkg/machinery/nethelpers/default_action.go new file mode 100644 index 00000000000..396353d0a40 --- /dev/null +++ b/pkg/machinery/nethelpers/default_action.go @@ -0,0 +1,16 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package nethelpers + +//go:generate enumer -type=DefaultAction -linecomment -text + +// DefaultAction is a default firewall action. +type DefaultAction int + +// DefaultAction constants. +const ( + DefaultActionAccept DefaultAction = iota // accept + DefaultActionBlock // block +) diff --git a/pkg/machinery/nethelpers/defaultaction_enumer.go b/pkg/machinery/nethelpers/defaultaction_enumer.go new file mode 100644 index 00000000000..a755493d2be --- /dev/null +++ b/pkg/machinery/nethelpers/defaultaction_enumer.go @@ -0,0 +1,61 @@ +// Code generated by "enumer -type=DefaultAction -linecomment -text"; DO NOT EDIT. + +package nethelpers + +import ( + "fmt" +) + +const _DefaultActionName = "acceptblock" + +var _DefaultActionIndex = [...]uint8{0, 6, 11} + +func (i DefaultAction) String() string { + if i < 0 || i >= DefaultAction(len(_DefaultActionIndex)-1) { + return fmt.Sprintf("DefaultAction(%d)", i) + } + return _DefaultActionName[_DefaultActionIndex[i]:_DefaultActionIndex[i+1]] +} + +var _DefaultActionValues = []DefaultAction{0, 1} + +var _DefaultActionNameToValueMap = map[string]DefaultAction{ + _DefaultActionName[0:6]: 0, + _DefaultActionName[6:11]: 1, +} + +// DefaultActionString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func DefaultActionString(s string) (DefaultAction, error) { + if val, ok := _DefaultActionNameToValueMap[s]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to DefaultAction values", s) +} + +// DefaultActionValues returns all values of the enum +func DefaultActionValues() []DefaultAction { + return _DefaultActionValues +} + +// IsADefaultAction returns "true" if the value is listed in the enum definition. "false" otherwise +func (i DefaultAction) IsADefaultAction() bool { + for _, v := range _DefaultActionValues { + if i == v { + return true + } + } + return false +} + +// MarshalText implements the encoding.TextMarshaler interface for DefaultAction +func (i DefaultAction) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for DefaultAction +func (i *DefaultAction) UnmarshalText(text []byte) error { + var err error + *i, err = DefaultActionString(string(text)) + return err +} diff --git a/pkg/machinery/nethelpers/protocol.go b/pkg/machinery/nethelpers/protocol.go index b1831590880..dda80717ab5 100644 --- a/pkg/machinery/nethelpers/protocol.go +++ b/pkg/machinery/nethelpers/protocol.go @@ -13,6 +13,8 @@ type Protocol uint8 // //structprotogen:gen_enum const ( - ProtocolTCP Protocol = 0x6 // tcp - ProtocolUDP Protocol = 0x11 // udp + ProtocolICMP Protocol = 0x1 // icmp + ProtocolTCP Protocol = 0x6 // tcp + ProtocolUDP Protocol = 0x11 // udp + ProtocolICMPv6 Protocol = 0x3a // icmpv6 ) diff --git a/pkg/machinery/nethelpers/protocol_enumer.go b/pkg/machinery/nethelpers/protocol_enumer.go index e2c5587e2d5..28c63b4af9f 100644 --- a/pkg/machinery/nethelpers/protocol_enumer.go +++ b/pkg/machinery/nethelpers/protocol_enumer.go @@ -7,31 +7,41 @@ import ( ) const ( - _ProtocolName_0 = "tcp" - _ProtocolName_1 = "udp" + _ProtocolName_0 = "icmp" + _ProtocolName_1 = "tcp" + _ProtocolName_2 = "udp" + _ProtocolName_3 = "icmpv6" ) var ( - _ProtocolIndex_0 = [...]uint8{0, 3} + _ProtocolIndex_0 = [...]uint8{0, 4} _ProtocolIndex_1 = [...]uint8{0, 3} + _ProtocolIndex_2 = [...]uint8{0, 3} + _ProtocolIndex_3 = [...]uint8{0, 6} ) func (i Protocol) String() string { switch { - case i == 6: + case i == 1: return _ProtocolName_0 - case i == 17: + case i == 6: return _ProtocolName_1 + case i == 17: + return _ProtocolName_2 + case i == 58: + return _ProtocolName_3 default: return fmt.Sprintf("Protocol(%d)", i) } } -var _ProtocolValues = []Protocol{6, 17} +var _ProtocolValues = []Protocol{1, 6, 17, 58} var _ProtocolNameToValueMap = map[string]Protocol{ - _ProtocolName_0[0:3]: 6, - _ProtocolName_1[0:3]: 17, + _ProtocolName_0[0:4]: 1, + _ProtocolName_1[0:3]: 6, + _ProtocolName_2[0:3]: 17, + _ProtocolName_3[0:6]: 58, } // ProtocolString retrieves an enum value from the enum constants string name. diff --git a/pkg/machinery/resources/network/nftables_chain.go b/pkg/machinery/resources/network/nftables_chain.go index e10a930ba2e..9fff3ef861b 100644 --- a/pkg/machinery/resources/network/nftables_chain.go +++ b/pkg/machinery/resources/network/nftables_chain.go @@ -135,8 +135,21 @@ func (NfTablesChainExtension) ResourceDefinition() meta.ResourceDefinitionSpec { Type: NfTablesChainType, Aliases: []resource.Type{"chain", "chains"}, DefaultNamespace: NamespaceName, - PrintColumns: []meta.PrintColumn{}, - Sensitivity: meta.NonSensitive, + PrintColumns: []meta.PrintColumn{ + { + Name: "Type", + JSONPath: `{.type}`, + }, + { + Name: "Hook", + JSONPath: `{.hook}`, + }, + { + Name: "Priority", + JSONPath: `{.priority}`, + }, + }, + Sensitivity: meta.NonSensitive, } } diff --git a/website/content/v1.6/reference/api.md b/website/content/v1.6/reference/api.md index 08e98a99b6f..b5f377fdce7 100644 --- a/website/content/v1.6/reference/api.md +++ b/website/content/v1.6/reference/api.md @@ -1285,8 +1285,10 @@ NethelpersProtocol is a inet protocol. | Name | Number | Description | | ---- | ------ | ----------- | | NETHELPERS_PROTOCOL_UNSPECIFIED | 0 | | +| PROTOCOL_ICMP | 1 | | | PROTOCOL_TCP | 6 | | | PROTOCOL_UDP | 17 | | +| PROTOCOL_ICM_PV6 | 58 | |