mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-07-04 01:07:49 +02:00
all: add clients list command to debug Mac discovery
This commit is contained in:
committed by
Cuong Manh Le
parent
61b6431b6e
commit
437fb1b16d
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -26,6 +27,7 @@ import (
|
|||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/kardianos/service"
|
"github.com/kardianos/service"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
"github.com/olekukonko/tablewriter"
|
||||||
"github.com/pelletier/go-toml/v2"
|
"github.com/pelletier/go-toml/v2"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -35,6 +37,7 @@ import (
|
|||||||
"tailscale.com/net/interfaces"
|
"tailscale.com/net/interfaces"
|
||||||
|
|
||||||
"github.com/Control-D-Inc/ctrld"
|
"github.com/Control-D-Inc/ctrld"
|
||||||
|
"github.com/Control-D-Inc/ctrld/internal/clientinfo"
|
||||||
"github.com/Control-D-Inc/ctrld/internal/controld"
|
"github.com/Control-D-Inc/ctrld/internal/controld"
|
||||||
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
|
ctrldnet "github.com/Control-D-Inc/ctrld/internal/net"
|
||||||
"github.com/Control-D-Inc/ctrld/internal/router"
|
"github.com/Control-D-Inc/ctrld/internal/router"
|
||||||
@@ -751,6 +754,66 @@ NOTE: Uninstalling will set DNS to values provided by DHCP.`,
|
|||||||
uninstallCmdAlias.Flags().StringVarP(&ifaceStartStop, "iface", "", "auto", `Reset DNS setting for iface, "auto" means the default interface gateway`)
|
uninstallCmdAlias.Flags().StringVarP(&ifaceStartStop, "iface", "", "auto", `Reset DNS setting for iface, "auto" means the default interface gateway`)
|
||||||
uninstallCmdAlias.Flags().AddFlagSet(stopCmd.Flags())
|
uninstallCmdAlias.Flags().AddFlagSet(stopCmd.Flags())
|
||||||
rootCmd.AddCommand(uninstallCmdAlias)
|
rootCmd.AddCommand(uninstallCmdAlias)
|
||||||
|
|
||||||
|
listClientsCmd := &cobra.Command{
|
||||||
|
Use: "list",
|
||||||
|
Short: "List clients that ctrld discovered",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
|
initConsoleLogging()
|
||||||
|
checkHasElevatedPrivilege()
|
||||||
|
},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
dir, err := userHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
mainLog.Fatal().Err(err).Msg("failed to find ctrld home dir")
|
||||||
|
}
|
||||||
|
cc := newControlClient(filepath.Join(dir, ctrldControlUnixSock))
|
||||||
|
resp, err := cc.post(listClientsPath, nil)
|
||||||
|
if err != nil {
|
||||||
|
mainLog.Fatal().Err(err).Msg("failed to get clients list")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var clients []*clientinfo.Client
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&clients); err != nil {
|
||||||
|
mainLog.Fatal().Err(err).Msg("failed to decode clients list result")
|
||||||
|
}
|
||||||
|
map2Slice := func(m map[string]struct{}) []string {
|
||||||
|
s := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
s = append(s, k)
|
||||||
|
}
|
||||||
|
sort.Strings(s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
data := make([][]string, len(clients))
|
||||||
|
for i, c := range clients {
|
||||||
|
row := []string{
|
||||||
|
c.IP.String(),
|
||||||
|
c.Hostname,
|
||||||
|
c.Mac,
|
||||||
|
strings.Join(map2Slice(c.Source), ","),
|
||||||
|
}
|
||||||
|
data[i] = row
|
||||||
|
}
|
||||||
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
|
table.SetHeader([]string{"IP", "Hostname", "Mac", "Discovered"})
|
||||||
|
table.SetAutoFormatHeaders(false)
|
||||||
|
table.AppendBulk(data)
|
||||||
|
table.Render()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
clientsCmd := &cobra.Command{
|
||||||
|
Use: "clients",
|
||||||
|
Short: "Manage clients",
|
||||||
|
Args: cobra.OnlyValidArgs,
|
||||||
|
ValidArgs: []string{
|
||||||
|
listClientsCmd.Use,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
clientsCmd.AddCommand(listClientsCmd)
|
||||||
|
rootCmd.AddCommand(clientsCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeConfigFile() error {
|
func writeConfigFile() error {
|
||||||
|
|||||||
@@ -2,13 +2,18 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const contentTypeJson = "application/json"
|
const (
|
||||||
|
contentTypeJson = "application/json"
|
||||||
|
listClientsPath = "/clients"
|
||||||
|
)
|
||||||
|
|
||||||
type controlServer struct {
|
type controlServer struct {
|
||||||
server *http.Server
|
server *http.Server
|
||||||
@@ -48,7 +53,16 @@ func (s *controlServer) register(pattern string, handler http.Handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *prog) registerControlServerHandler() {
|
func (p *prog) registerControlServerHandler() {
|
||||||
// TODO: register handler here.
|
p.cs.mux.Handle(listClientsPath, http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
|
||||||
|
clients := p.ciTable.ListClients()
|
||||||
|
sort.Slice(clients, func(i, j int) bool {
|
||||||
|
return clients[i].IP.Less(clients[j].IP)
|
||||||
|
})
|
||||||
|
if err := json.NewEncoder(w).Encode(&clients); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func jsonResponse(next http.Handler) http.Handler {
|
func jsonResponse(next http.Handler) http.Handler {
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ require (
|
|||||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
|
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86
|
||||||
github.com/kardianos/service v1.2.1
|
github.com/kardianos/service v1.2.1
|
||||||
github.com/miekg/dns v1.1.55
|
github.com/miekg/dns v1.1.55
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8
|
github.com/pelletier/go-toml/v2 v2.0.8
|
||||||
github.com/quic-go/quic-go v0.32.0
|
github.com/quic-go/quic-go v0.32.0
|
||||||
github.com/rs/zerolog v1.28.0
|
github.com/rs/zerolog v1.28.0
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/spf13/viper v1.16.0
|
github.com/spf13/viper v1.16.0
|
||||||
github.com/stretchr/testify v1.8.3
|
github.com/stretchr/testify v1.8.3
|
||||||
github.com/vishvananda/netlink v1.2.1-beta.2
|
github.com/vishvananda/netlink v1.2.1-beta.2
|
||||||
@@ -48,6 +50,7 @@ require (
|
|||||||
github.com/magiconair/properties v1.8.7 // indirect
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 // indirect
|
||||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||||
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 // indirect
|
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 // indirect
|
||||||
@@ -60,11 +63,11 @@ require (
|
|||||||
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
|
github.com/quic-go/qtls-go1-18 v0.2.0 // indirect
|
||||||
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
|
github.com/quic-go/qtls-go1-19 v0.2.0 // indirect
|
||||||
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
|
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||||
github.com/spf13/afero v1.9.5 // indirect
|
github.com/spf13/afero v1.9.5 // indirect
|
||||||
github.com/spf13/cast v1.5.1 // indirect
|
github.com/spf13/cast v1.5.1 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
|
||||||
github.com/subosito/gotenv v1.4.2 // indirect
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect
|
github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect
|
||||||
github.com/vishvananda/netns v0.0.4 // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
|
|||||||
@@ -193,6 +193,9 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE=
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE=
|
||||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||||
@@ -206,6 +209,8 @@ github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
|
|||||||
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||||
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||||
@@ -230,6 +235,9 @@ github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV5
|
|||||||
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||||
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
|
github.com/quic-go/quic-go v0.32.0 h1:lY02md31s1JgPiiyfqJijpu/UX/Iun304FI3yUqX7tA=
|
||||||
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
|
github.com/quic-go/quic-go v0.32.0/go.mod h1:/fCsKANhQIeD5l76c2JFU+07gVE3KaA0FP+0zMWwfwo=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
|
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
|||||||
@@ -27,3 +27,20 @@ func (a *arpDiscover) LookupMac(ip string) string {
|
|||||||
}
|
}
|
||||||
return val.(string)
|
return val.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *arpDiscover) String() string {
|
||||||
|
return "arp"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *arpDiscover) List() []string {
|
||||||
|
var ips []string
|
||||||
|
a.ip.Range(func(key, value any) bool {
|
||||||
|
ips = append(ips, value.(string))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
a.mac.Range(func(key, value any) bool {
|
||||||
|
ips = append(ips, key.(string))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return ips
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package clientinfo
|
package clientinfo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -9,25 +11,35 @@ import (
|
|||||||
|
|
||||||
// IpResolver is the interface for retrieving IP from Mac.
|
// IpResolver is the interface for retrieving IP from Mac.
|
||||||
type IpResolver interface {
|
type IpResolver interface {
|
||||||
|
fmt.Stringer
|
||||||
|
// LookupIP returns ip of the device with given mac.
|
||||||
LookupIP(mac string) string
|
LookupIP(mac string) string
|
||||||
|
// List returns list of ip known by the resolver.
|
||||||
|
List() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// MacResolver is the interface for retrieving Mac from IP.
|
// MacResolver is the interface for retrieving Mac from IP.
|
||||||
type MacResolver interface {
|
type MacResolver interface {
|
||||||
|
fmt.Stringer
|
||||||
|
// LookupMac returns mac of the device with given ip.
|
||||||
LookupMac(ip string) string
|
LookupMac(ip string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// HostnameByIpResolver is the interface for retrieving hostname from IP.
|
// HostnameByIpResolver is the interface for retrieving hostname from IP.
|
||||||
type HostnameByIpResolver interface {
|
type HostnameByIpResolver interface {
|
||||||
|
// LookupHostnameByIP returns hostname of the given ip.
|
||||||
LookupHostnameByIP(ip string) string
|
LookupHostnameByIP(ip string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// HostnameByMacResolver is the interface for retrieving hostname from Mac.
|
// HostnameByMacResolver is the interface for retrieving hostname from Mac.
|
||||||
type HostnameByMacResolver interface {
|
type HostnameByMacResolver interface {
|
||||||
|
// LookupHostnameByMac returns hostname of the device with given mac.
|
||||||
LookupHostnameByMac(mac string) string
|
LookupHostnameByMac(mac string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HostnameResolver is the interface for retrieving hostname from either IP or Mac.
|
||||||
type HostnameResolver interface {
|
type HostnameResolver interface {
|
||||||
|
fmt.Stringer
|
||||||
HostnameByIpResolver
|
HostnameByIpResolver
|
||||||
HostnameByMacResolver
|
HostnameByMacResolver
|
||||||
}
|
}
|
||||||
@@ -36,6 +48,13 @@ type refresher interface {
|
|||||||
refresh() error
|
refresh() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
IP netip.Addr
|
||||||
|
Mac string
|
||||||
|
Hostname string
|
||||||
|
Source map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
type Table struct {
|
type Table struct {
|
||||||
ipResolvers []IpResolver
|
ipResolvers []IpResolver
|
||||||
macResolvers []MacResolver
|
macResolvers []MacResolver
|
||||||
@@ -146,9 +165,6 @@ func (t *Table) LookupIP(mac string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Table) LookupMac(ip string) string {
|
func (t *Table) LookupMac(ip string) string {
|
||||||
t.arp.mac.Range(func(key, value any) bool {
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
for _, r := range t.macResolvers {
|
for _, r := range t.macResolvers {
|
||||||
if mac := r.LookupMac(ip); mac != "" {
|
if mac := r.LookupMac(ip); mac != "" {
|
||||||
return mac
|
return mac
|
||||||
@@ -169,6 +185,86 @@ func (t *Table) LookupHostname(ip, mac string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type macEntry struct {
|
||||||
|
mac string
|
||||||
|
src string
|
||||||
|
}
|
||||||
|
|
||||||
|
type hostnameEntry struct {
|
||||||
|
name string
|
||||||
|
src string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Table) lookupMacAll(ip string) []*macEntry {
|
||||||
|
var res []*macEntry
|
||||||
|
for _, r := range t.macResolvers {
|
||||||
|
res = append(res, &macEntry{mac: r.LookupMac(ip), src: r.String()})
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Table) lookupHostnameAll(ip, mac string) []*hostnameEntry {
|
||||||
|
var res []*hostnameEntry
|
||||||
|
for _, r := range t.hostnameResolvers {
|
||||||
|
src := r.String()
|
||||||
|
if name := r.LookupHostnameByIP(ip); name != "" {
|
||||||
|
res = append(res, &hostnameEntry{name: name, src: src})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if name := r.LookupHostnameByMac(mac); name != "" {
|
||||||
|
res = append(res, &hostnameEntry{name: name, src: src})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListClients returns list of clients discovered by ctrld.
|
||||||
|
func (t *Table) ListClients() []*Client {
|
||||||
|
for _, r := range t.refreshers {
|
||||||
|
_ = r.refresh()
|
||||||
|
}
|
||||||
|
ipMap := make(map[string]*Client)
|
||||||
|
for _, ir := range t.ipResolvers {
|
||||||
|
for _, ip := range ir.List() {
|
||||||
|
c, ok := ipMap[ip]
|
||||||
|
if !ok {
|
||||||
|
c = &Client{
|
||||||
|
IP: netip.MustParseAddr(ip),
|
||||||
|
Source: map[string]struct{}{ir.String(): {}},
|
||||||
|
}
|
||||||
|
ipMap[ip] = c
|
||||||
|
} else {
|
||||||
|
c.Source[ir.String()] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ip := range ipMap {
|
||||||
|
c := ipMap[ip]
|
||||||
|
for _, e := range t.lookupMacAll(ip) {
|
||||||
|
if c.Mac == "" && e.mac != "" {
|
||||||
|
c.Mac = e.mac
|
||||||
|
}
|
||||||
|
if e.mac != "" {
|
||||||
|
c.Source[e.src] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, e := range t.lookupHostnameAll(ip, c.Mac) {
|
||||||
|
if c.Hostname == "" && e.name != "" {
|
||||||
|
c.Hostname = e.name
|
||||||
|
}
|
||||||
|
if e.name != "" {
|
||||||
|
c.Source[e.src] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clients := make([]*Client, 0, len(ipMap))
|
||||||
|
for _, c := range ipMap {
|
||||||
|
clients = append(clients, c)
|
||||||
|
}
|
||||||
|
return clients
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Table) discoverDHCP() bool {
|
func (t *Table) discoverDHCP() bool {
|
||||||
if t.cfg.Service.DiscoverDHCP == nil {
|
if t.cfg.Service.DiscoverDHCP == nil {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -100,6 +100,23 @@ func (d *dhcp) LookupHostnameByMac(mac string) string {
|
|||||||
return val.(string)
|
return val.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dhcp) String() string {
|
||||||
|
return "dhcp"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dhcp) List() []string {
|
||||||
|
var ips []string
|
||||||
|
d.ip.Range(func(key, value any) bool {
|
||||||
|
ips = append(ips, value.(string))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
d.mac.Range(func(key, value any) bool {
|
||||||
|
ips = append(ips, key.(string))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return ips
|
||||||
|
}
|
||||||
|
|
||||||
// AddLeaseFile adds given lease file for reading/watching clients info.
|
// AddLeaseFile adds given lease file for reading/watching clients info.
|
||||||
func (d *dhcp) addLeaseFile(name string, format ctrld.LeaseFileFormat) error {
|
func (d *dhcp) addLeaseFile(name string, format ctrld.LeaseFileFormat) error {
|
||||||
if d.watcher == nil {
|
if d.watcher == nil {
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ func (m *mdns) LookupHostnameByMac(mac string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mdns) String() string {
|
||||||
|
return "mdns"
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mdns) init(quitCh chan struct{}) error {
|
func (m *mdns) init(quitCh chan struct{}) error {
|
||||||
ifaces, err := multicastInterfaces()
|
ifaces, err := multicastInterfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -65,3 +65,7 @@ func (m *merlinDiscover) parseMerlinCustomClientList(data string) {
|
|||||||
m.hostname.Store(mac, hostname)
|
m.hostname.Store(mac, hostname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *merlinDiscover) String() string {
|
||||||
|
return "merlin"
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ func (p *ptrDiscover) LookupHostnameByMac(mac string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ptrDiscover) String() string {
|
||||||
|
return "ptr"
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ptrDiscover) lookupHostname(ip string) string {
|
func (p *ptrDiscover) lookupHostname(ip string) string {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|||||||
Reference in New Issue
Block a user