mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-16 11:41:39 +00:00
ipn: handle advertised routes provided by frontend.
Signed-off-by: David Anderson <dave@natulte.net>
This commit is contained in:
parent
5d79530caa
commit
47da432991
@ -17,6 +17,7 @@ import (
|
|||||||
|
|
||||||
"github.com/apenwarr/fixconsole"
|
"github.com/apenwarr/fixconsole"
|
||||||
"github.com/pborman/getopt/v2"
|
"github.com/pborman/getopt/v2"
|
||||||
|
"github.com/tailscale/wireguard-go/wgcfg"
|
||||||
"tailscale.com/ipn"
|
"tailscale.com/ipn"
|
||||||
"tailscale.com/logpolicy"
|
"tailscale.com/logpolicy"
|
||||||
"tailscale.com/safesocket"
|
"tailscale.com/safesocket"
|
||||||
@ -55,6 +56,7 @@ func main() {
|
|||||||
nuroutes := getopt.BoolLong("no-single-routes", 'N', "disallow (non-subnet) routes to single nodes")
|
nuroutes := getopt.BoolLong("no-single-routes", 'N', "disallow (non-subnet) routes to single nodes")
|
||||||
routeall := getopt.BoolLong("remote-routes", 'R', "accept routes advertised by remote nodes")
|
routeall := getopt.BoolLong("remote-routes", 'R', "accept routes advertised by remote nodes")
|
||||||
nopf := getopt.BoolLong("no-packet-filter", 'F', "disable packet filter")
|
nopf := getopt.BoolLong("no-packet-filter", 'F', "disable packet filter")
|
||||||
|
advroutes := getopt.ListLong("routes", 'r', "routes to advertise to other nodes (comma-separated, e.g. 10.0.0.0/8,192.168.1.0/24)")
|
||||||
getopt.Parse()
|
getopt.Parse()
|
||||||
pol := logpolicy.New("tailnode.log.tailscale.io", "tailscale")
|
pol := logpolicy.New("tailnode.log.tailscale.io", "tailscale")
|
||||||
if len(getopt.Args()) > 0 {
|
if len(getopt.Args()) > 0 {
|
||||||
@ -63,6 +65,15 @@ func main() {
|
|||||||
|
|
||||||
defer pol.Close()
|
defer pol.Close()
|
||||||
|
|
||||||
|
var adv []wgcfg.CIDR
|
||||||
|
for _, s := range *advroutes {
|
||||||
|
cidr, err := wgcfg.ParseCIDR(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%q is not a valid CIDR prefix: %v", s, err)
|
||||||
|
}
|
||||||
|
adv = append(adv, *cidr)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(apenwarr): fix different semantics between prefs and uflags
|
// TODO(apenwarr): fix different semantics between prefs and uflags
|
||||||
// TODO(apenwarr): allow setting/using CorpDNS
|
// TODO(apenwarr): allow setting/using CorpDNS
|
||||||
prefs := ipn.Prefs{
|
prefs := ipn.Prefs{
|
||||||
@ -70,6 +81,7 @@ func main() {
|
|||||||
RouteAll: *routeall,
|
RouteAll: *routeall,
|
||||||
AllowSingleHosts: !*nuroutes,
|
AllowSingleHosts: !*nuroutes,
|
||||||
UsePacketFilter: !*nopf,
|
UsePacketFilter: !*nopf,
|
||||||
|
AdvertiseRoutes: adv,
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := safesocket.Connect("", "Tailscale", "tailscaled", 41112)
|
c, err := safesocket.Connect("", "Tailscale", "tailscaled", 41112)
|
||||||
|
11
ipn/local.go
11
ipn/local.go
@ -156,6 +156,8 @@ func (b *LocalBackend) Start(opts Options) error {
|
|||||||
return fmt.Errorf("loading requested state: %v", err)
|
return fmt.Errorf("loading requested state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hi.RoutableIPs = append(hi.RoutableIPs, b.prefs.AdvertiseRoutes...)
|
||||||
|
|
||||||
b.notify = opts.Notify
|
b.notify = opts.Notify
|
||||||
b.netMapCache = nil
|
b.netMapCache = nil
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
@ -502,8 +504,17 @@ func (b *LocalBackend) SetPrefs(new Prefs) {
|
|||||||
b.logf("Failed to save new controlclient state: %v", err)
|
b.logf("Failed to save new controlclient state: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
oldHi := b.hiCache
|
||||||
|
newHi := oldHi.Copy()
|
||||||
|
newHi.RoutableIPs = append([]wgcfg.CIDR(nil), b.prefs.AdvertiseRoutes...)
|
||||||
|
b.hiCache = *newHi
|
||||||
|
cli := b.c
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
|
|
||||||
|
if cli != nil && !oldHi.Equal(newHi) {
|
||||||
|
cli.SetHostinfo(*newHi)
|
||||||
|
}
|
||||||
|
|
||||||
if old.WantRunning != new.WantRunning {
|
if old.WantRunning != new.WantRunning {
|
||||||
b.stateMachine()
|
b.stateMachine()
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,15 +5,14 @@
|
|||||||
package ipn
|
package ipn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/tailscale/wireguard-go/wgcfg"
|
||||||
"tailscale.com/atomicfile"
|
"tailscale.com/atomicfile"
|
||||||
"tailscale.com/control/controlclient"
|
"tailscale.com/control/controlclient"
|
||||||
)
|
)
|
||||||
@ -44,7 +43,7 @@ type Prefs struct {
|
|||||||
UsePacketFilter bool
|
UsePacketFilter bool
|
||||||
// AdvertiseRoutes specifies CIDR prefixes to advertise into the
|
// AdvertiseRoutes specifies CIDR prefixes to advertise into the
|
||||||
// Tailscale network as reachable through the current node.
|
// Tailscale network as reachable through the current node.
|
||||||
AdvertiseRoutes []*net.IPNet
|
AdvertiseRoutes []wgcfg.CIDR
|
||||||
|
|
||||||
// NotepadURLs is a debugging setting that opens OAuth URLs in
|
// NotepadURLs is a debugging setting that opens OAuth URLs in
|
||||||
// notepad.exe on Windows, rather than loading them in a browser.
|
// notepad.exe on Windows, rather than loading them in a browser.
|
||||||
@ -102,12 +101,12 @@ func (p *Prefs) Equals(p2 *Prefs) bool {
|
|||||||
p.Persist.Equals(p2.Persist)
|
p.Persist.Equals(p2.Persist)
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareIPNets(a, b []*net.IPNet) bool {
|
func compareIPNets(a, b []wgcfg.CIDR) bool {
|
||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := range a {
|
for i := range a {
|
||||||
if !a[i].IP.Equal(b[i].IP) || !bytes.Equal(a[i].Mask, b[i].Mask) {
|
if !a[i].IP.Equal(&b[i].IP) || a[i].Mask != b[i].Mask {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@
|
|||||||
package ipn
|
package ipn
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/tailscale/wireguard-go/wgcfg"
|
||||||
"tailscale.com/control/controlclient"
|
"tailscale.com/control/controlclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,13 +26,13 @@ func TestPrefsEqual(t *testing.T) {
|
|||||||
have, prefsHandles)
|
have, prefsHandles)
|
||||||
}
|
}
|
||||||
|
|
||||||
nets := func(strs ...string) (ns []*net.IPNet) {
|
nets := func(strs ...string) (ns []wgcfg.CIDR) {
|
||||||
for _, s := range strs {
|
for _, s := range strs {
|
||||||
_, n, err := net.ParseCIDR(s)
|
n, err := wgcfg.ParseCIDR(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ns = append(ns, n)
|
ns = append(ns, *n)
|
||||||
}
|
}
|
||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
@ -124,12 +124,12 @@ func TestPrefsEqual(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
&Prefs{AdvertiseRoutes: nil},
|
&Prefs{AdvertiseRoutes: nil},
|
||||||
&Prefs{AdvertiseRoutes: []*net.IPNet{}},
|
&Prefs{AdvertiseRoutes: []wgcfg.CIDR{}},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&Prefs{AdvertiseRoutes: []*net.IPNet{}},
|
&Prefs{AdvertiseRoutes: []wgcfg.CIDR{}},
|
||||||
&Prefs{AdvertiseRoutes: []*net.IPNet{}},
|
&Prefs{AdvertiseRoutes: []wgcfg.CIDR{}},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,7 @@ type Hostinfo struct {
|
|||||||
Services []Service `json:",omitempty"` // services advertised by this machine
|
Services []Service `json:",omitempty"` // services advertised by this machine
|
||||||
|
|
||||||
// NOTE: any new fields containing pointers in this type
|
// NOTE: any new fields containing pointers in this type
|
||||||
// require changes to Hostinfo.Copy.
|
// require changes to Hostinfo.Copy and Hostinfo.Equal.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy makes a deep copy of Hostinfo.
|
// Copy makes a deep copy of Hostinfo.
|
||||||
@ -234,6 +234,11 @@ func (hinfo *Hostinfo) Copy() (res *Hostinfo) {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equal reports whether h and h2 are equal.
|
||||||
|
func (h *Hostinfo) Equal(h2 *Hostinfo) bool {
|
||||||
|
return reflect.DeepEqual(h, h2)
|
||||||
|
}
|
||||||
|
|
||||||
type RegisterRequest struct {
|
type RegisterRequest struct {
|
||||||
Version int
|
Version int
|
||||||
NodeKey NodeKey
|
NodeKey NodeKey
|
||||||
|
@ -19,6 +19,143 @@ func fieldsOf(t reflect.Type) (fields []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHostinfoEqual(t *testing.T) {
|
||||||
|
hiHandles := []string{"IPNVersion", "FrontendLogID", "BackendLogID", "OS", "Hostname", "RoutableIPs", "Services"}
|
||||||
|
if have := fieldsOf(reflect.TypeOf(Hostinfo{})); !reflect.DeepEqual(have, hiHandles) {
|
||||||
|
t.Errorf("Hostinfo.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
|
||||||
|
have, hiHandles)
|
||||||
|
}
|
||||||
|
|
||||||
|
nets := func(strs ...string) (ns []wgcfg.CIDR) {
|
||||||
|
for _, s := range strs {
|
||||||
|
n, err := wgcfg.ParseCIDR(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ns = append(ns, *n)
|
||||||
|
}
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
a, b *Hostinfo
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{},
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
&Hostinfo{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{},
|
||||||
|
&Hostinfo{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
&Hostinfo{IPNVersion: "1"},
|
||||||
|
&Hostinfo{IPNVersion: "2"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{IPNVersion: "2"},
|
||||||
|
&Hostinfo{IPNVersion: "2"},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
&Hostinfo{FrontendLogID: "1"},
|
||||||
|
&Hostinfo{FrontendLogID: "2"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{FrontendLogID: "2"},
|
||||||
|
&Hostinfo{FrontendLogID: "2"},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
&Hostinfo{BackendLogID: "1"},
|
||||||
|
&Hostinfo{BackendLogID: "2"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{BackendLogID: "2"},
|
||||||
|
&Hostinfo{BackendLogID: "2"},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
&Hostinfo{OS: "windows"},
|
||||||
|
&Hostinfo{OS: "linux"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{OS: "windows"},
|
||||||
|
&Hostinfo{OS: "windows"},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
&Hostinfo{Hostname: "vega"},
|
||||||
|
&Hostinfo{Hostname: "iris"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{Hostname: "vega"},
|
||||||
|
&Hostinfo{Hostname: "vega"},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
&Hostinfo{RoutableIPs: nil},
|
||||||
|
&Hostinfo{RoutableIPs: nets("10.0.0.0/16")},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
||||||
|
&Hostinfo{RoutableIPs: nets("10.2.0.0/16", "192.168.2.0/24")},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
||||||
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.2.0/24")},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
||||||
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
&Hostinfo{Services: []Service{Service{TCP, 1234, "foo"}}},
|
||||||
|
&Hostinfo{Services: []Service{Service{UDP, 2345, "bar"}}},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Hostinfo{Services: []Service{Service{TCP, 1234, "foo"}}},
|
||||||
|
&Hostinfo{Services: []Service{Service{TCP, 1234, "foo"}}},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
got := tt.a.Equal(tt.b)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("%d. Equal = %v; want %v", i, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNodeEqual(t *testing.T) {
|
func TestNodeEqual(t *testing.T) {
|
||||||
nodeHandles := []string{"ID", "Name", "User", "Key", "KeyExpiry", "Machine", "Addresses", "AllowedIPs", "Endpoints", "Hostinfo", "Created", "LastSeen", "MachineAuthorized"}
|
nodeHandles := []string{"ID", "Name", "User", "Key", "KeyExpiry", "Machine", "Addresses", "AllowedIPs", "Endpoints", "Hostinfo", "Created", "LastSeen", "MachineAuthorized"}
|
||||||
if have := fieldsOf(reflect.TypeOf(Node{})); !reflect.DeepEqual(have, nodeHandles) {
|
if have := fieldsOf(reflect.TypeOf(Node{})); !reflect.DeepEqual(have, nodeHandles) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user