github.com/cilium/cilium@v1.16.2/pkg/fqdn/restore/restore.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  // The restore package provides data structures important to restoring
     5  // DNS proxy rules. This package serves as a central source for these
     6  // structures.
     7  // Note that these are marshaled as JSON and any changes need to be compatible
     8  // across an upgrade!
     9  package restore
    10  
    11  import (
    12  	"fmt"
    13  	"sort"
    14  	"testing"
    15  )
    16  
    17  // PortProtoV2 is 1 value at bit position 24.
    18  const PortProtoV2 = 1 << 24
    19  
    20  // PortProto is uint32 that encodes two different
    21  // versions of port protocol keys. Version 1 is protocol
    22  // agnostic and (naturally) encodes no values at bit
    23  // positions 16-31. Version 2 encodes protocol at bit
    24  // positions 16-23, and bit position 24 encodes a 1
    25  // value to indicate that it is Version 2. Both versions
    26  // encode the port at the
    27  // bit positions 0-15.
    28  //
    29  // This works because Version 1 will naturally encode
    30  // no values at postions 16-31 as the original Version 1
    31  // was a uint16. Version 2 enforces a 1 value at the 24th
    32  // bit position, so it will alway be legible.
    33  type PortProto uint32
    34  
    35  // MakeV2PortProto returns a Version 2 port protocol.
    36  func MakeV2PortProto(port uint16, proto uint8) PortProto {
    37  	return PortProto(PortProtoV2 | (uint32(proto) << 16) | uint32(port))
    38  }
    39  
    40  // IsPortV2 returns true if the PortProto
    41  // is Version 2.
    42  func (pp PortProto) IsPortV2() bool {
    43  	return PortProtoV2&pp == PortProtoV2
    44  }
    45  
    46  // Port returns the port of the PortProto
    47  func (pp PortProto) Port() uint16 {
    48  	return uint16(pp & 0x0000_ffff)
    49  }
    50  
    51  // Protocol returns the protocol of the
    52  // PortProto. It returns "0" for Version 1.
    53  func (pp PortProto) Protocol() uint8 {
    54  	return uint8((pp & 0xff_0000) >> 16)
    55  }
    56  
    57  // ToV1 returns the Version 1 (that is, "port")
    58  // version of the PortProto.
    59  func (pp PortProto) ToV1() PortProto {
    60  	return pp & 0x0000_ffff
    61  }
    62  
    63  // String returns the decimal representation
    64  // of PortProtocol in string form.
    65  func (pp PortProto) String() string {
    66  	return fmt.Sprintf("%d", pp)
    67  }
    68  
    69  // DNSRules contains IP-based DNS rules for a set of port-protocols (e.g., UDP/53)
    70  type DNSRules map[PortProto]IPRules
    71  
    72  // IPRules is an unsorted collection of IPrules
    73  type IPRules []IPRule
    74  
    75  // IPRule stores the allowed destination IPs for a DNS names matching a regex
    76  type IPRule struct {
    77  	Re  RuleRegex
    78  	IPs map[string]struct{} // IPs, nil set is wildcard and allows all IPs!
    79  }
    80  
    81  // RuleRegex is a wrapper for a pointer to a string so that we can define marshalers for it.
    82  type RuleRegex struct {
    83  	Pattern *string
    84  }
    85  
    86  // Sort is only used for testing
    87  // Sorts in place, but returns IPRules for convenience
    88  func (r IPRules) Sort(_ *testing.T) IPRules {
    89  	sort.SliceStable(r, func(i, j int) bool {
    90  		if r[i].Re.Pattern != nil && r[j].Re.Pattern != nil {
    91  			return *r[i].Re.Pattern < *r[j].Re.Pattern
    92  		}
    93  		if r[i].Re.Pattern != nil {
    94  			return true
    95  		}
    96  		return false
    97  	})
    98  
    99  	return r
   100  }
   101  
   102  // Sort is only used for testing
   103  // Sorts in place, but returns DNSRules for convenience
   104  func (r DNSRules) Sort(_ *testing.T) DNSRules {
   105  	for pp, ipRules := range r {
   106  		if len(ipRules) > 0 {
   107  			ipRules = ipRules.Sort(nil)
   108  			r[pp] = ipRules
   109  		}
   110  	}
   111  	return r
   112  }
   113  
   114  // UnmarshalText unmarshals json into a RuleRegex
   115  // This must have a pointer receiver, otherwise the RuleRegex remains empty.
   116  func (r *RuleRegex) UnmarshalText(b []byte) error {
   117  	pattern := string(b)
   118  	r.Pattern = &pattern
   119  	return nil
   120  }
   121  
   122  // MarshalText marshals RuleRegex as string
   123  func (r RuleRegex) MarshalText() ([]byte, error) {
   124  	if r.Pattern != nil {
   125  		return []byte(*r.Pattern), nil
   126  	}
   127  	return nil, nil
   128  }