mirror of
https://github.com/jsiebens/ionscale.git
synced 2026-03-31 15:07:49 +01:00
feat: view and enable routes on machines
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/muesli/coral"
|
||||
"github.com/nleeper/goment"
|
||||
"github.com/rodaine/table"
|
||||
"inet.af/netaddr"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -19,6 +20,8 @@ func machineCommands() *coral.Command {
|
||||
|
||||
command.AddCommand(deleteMachineCommand())
|
||||
command.AddCommand(listMachinesCommand())
|
||||
command.AddCommand(getMachineRoutesCommand())
|
||||
command.AddCommand(setMachineRoutesCommand())
|
||||
|
||||
return command
|
||||
}
|
||||
@@ -109,3 +112,88 @@ func listMachinesCommand() *coral.Command {
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func getMachineRoutesCommand() *coral.Command {
|
||||
command := &coral.Command{
|
||||
Use: "get-routes",
|
||||
Short: "Show the routes of a machine",
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
var machineID uint64
|
||||
var target = Target{}
|
||||
target.prepareCommand(command)
|
||||
command.Flags().Uint64Var(&machineID, "machine-id", 0, "")
|
||||
|
||||
command.RunE = func(command *coral.Command, args []string) error {
|
||||
grpcClient, c, err := target.createGRPCClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer safeClose(c)
|
||||
|
||||
req := api.GetMachineRoutesRequest{MachineId: machineID}
|
||||
resp, err := grpcClient.GetMachineRoutes(context.Background(), &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tbl := table.New("ROUTE", "ALLOWED")
|
||||
for _, r := range resp.Routes {
|
||||
tbl.AddRow(r.Advertised, r.Allowed)
|
||||
}
|
||||
tbl.Print()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
func setMachineRoutesCommand() *coral.Command {
|
||||
command := &coral.Command{
|
||||
Use: "set-routes",
|
||||
Short: "Enable routes of a machine",
|
||||
SilenceUsage: true,
|
||||
}
|
||||
|
||||
var machineID uint64
|
||||
var allowedIps []string
|
||||
var target = Target{}
|
||||
target.prepareCommand(command)
|
||||
command.Flags().Uint64Var(&machineID, "machine-id", 0, "")
|
||||
command.Flags().StringSliceVar(&allowedIps, "allowed-ips", []string{}, "")
|
||||
|
||||
command.RunE = func(command *coral.Command, args []string) error {
|
||||
client, c, err := target.createGRPCClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer safeClose(c)
|
||||
|
||||
var prefixes []netaddr.IPPrefix
|
||||
for _, r := range allowedIps {
|
||||
p, err := netaddr.ParseIPPrefix(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prefixes = append(prefixes, p)
|
||||
}
|
||||
|
||||
req := api.SetMachineRoutesRequest{MachineId: machineID, AllowedIps: allowedIps}
|
||||
resp, err := client.SetMachineRoutes(context.Background(), &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tbl := table.New("ROUTE", "ALLOWED")
|
||||
for _, r := range resp.Routes {
|
||||
tbl.AddRow(r.Advertised, r.Allowed)
|
||||
}
|
||||
tbl.Print()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ type Machine struct {
|
||||
|
||||
HostInfo HostInfo
|
||||
Endpoints Endpoints
|
||||
AllowIPs AllowIPs
|
||||
|
||||
IPv4 IP
|
||||
IPv6 IP
|
||||
@@ -56,6 +57,15 @@ func (m *Machine) HasTag(tag string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Machine) IsAllowedIP(i netaddr.IPPrefix) bool {
|
||||
for _, t := range m.AllowIPs {
|
||||
if t.Overlaps(i) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type IP struct {
|
||||
*netaddr.IP
|
||||
}
|
||||
@@ -81,6 +91,36 @@ func (i IP) Value() (driver.Value, error) {
|
||||
return i.String(), nil
|
||||
}
|
||||
|
||||
type AllowIPs []netaddr.IPPrefix
|
||||
|
||||
func (hi *AllowIPs) Scan(destination interface{}) error {
|
||||
switch value := destination.(type) {
|
||||
case []byte:
|
||||
return json.Unmarshal(value, hi)
|
||||
default:
|
||||
return fmt.Errorf("unexpected data type %T", destination)
|
||||
}
|
||||
}
|
||||
|
||||
func (hi AllowIPs) Value() (driver.Value, error) {
|
||||
bytes, err := json.Marshal(hi)
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
// GormDataType gorm common data type
|
||||
func (AllowIPs) GormDataType() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
// GormDBDataType gorm db data type
|
||||
func (AllowIPs) GormDBDataType(db *gorm.DB, field *schema.Field) string {
|
||||
switch db.Dialector.Name() {
|
||||
case "sqlite":
|
||||
return "JSON"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type HostInfo tailcfg.Hostinfo
|
||||
|
||||
func (hi *HostInfo) Scan(destination interface{}) error {
|
||||
|
||||
@@ -116,6 +116,8 @@ func ToNode(m *domain.Machine, connected bool) (*tailcfg.Node, error) {
|
||||
allowedIPs = append(allowedIPs, ipv6)
|
||||
}
|
||||
|
||||
allowedIPs = append(allowedIPs, m.AllowIPs...)
|
||||
|
||||
var derp string
|
||||
if hostinfo.NetInfo != nil {
|
||||
derp = fmt.Sprintf("127.3.3.40:%d", hostinfo.NetInfo.PreferredDERP)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
func (s *Service) ListMachines(ctx context.Context, req *api.ListMachinesRequest) (*api.ListMachinesResponse, error) {
|
||||
@@ -75,3 +76,78 @@ func (s *Service) DeleteMachine(ctx context.Context, req *api.DeleteMachineReque
|
||||
|
||||
return &api.DeleteMachineResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetMachineRoutes(ctx context.Context, req *api.GetMachineRoutesRequest) (*api.GetMachineRoutesResponse, error) {
|
||||
|
||||
m, err := s.repository.GetMachine(ctx, req.MachineId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m == nil {
|
||||
return nil, status.Error(codes.NotFound, "machine does not exist")
|
||||
}
|
||||
|
||||
var routes []*api.RoutableIP
|
||||
for _, r := range m.HostInfo.RoutableIPs {
|
||||
routes = append(routes, &api.RoutableIP{
|
||||
Advertised: r.String(),
|
||||
Allowed: m.IsAllowedIP(r),
|
||||
})
|
||||
}
|
||||
|
||||
response := api.GetMachineRoutesResponse{
|
||||
Routes: routes,
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (s *Service) SetMachineRoutes(ctx context.Context, req *api.SetMachineRoutesRequest) (*api.GetMachineRoutesResponse, error) {
|
||||
m, err := s.repository.GetMachine(ctx, req.MachineId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m == nil {
|
||||
return nil, status.Error(codes.NotFound, "machine does not exist")
|
||||
}
|
||||
|
||||
var allowedIps []netaddr.IPPrefix
|
||||
for _, r := range req.AllowedIps {
|
||||
prefix, err := netaddr.ParseIPPrefix(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allowedIps = append(allowedIps, prefix)
|
||||
}
|
||||
|
||||
m.AllowIPs = allowedIps
|
||||
if err := s.repository.SaveMachine(ctx, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.brokers(m.TailnetID).SignalPeerUpdated(m.ID)
|
||||
|
||||
var routes []*api.RoutableIP
|
||||
for _, r := range m.HostInfo.RoutableIPs {
|
||||
routes = append(routes, &api.RoutableIP{
|
||||
Advertised: r.String(),
|
||||
Allowed: m.IsAllowedIP(r),
|
||||
})
|
||||
}
|
||||
|
||||
response := api.GetMachineRoutesResponse{
|
||||
Routes: routes,
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func mapIp(ip []netaddr.IPPrefix) []string {
|
||||
var x = []string{}
|
||||
for _, i := range ip {
|
||||
x = append(x, i.String())
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user