diff --git a/cmd/proxy-to-grafana/proxy-to-grafana.go b/cmd/proxy-to-grafana/proxy-to-grafana.go index b9f3c7e9b..56c566e75 100644 --- a/cmd/proxy-to-grafana/proxy-to-grafana.go +++ b/cmd/proxy-to-grafana/proxy-to-grafana.go @@ -14,14 +14,14 @@ // // Use this Grafana configuration to enable the auth proxy: // -// [auth.proxy] -// enabled = true -// header_name = X-WEBAUTH-USER -// header_property = username -// auto_sign_up = true -// whitelist = 127.0.0.1 -// headers = Name:X-WEBAUTH-NAME -// enable_login_token = true +// [auth.proxy] +// enabled = true +// header_name = X-WEBAUTH-USER +// header_property = username +// auto_sign_up = true +// whitelist = 127.0.0.1 +// headers = Name:X-WEBAUTH-NAME +// enable_login_token = true package main import ( diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index 36dcf4d86..17772b715 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -178,15 +178,16 @@ var upArgs upArgsT // JSON block will be output. The AuthURL and QR fields will not be present, the // BackendState and Error fields will give the result of the authentication. // Ex: -// { -// "AuthURL": "https://login.tailscale.com/a/0123456789abcdef", -// "QR": "data:image/png;base64,0123...cdef" -// "BackendState": "NeedsLogin" -// } -// { -// "BackendState": "Running" -// } // +// { +// "AuthURL": "https://login.tailscale.com/a/0123456789abcdef", +// "QR": "data:image/png;base64,0123...cdef" +// "BackendState": "NeedsLogin" +// } +// +// { +// "BackendState": "Running" +// } type upOutputJSON struct { AuthURL string `json:",omitempty"` // Authentication URL of the form https://login.tailscale.com/a/0123456789 QR string `json:",omitempty"` // a DataURL (base64) PNG of a QR code AuthURL diff --git a/cmd/tsconnect/tsconnect.go b/cmd/tsconnect/tsconnect.go index 3f48987d1..1fb183deb 100644 --- a/cmd/tsconnect/tsconnect.go +++ b/cmd/tsconnect/tsconnect.go @@ -4,10 +4,10 @@ // The tsconnect command builds and serves the static site that is generated for // the Tailscale Connect JS/WASM client. Can be run in 3 modes: -// - dev: builds the site and serves it. JS and CSS changes can be picked up -// with a reload. -// - build: builds the site and writes it to dist/ -// - serve: serves the site from dist/ (embedded in the binary) +// - dev: builds the site and serves it. JS and CSS changes can be picked up +// with a reload. +// - build: builds the site and writes it to dist/ +// - serve: serves the site from dist/ (embedded in the binary) package main // import "tailscale.com/cmd/tsconnect" import ( diff --git a/cmd/viewer/viewer.go b/cmd/viewer/viewer.go index 99c6c21c5..a8fb49cc3 100644 --- a/cmd/viewer/viewer.go +++ b/cmd/viewer/viewer.go @@ -342,8 +342,7 @@ func main() { it := codegen.NewImportTracker(pkg.Types) buf := new(bytes.Buffer) - fmt.Fprintf(buf, `//go:generate go run tailscale.com/cmd/cloner %s`, strings.Join(flagArgs, " ")) - fmt.Fprintln(buf) + fmt.Fprintf(buf, "//go:generate go run tailscale.com/cmd/cloner %s\n\n", strings.Join(flagArgs, " ")) runCloner := false for _, typeName := range typeNames { typ, ok := namedTypes[typeName] diff --git a/derp/derp.go b/derp/derp.go index 37bb8e604..3107f3dea 100644 --- a/derp/derp.go +++ b/derp/derp.go @@ -40,8 +40,8 @@ const ( ) // ProtocolVersion is bumped whenever there's a wire-incompatible change. -// * version 1 (zero on wire): consistent box headers, in use by employee dev nodes a bit -// * version 2: received packets have src addrs in frameRecvPacket at beginning +// - version 1 (zero on wire): consistent box headers, in use by employee dev nodes a bit +// - version 2: received packets have src addrs in frameRecvPacket at beginning const ProtocolVersion = 2 // frameType is the one byte frame type at the beginning of the frame diff --git a/disco/disco.go b/disco/disco.go index 53ce81361..c00392f24 100644 --- a/disco/disco.go +++ b/disco/disco.go @@ -7,16 +7,17 @@ // A discovery message is: // // Header: -// magic [6]byte // “TS💬” (0x54 53 f0 9f 92 ac) -// senderDiscoPub [32]byte // nacl public key -// nonce [24]byte +// +// magic [6]byte // “TS💬” (0x54 53 f0 9f 92 ac) +// senderDiscoPub [32]byte // nacl public key +// nonce [24]byte // // The recipient then decrypts the bytes following (the nacl secretbox) // and then the inner payload structure is: // -// messageType byte (the MessageType constants below) -// messageVersion byte (0 for now; but always ignore bytes at the end) -// message-paylod [...]byte +// messageType byte (the MessageType constants below) +// messageVersion byte (0 for now; but always ignore bytes at the end) +// message-paylod [...]byte package disco import ( diff --git a/ipn/backend.go b/ipn/backend.go index 54aa7229d..ab59d7002 100644 --- a/ipn/backend.go +++ b/ipn/backend.go @@ -162,12 +162,12 @@ type PartialFile struct { // // Various platforms currently set StateKey in different ways: // -// * the macOS/iOS GUI apps set it to "ipn-go-bridge" -// * the Android app sets it to "ipn-android" -// * on Windows, it's the empty string (in client mode) or, via -// LocalBackend.userID, a string like "user-$USER_ID" (used in -// server mode). -// * on Linux/etc, it's always "_daemon" (ipn.GlobalDaemonStateKey) +// - the macOS/iOS GUI apps set it to "ipn-go-bridge" +// - the Android app sets it to "ipn-android" +// - on Windows, it's the empty string (in client mode) or, via +// LocalBackend.userID, a string like "user-$USER_ID" (used in +// server mode). +// - on Linux/etc, it's always "_daemon" (ipn.GlobalDaemonStateKey) type StateKey string type Options struct { diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index ffff19488..e86db4863 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -883,11 +883,11 @@ func (b *LocalBackend) getNewControlClientFunc() clientGen { // startIsNoopLocked reports whether a Start call on this LocalBackend // with the provided Start Options would be a useless no-op. // -// TODO(apenwarr): we shouldn't need this. -// The state machine is now nearly clean enough where it can accept a new -// connection while in any state, not just Running, and on any platform. -// We'd want to add a few more tests to state_test.go to ensure this continues -// to work as expected. +// TODO(apenwarr): we shouldn't need this. The state machine is now +// nearly clean enough where it can accept a new connection while in +// any state, not just Running, and on any platform. We'd want to add +// a few more tests to state_test.go to ensure this continues to work +// as expected. // // b.mu must be held. func (b *LocalBackend) startIsNoopLocked(opts ipn.Options) bool { @@ -2926,7 +2926,7 @@ func (b *LocalBackend) RequestEngineStatus() { // feed events into LocalBackend. // // TODO(apenwarr): use a channel or something to prevent re-entrancy? -// Or maybe just call the state machine from fewer places. +// Or maybe just call the state machine from fewer places. func (b *LocalBackend) stateMachine() { b.enterState(b.nextState()) } diff --git a/ipn/localapi/localapi.go b/ipn/localapi/localapi.go index f5b8ca455..de6e5cddc 100644 --- a/ipn/localapi/localapi.go +++ b/ipn/localapi/localapi.go @@ -545,7 +545,7 @@ func (h *Handler) serveFileTargets(w http.ResponseWriter, r *http.Request) { // // URL format: // -// * PUT /localapi/v0/file-put/:stableID/:escaped-filename +// - PUT /localapi/v0/file-put/:stableID/:escaped-filename func (h *Handler) serveFilePut(w http.ResponseWriter, r *http.Request) { if !h.PermitWrite { http.Error(w, "file access denied", http.StatusForbidden) diff --git a/ipn/message.go b/ipn/message.go index 6149a38b8..8404c2c08 100644 --- a/ipn/message.go +++ b/ipn/message.go @@ -305,8 +305,8 @@ func (bc *BackendClient) RequestStatus() { // MaxMessageSize is the maximum message size, in bytes. const MaxMessageSize = 10 << 20 -// TODO(apenwarr): incremental json decode? -// That would let us avoid storing the whole byte array uselessly in RAM. +// TODO(apenwarr): incremental json decode? That would let us avoid +// storing the whole byte array uselessly in RAM. func ReadMsg(r io.Reader) ([]byte, error) { cb := make([]byte, 4) _, err := io.ReadFull(r, cb) @@ -328,10 +328,11 @@ func ReadMsg(r io.Reader) ([]byte, error) { return b, nil } -// TODO(apenwarr): incremental json encode? -// That would save RAM, at the expense of having to encode once so that -// we can produce the initial byte count. func WriteMsg(w io.Writer, b []byte) error { + // TODO(apenwarr): incremental json encode? That would save RAM, at the + // expense of having to encode once so that we can produce the initial byte + // count. + // TODO(bradfitz): this does two writes to w, which likely // does two writes on the wire, two frame generations, etc. We // should take a concrete buffered type, or use a sync.Pool to diff --git a/ipn/store/stores.go b/ipn/store/stores.go index 98c1d2aa0..96b8a0be5 100644 --- a/ipn/store/stores.go +++ b/ipn/store/stores.go @@ -49,13 +49,13 @@ var knownStores map[string]Provider // // By default the following stores are registered: // -// * if the string begins with "mem:", the suffix +// - if the string begins with "mem:", the suffix // is ignored and an in-memory store is used. -// * (Linux-only) if the string begins with "arn:", +// - (Linux-only) if the string begins with "arn:", // the suffix an AWS ARN for an SSM. -// * (Linux-only) if the string begins with "kube:", +// - (Linux-only) if the string begins with "kube:", // the suffix is a Kubernetes secret name -// * In all other cases, the path is treated as a filepath. +// - In all other cases, the path is treated as a filepath. func New(logf logger.Logf, path string) (ipn.StateStore, error) { regOnce.Do(registerDefaultStores) for prefix, sf := range knownStores { diff --git a/net/dns/resolved.go b/net/dns/resolved.go index 53a359f2c..a2a164577 100644 --- a/net/dns/resolved.go +++ b/net/dns/resolved.go @@ -31,7 +31,9 @@ import ( // In other cases, resolved may be managing the system DNS configuration directly. // Then the nameserver list will be a concatenation of those for all // the interfaces that register their interest in being a default resolver with -// SetLinkDomains([]{{"~.", true}, ...}) +// +// SetLinkDomains([]{{"~.", true}, ...}) +// // which includes at least the interface with the default route, i.e. not us. // This does not work for us: there is a possibility of getting NXDOMAIN // from the other nameservers before we are asked or get a chance to respond. diff --git a/net/dns/resolver/tsdns.go b/net/dns/resolver/tsdns.go index f28c3142c..729d26492 100644 --- a/net/dns/resolver/tsdns.go +++ b/net/dns/resolver/tsdns.go @@ -1025,11 +1025,11 @@ const ( // https://tools.ietf.org/html/rfc6763 lists // "five special RR names" for Bonjour service discovery: // -// b._dns-sd._udp.. -// db._dns-sd._udp.. -// r._dns-sd._udp.. -// dr._dns-sd._udp.. -// lb._dns-sd._udp.. +// b._dns-sd._udp.. +// db._dns-sd._udp.. +// r._dns-sd._udp.. +// dr._dns-sd._udp.. +// lb._dns-sd._udp.. func hasRDNSBonjourPrefix(name dnsname.FQDN) bool { s := name.WithTrailingDot() base, rest, ok := strings.Cut(s, ".") @@ -1063,9 +1063,12 @@ func rawNameToLower(name []byte) string { // ptrNameToIPv4 transforms a PTR name representing an IPv4 address to said address. // Such names are IPv4 labels in reverse order followed by .in-addr.arpa. // For example, -// 4.3.2.1.in-addr.arpa +// +// 4.3.2.1.in-addr.arpa +// // is transformed to -// 1.2.3.4 +// +// 1.2.3.4 func rdnsNameToIPv4(name dnsname.FQDN) (ip netip.Addr, ok bool) { s := strings.TrimSuffix(name.WithTrailingDot(), rdnsv4Suffix) ip, err := netip.ParseAddr(s) @@ -1082,9 +1085,12 @@ func rdnsNameToIPv4(name dnsname.FQDN) (ip netip.Addr, ok bool) { // ptrNameToIPv6 transforms a PTR name representing an IPv6 address to said address. // Such names are dot-separated nibbles in reverse order followed by .ip6.arpa. // For example, -// b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. +// +// b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. +// // is transformed to -// 2001:db8::567:89ab +// +// 2001:db8::567:89ab func rdnsNameToIPv6(name dnsname.FQDN) (ip netip.Addr, ok bool) { var b [32]byte var ipb [16]byte diff --git a/net/interfaces/interfaces_darwin_test.go b/net/interfaces/interfaces_darwin_test.go index 0ee238caf..245ea8211 100644 --- a/net/interfaces/interfaces_darwin_test.go +++ b/net/interfaces/interfaces_darwin_test.go @@ -39,7 +39,6 @@ default link#14 UCSI utun2 10/16 link#4 UCS en0 ! 10.0.0.1/32 link#4 UCS en0 ! ... - */ func likelyHomeRouterIPDarwinExec() (ret netip.Addr, ok bool) { if version.IsMobile() { diff --git a/net/packet/tsmp.go b/net/packet/tsmp.go index 76642b97b..310378694 100644 --- a/net/packet/tsmp.go +++ b/net/packet/tsmp.go @@ -25,13 +25,13 @@ import ( // TCP RST, this includes a reason. // // On the wire, after the IP header, it's currently 7 or 8 bytes: -// * '!' -// * IPProto byte (IANA protocol number: TCP or UDP) -// * 'A' or 'S' (RejectedDueToACLs, RejectedDueToShieldsUp) -// * srcPort big endian uint16 -// * dstPort big endian uint16 -// * [optional] byte of flag bits: -// lowest bit (0x1): MaybeBroken +// - '!' +// - IPProto byte (IANA protocol number: TCP or UDP) +// - 'A' or 'S' (RejectedDueToACLs, RejectedDueToShieldsUp) +// - srcPort big endian uint16 +// - dstPort big endian uint16 +// - [optional] byte of flag bits: +// lowest bit (0x1): MaybeBroken // // In the future it might also accept 16 byte IP flow src/dst IPs // after the header, if they're different than the IP-level ones. @@ -205,8 +205,8 @@ func (pp *Parsed) AsTailscaleRejectedHeader() (h TailscaleRejectedHeader, ok boo // TSMPPingRequest is a TSMP message that's like an ICMP ping request. // // On the wire, after the IP header, it's currently 9 bytes: -// * 'p' (TSMPTypePing) -// * 8 opaque ping bytes to copy back in the response +// - 'p' (TSMPTypePing) +// - 8 opaque ping bytes to copy back in the response type TSMPPingRequest struct { Data [8]byte } diff --git a/net/tlsdial/tlsdial.go b/net/tlsdial/tlsdial.go index 103e00f4d..35f1c0c4f 100644 --- a/net/tlsdial/tlsdial.go +++ b/net/tlsdial/tlsdial.go @@ -164,19 +164,20 @@ func SetConfigExpectedCert(c *tls.Config, certDNSName string) { letsEncryptX1 is the LetsEncrypt X1 root: Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Validity - Not Before: Jun 4 11:04:38 2015 GMT - Not After : Jun 4 11:04:38 2035 GMT - Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (4096 bit) + + Data: + Version: 3 (0x2) + Serial Number: + 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Validity + Not Before: Jun 4 11:04:38 2015 GMT + Not After : Jun 4 11:04:38 2035 GMT + Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) We bake it into the binary as a fallback verification root, in case the system we're running on doesn't have it. @@ -189,7 +190,6 @@ $ sudo update-ca-certificates Then restart tailscaled. To also test dnsfallback's use of it, nuke your /etc/resolv.conf and it should still start & run fine. - */ const letsEncryptX1 = ` -----BEGIN CERTIFICATE----- diff --git a/paths/migrate.go b/paths/migrate.go index 8e4f3d595..94f340678 100644 --- a/paths/migrate.go +++ b/paths/migrate.go @@ -13,11 +13,11 @@ import ( // TryConfigFileMigration carefully copies the contents of oldFile to // newFile, returning the path which should be used to read the config. -// - if newFile already exists, don't modify it just return its path -// - if neither oldFile nor newFile exist, return newFile for a fresh -// default config to be written to. -// - if oldFile exists but copying to newFile fails, return oldFile so -// there will at least be some config to work with. +// - if newFile already exists, don't modify it just return its path +// - if neither oldFile nor newFile exist, return newFile for a fresh +// default config to be written to. +// - if oldFile exists but copying to newFile fails, return oldFile so +// there will at least be some config to work with. func TryConfigFileMigration(logf logger.Logf, oldFile, newFile string) string { _, err := os.Stat(newFile) if err == nil { diff --git a/paths/paths_windows.go b/paths/paths_windows.go index f74be0200..03fbbac73 100644 --- a/paths/paths_windows.go +++ b/paths/paths_windows.go @@ -18,12 +18,15 @@ import ( // Owner: The user for the current process; // Primary Group: The primary group for the current process; // DACL: Full control to the current user and to the Administrators group. -// (We include Administrators so that admin users may still access logs; -// granting access exclusively to LocalSystem would require admins to use -// special tools to access the Log directory) +// +// (We include Administrators so that admin users may still access logs; +// granting access exclusively to LocalSystem would require admins to use +// special tools to access the Log directory) +// // Inheritance: The directory does not inherit the ACL from its parent. -// However, any directories and/or files created within this -// directory *do* inherit the ACL that we are setting. +// +// However, any directories and/or files created within this +// directory *do* inherit the ACL that we are setting. func ensureStateDirPerms(dirPath string) error { fi, err := os.Stat(dirPath) if err != nil { diff --git a/prober/prober.go b/prober/prober.go index fbe302910..4f33d34cf 100644 --- a/prober/prober.go +++ b/prober/prober.go @@ -239,13 +239,13 @@ func (v varExporter) String() string { // WritePrometheus writes the the state of all probes to w. // // For each probe, WritePrometheus exports 5 variables: -// - _interval_secs, how frequently the probe runs. -// - _start_secs, when the probe last started running, in seconds since epoch. -// - _end_secs, when the probe last finished running, in seconds since epoch. -// - _latency_millis, how long the last probe cycle took, in -// milliseconds. This is just (end_secs-start_secs) in an easier to -// graph form. -// - _result, 1 if the last probe succeeded, 0 if it failed. +// - _interval_secs, how frequently the probe runs. +// - _start_secs, when the probe last started running, in seconds since epoch. +// - _end_secs, when the probe last finished running, in seconds since epoch. +// - _latency_millis, how long the last probe cycle took, in +// milliseconds. This is just (end_secs-start_secs) in an easier to +// graph form. +// - _result, 1 if the last probe succeeded, 0 if it failed. // // Each probe has a set of static key/value labels (defined once at // probe creation), which are added as Prometheus metric labels to diff --git a/safesocket/pipe_windows.go b/safesocket/pipe_windows.go index 9041cbefb..fb27e9413 100644 --- a/safesocket/pipe_windows.go +++ b/safesocket/pipe_windows.go @@ -27,11 +27,12 @@ func setFlags(network, address string, c syscall.RawConn) error { } // TODO(apenwarr): use named pipes instead of sockets? -// I tried to use winio.ListenPipe() here, but that code is a disaster, -// built on top of an API that's a disaster. So for now we'll hack it by -// just always using a TCP session on a fixed port on localhost. As a -// result, on Windows we ignore the vendor and name strings. -// NOTE(bradfitz): Jason did a new pipe package: https://go-review.googlesource.com/c/sys/+/299009 +// +// I tried to use winio.ListenPipe() here, but that code is a disaster, +// built on top of an API that's a disaster. So for now we'll hack it by +// just always using a TCP session on a fixed port on localhost. As a +// result, on Windows we ignore the vendor and name strings. +// NOTE(bradfitz): Jason did a new pipe package: https://go-review.googlesource.com/c/sys/+/299009 func listen(path string, port uint16) (_ net.Listener, gotPort uint16, _ error) { lc := net.ListenConfig{ Control: setFlags, diff --git a/safesocket/safesocket_darwin.go b/safesocket/safesocket_darwin.go index 0a863b496..cd3defdb5 100644 --- a/safesocket/safesocket_darwin.go +++ b/safesocket/safesocket_darwin.go @@ -26,8 +26,9 @@ func init() { // from /Library/Tailscale. // // In that case the files are: -// /Library/Tailscale/ipnport => $port (symlink with localhost port number target) -// /Library/Tailscale/sameuserproof-$port is a file with auth +// +// /Library/Tailscale/ipnport => $port (symlink with localhost port number target) +// /Library/Tailscale/sameuserproof-$port is a file with auth func localTCPPortAndTokenMacsys() (port int, token string, err error) { const dir = "/Library/Tailscale" diff --git a/safesocket/unixsocket.go b/safesocket/unixsocket.go index 73915c0a2..b4d361459 100644 --- a/safesocket/unixsocket.go +++ b/safesocket/unixsocket.go @@ -118,11 +118,11 @@ func socketPermissionsForOS() os.FileMode { // homebrew or go install). This little dance to connect a regular user binary // to the sandboxed network extension is: // -// * the sandboxed IPNExtension picks a random localhost:0 TCP port +// - the sandboxed IPNExtension picks a random localhost:0 TCP port // to listen on -// * it also picks a random hex string that acts as an auth token -// * the CLI looks on disk for that TCP port + auth token (see localTCPPortAndTokenDarwin) -// * we send it upon TCP connect to prove to the Tailscale daemon that +// - it also picks a random hex string that acts as an auth token +// - the CLI looks on disk for that TCP port + auth token (see localTCPPortAndTokenDarwin) +// - we send it upon TCP connect to prove to the Tailscale daemon that // we're a suitably privileged user to have access the files on disk // which the Network/App Extension wrote. func connectMacOSAppSandbox() (net.Conn, error) { diff --git a/tailcfg/derpmap.go b/tailcfg/derpmap.go index 62564f0d6..41d863b66 100644 --- a/tailcfg/derpmap.go +++ b/tailcfg/derpmap.go @@ -20,7 +20,7 @@ type DERPMap struct { OmitDefaultRegions bool `json:"omitDefaultRegions,omitempty"` } -/// RegionIDs returns the sorted region IDs. +// / RegionIDs returns the sorted region IDs. func (m *DERPMap) RegionIDs() []int { ret := make([]int, 0, len(m.Regions)) for rid := range m.Regions { diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index e81082f3d..22978c330 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -37,37 +37,38 @@ type CapabilityVersion int // CurrentCapabilityVersion is the current capability version of the codebase. // // History of versions: -// 3: implicit compression, keep-alives -// 4: opt-in keep-alives via KeepAlive field, opt-in compression via Compress -// 5: 2020-10-19, implies IncludeIPv6, delta Peers/UserProfiles, supports MagicDNS -// 6: 2020-12-07: means MapResponse.PacketFilter nil means unchanged -// 7: 2020-12-15: FilterRule.SrcIPs accepts CIDRs+ranges, doesn't warn about 0.0.0.0/:: -// 8: 2020-12-19: client can buggily receive IPv6 addresses and routes if beta enabled server-side -// 9: 2020-12-30: client doesn't auto-add implicit search domains from peers; only DNSConfig.Domains -// 10: 2021-01-17: client understands MapResponse.PeerSeenChange -// 11: 2021-03-03: client understands IPv6, multiple default routes, and goroutine dumping -// 12: 2021-03-04: client understands PingRequest -// 13: 2021-03-19: client understands FilterRule.IPProto -// 14: 2021-04-07: client understands DNSConfig.Routes and DNSConfig.Resolvers -// 15: 2021-04-12: client treats nil MapResponse.DNSConfig as meaning unchanged -// 16: 2021-04-15: client understands Node.Online, MapResponse.OnlineChange -// 17: 2021-04-18: MapResponse.Domain empty means unchanged -// 18: 2021-04-19: MapResponse.Node nil means unchanged (all fields now omitempty) -// 19: 2021-04-21: MapResponse.Debug.SleepSeconds -// 20: 2021-06-11: MapResponse.LastSeen used even less (https://github.com/tailscale/tailscale/issues/2107) -// 21: 2021-06-15: added MapResponse.DNSConfig.CertDomains -// 22: 2021-06-16: added MapResponse.DNSConfig.ExtraRecords -// 23: 2021-08-25: DNSConfig.Routes values may be empty (for ExtraRecords support in 1.14.1+) -// 24: 2021-09-18: MapResponse.Health from control to node; node shows in "tailscale status" -// 25: 2021-11-01: MapResponse.Debug.Exit -// 26: 2022-01-12: (nothing, just bumping for 1.20.0) -// 27: 2022-02-18: start of SSHPolicy being respected -// 28: 2022-03-09: client can communicate over Noise. -// 29: 2022-03-21: MapResponse.PopBrowserURL -// 30: 2022-03-22: client can request id tokens. -// 31: 2022-04-15: PingRequest & PingResponse TSMP & disco support -// 32: 2022-04-17: client knows FilterRule.CapMatch -// 33: 2022-07-20: added MapResponse.PeersChangedPatch (DERPRegion + Endpoints) +// +// 3: implicit compression, keep-alives +// 4: opt-in keep-alives via KeepAlive field, opt-in compression via Compress +// 5: 2020-10-19, implies IncludeIPv6, delta Peers/UserProfiles, supports MagicDNS +// 6: 2020-12-07: means MapResponse.PacketFilter nil means unchanged +// 7: 2020-12-15: FilterRule.SrcIPs accepts CIDRs+ranges, doesn't warn about 0.0.0.0/:: +// 8: 2020-12-19: client can buggily receive IPv6 addresses and routes if beta enabled server-side +// 9: 2020-12-30: client doesn't auto-add implicit search domains from peers; only DNSConfig.Domains +// 10: 2021-01-17: client understands MapResponse.PeerSeenChange +// 11: 2021-03-03: client understands IPv6, multiple default routes, and goroutine dumping +// 12: 2021-03-04: client understands PingRequest +// 13: 2021-03-19: client understands FilterRule.IPProto +// 14: 2021-04-07: client understands DNSConfig.Routes and DNSConfig.Resolvers +// 15: 2021-04-12: client treats nil MapResponse.DNSConfig as meaning unchanged +// 16: 2021-04-15: client understands Node.Online, MapResponse.OnlineChange +// 17: 2021-04-18: MapResponse.Domain empty means unchanged +// 18: 2021-04-19: MapResponse.Node nil means unchanged (all fields now omitempty) +// 19: 2021-04-21: MapResponse.Debug.SleepSeconds +// 20: 2021-06-11: MapResponse.LastSeen used even less (https://github.com/tailscale/tailscale/issues/2107) +// 21: 2021-06-15: added MapResponse.DNSConfig.CertDomains +// 22: 2021-06-16: added MapResponse.DNSConfig.ExtraRecords +// 23: 2021-08-25: DNSConfig.Routes values may be empty (for ExtraRecords support in 1.14.1+) +// 24: 2021-09-18: MapResponse.Health from control to node; node shows in "tailscale status" +// 25: 2021-11-01: MapResponse.Debug.Exit +// 26: 2022-01-12: (nothing, just bumping for 1.20.0) +// 27: 2022-02-18: start of SSHPolicy being respected +// 28: 2022-03-09: client can communicate over Noise. +// 29: 2022-03-21: MapResponse.PopBrowserURL +// 30: 2022-03-22: client can request id tokens. +// 31: 2022-04-15: PingRequest & PingResponse TSMP & disco support +// 32: 2022-04-17: client knows FilterRule.CapMatch +// 33: 2022-07-20: added MapResponse.PeersChangedPatch (DERPRegion + Endpoints) const CurrentCapabilityVersion CapabilityVersion = 33 type StableID string @@ -746,6 +747,7 @@ func (st SignatureType) String() string { // RegisterRequest is sent by a client to register the key for a node. // It is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box, // using the local machine key, and sent to: +// // https://login.tailscale.com/machine/ type RegisterRequest struct { _ structs.Incomparable @@ -864,6 +866,7 @@ type Endpoint struct { // // The request is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box, // using the local machine key, and sent to: +// // https://login.tailscale.com/machine//map type MapRequest struct { // Version is incremented whenever the client code changes enough that @@ -1514,6 +1517,7 @@ const ( // // The request is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box, // using the local machine key, and sent to: +// // https://login.tailscale.com/machine//set-dns type SetDNSRequest struct { // Version is the client's capabilities diff --git a/tempfork/gliderlabs/ssh/doc.go b/tempfork/gliderlabs/ssh/doc.go index 5a10393c2..d13919176 100644 --- a/tempfork/gliderlabs/ssh/doc.go +++ b/tempfork/gliderlabs/ssh/doc.go @@ -10,29 +10,29 @@ use crypto/ssh for building SSH clients. ListenAndServe starts an SSH server with a given address, handler, and options. The handler is usually nil, which means to use DefaultHandler. Handle sets DefaultHandler: - ssh.Handle(func(s ssh.Session) { - io.WriteString(s, "Hello world\n") - }) + ssh.Handle(func(s ssh.Session) { + io.WriteString(s, "Hello world\n") + }) - log.Fatal(ssh.ListenAndServe(":2222", nil)) + log.Fatal(ssh.ListenAndServe(":2222", nil)) If you don't specify a host key, it will generate one every time. This is convenient except you'll have to deal with clients being confused that the host key is different. It's a better idea to generate or point to an existing key on your system: - log.Fatal(ssh.ListenAndServe(":2222", nil, ssh.HostKeyFile("/Users/progrium/.ssh/id_rsa"))) + log.Fatal(ssh.ListenAndServe(":2222", nil, ssh.HostKeyFile("/Users/progrium/.ssh/id_rsa"))) Although all options have functional option helpers, another way to control the server's behavior is by creating a custom Server: - s := &ssh.Server{ - Addr: ":2222", - Handler: sessionHandler, - PublicKeyHandler: authHandler, - } - s.AddHostKey(hostKeySigner) + s := &ssh.Server{ + Addr: ":2222", + Handler: sessionHandler, + PublicKeyHandler: authHandler, + } + s.AddHostKey(hostKeySigner) - log.Fatal(s.ListenAndServe()) + log.Fatal(s.ListenAndServe()) This package automatically handles basic SSH requests like setting environment variables, requesting PTY, and changing window size. These requests are diff --git a/tsweb/tsweb.go b/tsweb/tsweb.go index 83a0ab077..75c2839be 100644 --- a/tsweb/tsweb.go +++ b/tsweb/tsweb.go @@ -582,17 +582,17 @@ func writePromExpVar(w io.Writer, prefix string, kv expvar.KeyValue) { // VarzHandler is an HTTP handler to write expvar values into the // prometheus export format: // -// https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md +// https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md // // It makes the following assumptions: // -// * *expvar.Int are counters (unless marked as a gauge_; see below) -// * a *tailscale/metrics.Set is descended into, joining keys with +// - *expvar.Int are counters (unless marked as a gauge_; see below) +// - a *tailscale/metrics.Set is descended into, joining keys with // underscores. So use underscores as your metric names. -// * an expvar named starting with "gauge_" or "counter_" is of that +// - an expvar named starting with "gauge_" or "counter_" is of that // Prometheus type, and has that prefix stripped. -// * anything else is untyped and thus not exported. -// * expvar.Func can return an int or int64 (for now) and anything else +// - anything else is untyped and thus not exported. +// - expvar.Func can return an int or int64 (for now) and anything else // is not exported. // // This will evolve over time, or perhaps be replaced. diff --git a/types/logger/tokenbucket.go b/types/logger/tokenbucket.go index 293fe0863..544fffe26 100644 --- a/types/logger/tokenbucket.go +++ b/types/logger/tokenbucket.go @@ -12,10 +12,11 @@ import ( // It's similar in function to golang.org/x/time/rate.Limiter, which we // can't use because: -// - It doesn't give access to the number of accumulated tokens, which we -// need for implementing hysteresis; -// - It doesn't let us provide our own time function, which we need for -// implementing proper unit tests. +// - It doesn't give access to the number of accumulated tokens, which we +// need for implementing hysteresis; +// - It doesn't let us provide our own time function, which we need for +// implementing proper unit tests. +// // rate.Limiter is also much more complex than necessary, but that wouldn't // be enough to disqualify it on its own. // diff --git a/util/clientmetric/clientmetric.go b/util/clientmetric/clientmetric.go index e1b2ca7d4..fceb76635 100644 --- a/util/clientmetric/clientmetric.go +++ b/util/clientmetric/clientmetric.go @@ -216,11 +216,11 @@ const ( // without further escaping. // // The current encoding is: -// * name immediately following metric: +// - name immediately following metric: // 'N' + hex(varint(len(name))) + name -// * set value of a metric: +// - set value of a metric: // 'S' + hex(varint(wireid)) + hex(varint(value)) -// * increment a metric: (decrements if negative) +// - increment a metric: (decrements if negative) // 'I' + hex(varint(wireid)) + hex(varint(value)) func EncodeLogTailMetricsDelta() string { mu.Lock() diff --git a/util/deephash/deephash.go b/util/deephash/deephash.go index 93ab1abc5..e274ed53f 100644 --- a/util/deephash/deephash.go +++ b/util/deephash/deephash.go @@ -9,11 +9,11 @@ // Hash(x) == Hash(y) is an appropriate replacement for x == y. // // The definition of equality is identical to reflect.DeepEqual except: -// * Floating-point values are compared based on the raw bits, -// which means that NaNs (with the same bit pattern) are treated as equal. -// * Types which implement interface { AppendTo([]byte) []byte } use -// the AppendTo method to produce a textual representation of the value. -// Thus, two values are equal if AppendTo produces the same bytes. +// - Floating-point values are compared based on the raw bits, +// which means that NaNs (with the same bit pattern) are treated as equal. +// - Types which implement interface { AppendTo([]byte) []byte } use +// the AppendTo method to produce a textual representation of the value. +// Thus, two values are equal if AppendTo produces the same bytes. // // WARNING: This package, like most of the tailscale.com Go module, // should be considered Tailscale-internal; we make no API promises. diff --git a/util/multierr/multierr.go b/util/multierr/multierr.go index 6e17be3d4..7db592117 100644 --- a/util/multierr/multierr.go +++ b/util/multierr/multierr.go @@ -34,8 +34,9 @@ func (e Error) Errors() []error { // New returns an error composed from errs. // Some errors in errs get special treatment: -// * nil errors are discarded -// * errors of type Error are expanded into the top level +// - nil errors are discarded +// - errors of type Error are expanded into the top level +// // If the resulting slice has length 0, New returns nil. // If the resulting slice has length 1, New returns that error. // If the resulting slice has length > 1, New returns that slice as an Error. diff --git a/util/singleflight/singleflight.go b/util/singleflight/singleflight.go index fef02c298..88a9c5802 100644 --- a/util/singleflight/singleflight.go +++ b/util/singleflight/singleflight.go @@ -12,9 +12,9 @@ // This is a Tailscale fork of Go's singleflight package which has had several // homes in the past: // -// * https://github.com/golang/go/commit/61d3b2db6292581fc07a3767ec23ec94ad6100d1 -// * https://github.com/golang/groupcache/tree/master/singleflight -// * https://pkg.go.dev/golang.org/x/sync/singleflight +// - https://github.com/golang/go/commit/61d3b2db6292581fc07a3767ec23ec94ad6100d1 +// - https://github.com/golang/groupcache/tree/master/singleflight +// - https://pkg.go.dev/golang.org/x/sync/singleflight // // This fork adds generics. package singleflight // import "tailscale.com/util/singleflight" diff --git a/util/systemd/systemd_linux.go b/util/systemd/systemd_linux.go index 1988e7257..aac97814d 100644 --- a/util/systemd/systemd_linux.go +++ b/util/systemd/systemd_linux.go @@ -59,18 +59,18 @@ func Ready() { // Status sends a single line status update to systemd so that information shows up // in systemctl output. For example: // -// $ systemctl status tailscale -// ● tailscale.service - Tailscale client daemon -// Loaded: loaded (/nix/store/qc312qcy907wz80fqrgbbm8a9djafmlg-unit-tailscale.service/tailscale.service; enabled; vendor preset: enabled) -// Active: active (running) since Tue 2020-11-24 17:54:07 EST; 13h ago -// Main PID: 26741 (.tailscaled-wra) -// Status: "Connected; user@host.domain.tld; 100.101.102.103" -// IP: 0B in, 0B out -// Tasks: 22 (limit: 4915) -// Memory: 30.9M -// CPU: 2min 38.469s -// CGroup: /system.slice/tailscale.service -// └─26741 /nix/store/sv6cj4mw2jajm9xkbwj07k29dj30lh0n-tailscale-date.20200727/bin/tailscaled --port 41641 +// $ systemctl status tailscale +// ● tailscale.service - Tailscale client daemon +// Loaded: loaded (/nix/store/qc312qcy907wz80fqrgbbm8a9djafmlg-unit-tailscale.service/tailscale.service; enabled; vendor preset: enabled) +// Active: active (running) since Tue 2020-11-24 17:54:07 EST; 13h ago +// Main PID: 26741 (.tailscaled-wra) +// Status: "Connected; user@host.domain.tld; 100.101.102.103" +// IP: 0B in, 0B out +// Tasks: 22 (limit: 4915) +// Memory: 30.9M +// CPU: 2min 38.469s +// CGroup: /system.slice/tailscale.service +// └─26741 /nix/store/sv6cj4mw2jajm9xkbwj07k29dj30lh0n-tailscale-date.20200727/bin/tailscaled --port 41641 func Status(format string, args ...any) { err := notifier().Notify(sdnotify.Statusf(format, args...)) if err != nil { diff --git a/wgengine/filter/filter.go b/wgengine/filter/filter.go index e7faf8eaf..f2bc004af 100644 --- a/wgengine/filter/filter.go +++ b/wgengine/filter/filter.go @@ -245,17 +245,17 @@ func maybeHexdump(flag RunFlags, b []byte) string { } // TODO(apenwarr): use a bigger bucket for specifically TCP SYN accept logging? -// Logging is a quick way to record every newly opened TCP connection, but -// we have to be cautious about flooding the logs vs letting people use -// flood protection to hide their traffic. We could use a rate limiter in -// the actual *filter* for SYN accepts, perhaps. +// Logging is a quick way to record every newly opened TCP connection, but +// we have to be cautious about flooding the logs vs letting people use +// flood protection to hide their traffic. We could use a rate limiter in +// the actual *filter* for SYN accepts, perhaps. var acceptBucket = rate.NewLimiter(rate.Every(10*time.Second), 3) var dropBucket = rate.NewLimiter(rate.Every(5*time.Second), 10) // NOTE(Xe): This func init is used to detect -// TS_DEBUG_FILTER_RATE_LIMIT_LOGS=all, and if it matches, to -// effectively disable the limits on the log rate by setting the limit -// to 1 millisecond. This should capture everything. +// TS_DEBUG_FILTER_RATE_LIMIT_LOGS=all, and if it matches, to +// effectively disable the limits on the log rate by setting the limit +// to 1 millisecond. This should capture everything. func init() { if envknob.String("TS_DEBUG_FILTER_RATE_LIMIT_LOGS") != "all" { return diff --git a/wgengine/filter/tailcfg.go b/wgengine/filter/tailcfg.go index fea673f2f..a0abc0da3 100644 --- a/wgengine/filter/tailcfg.go +++ b/wgengine/filter/tailcfg.go @@ -102,10 +102,10 @@ var ( // parseIPSet parses arg as one: // -// * an IP address (IPv4 or IPv6) -// * the string "*" to match everything (both IPv4 & IPv6) -// * a CIDR (e.g. "192.168.0.0/16") -// * a range of two IPs, inclusive, separated by hyphen ("2eff::1-2eff::0800") +// - an IP address (IPv4 or IPv6) +// - the string "*" to match everything (both IPv4 & IPv6) +// - a CIDR (e.g. "192.168.0.0/16") +// - a range of two IPs, inclusive, separated by hyphen ("2eff::1-2eff::0800") // // bits, if non-nil, is the legacy SrcBits CIDR length to make a IP // address (without a slash) treated as a CIDR of *bits length. diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index ec846e953..5dfdb00fb 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -1833,10 +1833,10 @@ func (c *Conn) sendDiscoMessage(dst netip.AddrPort, dstKey key.NodePublic, dstDi // // A discovery message has the form: // -// * magic [6]byte -// * senderDiscoPubKey [32]byte -// * nonce [24]byte -// * naclbox of payload (see tailscale.com/disco package for inner payload format) +// - magic [6]byte +// - senderDiscoPubKey [32]byte +// - nonce [24]byte +// - naclbox of payload (see tailscale.com/disco package for inner payload format) // // For messages received over DERP, the src.Addr() will be derpMagicIP (with // src.Port() being the region ID) and the derpNodeSrc will be the node key diff --git a/wgengine/userspace.go b/wgengine/userspace.go index ca4aecdc6..949806c7b 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -517,8 +517,8 @@ func (e *userspaceEngine) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper) // pollResolver reads packets from the DNS resolver and injects them inbound. // -// TODO(tom): Remove this fallback path (via NextPacket()) once -// all platforms use netstack. +// TODO(tom): Remove this fallback path (via NextPacket()) once all +// platforms use netstack. func (e *userspaceEngine) pollResolver() { for { bs, err := e.dns.NextPacket() @@ -1503,7 +1503,6 @@ func (e *userspaceEngine) WhoIsIPPort(ipport netip.AddrPort) (tsIP netip.Addr, o // If none is found in the wireguard config but one is found in // the netmap, it's described in an error. // -// // peerForIP acquires both e.mu and e.wgLock, but neither at the same // time. func (e *userspaceEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) {