@ -15,6 +15,7 @@ import (
"log"
"log"
"time"
"time"
"tailscale.com/envknob"
"tailscale.com/tailcfg"
"tailscale.com/tailcfg"
"tailscale.com/types/logger"
"tailscale.com/types/logger"
"tailscale.com/types/structs"
"tailscale.com/types/structs"
@ -116,7 +117,7 @@ func (bs *BackendServer) send(n Notify) {
if bs . sendNotifyMsg == nil {
if bs . sendNotifyMsg == nil {
return
return
}
}
n . Version = version. Long
n . Version = ipcVersion
bs . sendNotifyMsg ( n )
bs . sendNotifyMsg ( n )
}
}
@ -153,9 +154,9 @@ func (bs *BackendServer) GotCommandMsg(ctx context.Context, b []byte) error {
const ErrMsgPermissionDenied = "permission denied"
const ErrMsgPermissionDenied = "permission denied"
func ( bs * BackendServer ) GotCommand ( ctx context . Context , cmd * Command ) error {
func ( bs * BackendServer ) GotCommand ( ctx context . Context , cmd * Command ) error {
if cmd . Version != version. Long && ! cmd . AllowVersionSkew {
if cmd . Version != ipcVersion && ! cmd . AllowVersionSkew {
vs := fmt . Sprintf ( "GotCommand: Version mismatch! frontend=%#v backend=%#v" ,
vs := fmt . Sprintf ( "GotCommand: Version mismatch! frontend=%#v backend=%#v" ,
cmd . Version , version. Long )
cmd . Version , ipcVersion )
bs . logf ( "%s" , vs )
bs . logf ( "%s" , vs )
// ignore the command, but send a message back to the
// ignore the command, but send a message back to the
// caller so it can realize the version mismatch too.
// caller so it can realize the version mismatch too.
@ -228,6 +229,19 @@ func NewBackendClient(logf logger.Logf, sendCommandMsg func(jsonb []byte)) *Back
}
}
}
}
// IPCVersion returns version.Long usually, unless TS_DEBUG_FAKE_IPC_VERSION is
// set, in which it contains that value. This is only used for weird development
// cases when testing mismatched versions and you want the client to act like it's
// compatible with the server.
func IPCVersion ( ) string {
if v := envknob . String ( "TS_DEBUG_FAKE_IPC_VERSION" ) ; v != "" {
return v
}
return version . Long
}
var ipcVersion = IPCVersion ( )
func ( bc * BackendClient ) GotNotifyMsg ( b [ ] byte ) {
func ( bc * BackendClient ) GotNotifyMsg ( b [ ] byte ) {
if len ( b ) == 0 {
if len ( b ) == 0 {
// not interesting
// not interesting
@ -240,9 +254,9 @@ func (bc *BackendClient) GotNotifyMsg(b []byte) {
if err := json . Unmarshal ( b , & n ) ; err != nil {
if err := json . Unmarshal ( b , & n ) ; err != nil {
log . Fatalf ( "BackendClient.Notify: cannot decode message (length=%d, %#q): %v" , len ( b ) , b , err )
log . Fatalf ( "BackendClient.Notify: cannot decode message (length=%d, %#q): %v" , len ( b ) , b , err )
}
}
if n . Version != version. Long && ! bc . AllowVersionSkew {
if n . Version != ipcVersion && ! bc . AllowVersionSkew {
vs := fmt . Sprintf ( "GotNotify: Version mismatch! frontend=%#v backend=%#v" ,
vs := fmt . Sprintf ( "GotNotify: Version mismatch! frontend=%#v backend=%#v" ,
version. Long , n . Version )
ipcVersion , n . Version )
bc . logf ( "%s" , vs )
bc . logf ( "%s" , vs )
// delete anything in the notification except the version,
// delete anything in the notification except the version,
// to prevent incorrect operation.
// to prevent incorrect operation.
@ -257,7 +271,7 @@ func (bc *BackendClient) GotNotifyMsg(b []byte) {
}
}
func ( bc * BackendClient ) send ( cmd Command ) {
func ( bc * BackendClient ) send ( cmd Command ) {
cmd . Version = version. Long
cmd . Version = ipcVersion
b , err := json . Marshal ( cmd )
b , err := json . Marshal ( cmd )
if err != nil {
if err != nil {
log . Fatalf ( "Failed json.Marshal(cmd): %v\n" , err )
log . Fatalf ( "Failed json.Marshal(cmd): %v\n" , err )