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 }