util/checkchange: stop using deephash everywhere
Saves 45 KB from the min build, no longer pulling in deephash or util/hashx, both with unsafe code. It can actually be more efficient to not use deephash, as you don't have to walk all bytes of all fields recursively to answer that two things are not equal. Instead, you can just return false at the first difference you see. And then with views (as we use ~everywhere nowadays), the cloning the old value isn't expensive, as it's just a pointer under the hood. Updates #12614 Change-Id: I7b08616b8a09b3ade454bb5e0ac5672086fe8aec Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
28b1b4c3c1
commit
316afe7d02
+1
-1
@@ -5,7 +5,7 @@
|
||||
// the node and the coordination server.
|
||||
package tailcfg
|
||||
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile,VIPService --clonefunc
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile,VIPService,SSHPolicy --clonefunc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
@@ -651,9 +651,35 @@ var _VIPServiceCloneNeedsRegeneration = VIPService(struct {
|
||||
Active bool
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of SSHPolicy.
|
||||
// The result aliases no memory with the original.
|
||||
func (src *SSHPolicy) Clone() *SSHPolicy {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
dst := new(SSHPolicy)
|
||||
*dst = *src
|
||||
if src.Rules != nil {
|
||||
dst.Rules = make([]*SSHRule, len(src.Rules))
|
||||
for i := range dst.Rules {
|
||||
if src.Rules[i] == nil {
|
||||
dst.Rules[i] = nil
|
||||
} else {
|
||||
dst.Rules[i] = src.Rules[i].Clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _SSHPolicyCloneNeedsRegeneration = SSHPolicy(struct {
|
||||
Rules []*SSHRule
|
||||
}{})
|
||||
|
||||
// Clone duplicates src into dst and reports whether it succeeded.
|
||||
// To succeed, <src, dst> must be of types <*T, *T> or <*T, **T>,
|
||||
// where T is one of User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile,VIPService.
|
||||
// where T is one of User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile,VIPService,SSHPolicy.
|
||||
func Clone(dst, src any) bool {
|
||||
switch src := src.(type) {
|
||||
case *User:
|
||||
@@ -836,6 +862,15 @@ func Clone(dst, src any) bool {
|
||||
*dst = src.Clone()
|
||||
return true
|
||||
}
|
||||
case *SSHPolicy:
|
||||
switch dst := dst.(type) {
|
||||
case *SSHPolicy:
|
||||
*dst = *src.Clone()
|
||||
return true
|
||||
case **SSHPolicy:
|
||||
*dst = src.Clone()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+92
-1
@@ -21,7 +21,7 @@ import (
|
||||
"tailscale.com/types/views"
|
||||
)
|
||||
|
||||
//go:generate go run tailscale.com/cmd/cloner -clonefunc=true -type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile,VIPService
|
||||
//go:generate go run tailscale.com/cmd/cloner -clonefunc=true -type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile,VIPService,SSHPolicy
|
||||
|
||||
// View returns a read-only view of User.
|
||||
func (p *User) View() UserView {
|
||||
@@ -2604,3 +2604,94 @@ var _VIPServiceViewNeedsRegeneration = VIPService(struct {
|
||||
Ports []ProtoPortRange
|
||||
Active bool
|
||||
}{})
|
||||
|
||||
// View returns a read-only view of SSHPolicy.
|
||||
func (p *SSHPolicy) View() SSHPolicyView {
|
||||
return SSHPolicyView{ж: p}
|
||||
}
|
||||
|
||||
// SSHPolicyView provides a read-only view over SSHPolicy.
|
||||
//
|
||||
// Its methods should only be called if `Valid()` returns true.
|
||||
type SSHPolicyView struct {
|
||||
// ж is the underlying mutable value, named with a hard-to-type
|
||||
// character that looks pointy like a pointer.
|
||||
// It is named distinctively to make you think of how dangerous it is to escape
|
||||
// to callers. You must not let callers be able to mutate it.
|
||||
ж *SSHPolicy
|
||||
}
|
||||
|
||||
// Valid reports whether v's underlying value is non-nil.
|
||||
func (v SSHPolicyView) Valid() bool { return v.ж != nil }
|
||||
|
||||
// AsStruct returns a clone of the underlying value which aliases no memory with
|
||||
// the original.
|
||||
func (v SSHPolicyView) AsStruct() *SSHPolicy {
|
||||
if v.ж == nil {
|
||||
return nil
|
||||
}
|
||||
return v.ж.Clone()
|
||||
}
|
||||
|
||||
// MarshalJSON implements [jsonv1.Marshaler].
|
||||
func (v SSHPolicyView) MarshalJSON() ([]byte, error) {
|
||||
return jsonv1.Marshal(v.ж)
|
||||
}
|
||||
|
||||
// MarshalJSONTo implements [jsonv2.MarshalerTo].
|
||||
func (v SSHPolicyView) MarshalJSONTo(enc *jsontext.Encoder) error {
|
||||
return jsonv2.MarshalEncode(enc, v.ж)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements [jsonv1.Unmarshaler].
|
||||
func (v *SSHPolicyView) UnmarshalJSON(b []byte) error {
|
||||
if v.ж != nil {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
var x SSHPolicy
|
||||
if err := jsonv1.Unmarshal(b, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
v.ж = &x
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom].
|
||||
func (v *SSHPolicyView) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
|
||||
if v.ж != nil {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
var x SSHPolicy
|
||||
if err := jsonv2.UnmarshalDecode(dec, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
v.ж = &x
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rules are the rules to process for an incoming SSH connection. The first
|
||||
// matching rule takes its action and stops processing further rules.
|
||||
//
|
||||
// When an incoming connection first starts, all rules are evaluated in
|
||||
// "none" auth mode, where the client hasn't even been asked to send a
|
||||
// public key. All SSHRule.Principals requiring a public key won't match. If
|
||||
// a rule matches on the first pass and its Action is reject, the
|
||||
// authentication fails with that action's rejection message, if any.
|
||||
//
|
||||
// If the first pass rule evaluation matches nothing without matching an
|
||||
// Action with Reject set, the rules are considered to see whether public
|
||||
// keys might still result in a match. If not, "none" auth is terminated
|
||||
// before proceeding to public key mode. If so, the client is asked to try
|
||||
// public key authentication and the rules are evaluated again for each of
|
||||
// the client's present keys.
|
||||
func (v SSHPolicyView) Rules() views.SliceView[*SSHRule, SSHRuleView] {
|
||||
return views.SliceOfViews[*SSHRule, SSHRuleView](v.ж.Rules)
|
||||
}
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _SSHPolicyViewNeedsRegeneration = SSHPolicy(struct {
|
||||
Rules []*SSHRule
|
||||
}{})
|
||||
|
||||
Reference in New Issue
Block a user