diff --git a/cmd/pgcli/vpn/ipc/client/client.go b/cmd/pgcli/vpn/ipc/client/client.go index f8acb93..0e27308 100644 --- a/cmd/pgcli/vpn/ipc/client/client.go +++ b/cmd/pgcli/vpn/ipc/client/client.go @@ -21,17 +21,27 @@ func PrintPeers() error { "IPv6", "Mode", "NAT", + "Flags", "UDP Endpoints", "Version", }) for _, peer := range peers { + var flags []string + if _, ok := peer.Labels.Get("node.nr"); ok { + flags = append(flags, "NR") + } + if _, ok := peer.Labels.Get("node.off"); ok { + flags = append(flags, "OFF") + peer.Mode = "" + } tw.AppendRow(table.Row{ cmp.Or(peer.Hostname, "-"), cmp.Or(peer.IPv4, "-"), cmp.Or(peer.IPv6, "-"), - peer.Mode, + cmp.Or(peer.Mode, "-"), cmp.Or(peer.NAT, "-"), + cmp.Or(strings.Join(flags, ","), "-"), cmp.Or(strings.Join(peer.Addrs, ","), "-"), peer.Version, }) diff --git a/cmd/pgcli/vpn/ipc/server/http.go b/cmd/pgcli/vpn/ipc/server/http.go index 9c17938..bd6b9a1 100644 --- a/cmd/pgcli/vpn/ipc/server/http.go +++ b/cmd/pgcli/vpn/ipc/server/http.go @@ -109,6 +109,7 @@ type PeerState struct { Mode string `json:"mode"` NAT string `json:"nat"` Version string `json:"version"` + Labels disco.Labels `json:"labels"` } func (s *Server) handleQueryPeers(w http.ResponseWriter, r *http.Request) { @@ -136,6 +137,7 @@ func (s *Server) handleQueryPeers(w http.ResponseWriter, r *http.Request) { Mode: "RELAY", NAT: p.Meta.Get("nat"), Version: p.Meta.Get("version"), + Labels: p.Meta["label"], } if p2pPeer, ok := p2pPeers[disco.PeerID(p.Addr.String())]; ok { state.Mode = "P2P" diff --git a/cmd/pgcli/vpn/vpn.go b/cmd/pgcli/vpn/vpn.go index 37b0694..473f111 100644 --- a/cmd/pgcli/vpn/vpn.go +++ b/cmd/pgcli/vpn/vpn.go @@ -297,8 +297,8 @@ func (v *P2PVPN) listenPacketConn(ctx context.Context) (c *p2p.PacketConn, err e p2pOptions := []p2p.Option{ p2p.PeerMeta("version", Version), p2p.PeerMeta("name", hostname), - p2p.ListenPeerUp(v.addPeer), - p2p.ListenPeerLeave(v.removePeer), + p2p.ListenPeerUp(v.onPeerUp), + p2p.ListenPeerLeave(v.onPeerLeave), p2p.KeepAlivePeriod(6 * time.Second), } for _, l := range v.Config.Labels { @@ -341,12 +341,12 @@ func (v *P2PVPN) listenPacketConn(ctx context.Context) (c *p2p.PacketConn, err e return p2p.ListenPacketContext(ctx, peermap, p2pOptions...) } -func (v *P2PVPN) addPeer(pi disco.PeerID, m url.Values) { +func (v *P2PVPN) onPeerUp(pi disco.PeerID, m url.Values) { v.nic.AddPeer(nic.Peer{Addr: pi, IPv4: m.Get("alias1"), IPv6: m.Get("alias2"), Meta: m}) } -func (v *P2PVPN) removePeer(pi disco.PeerID) { - v.nic.RemovePeer(pi) +func (v *P2PVPN) onPeerLeave(pi disco.PeerID) { + v.nic.LabelPeer(pi, "node.off") } func (v *P2PVPN) loginIfNecessary(ctx context.Context) (disco.SecretStore, error) { diff --git a/vpn/nic/nic.go b/vpn/nic/nic.go index cc10754..d4f2222 100644 --- a/vpn/nic/nic.go +++ b/vpn/nic/nic.go @@ -102,6 +102,25 @@ func (r *VirtualNIC) RemovePeer(addr net.Addr) { } } +func (r *VirtualNIC) LabelPeer(addr net.Addr, kv string) { + r.init() + r.peersMutex.Lock() + defer r.peersMutex.Unlock() + _, v, ok := r.peers.Find(func(s string, p *Peer) bool { + return p.Addr == addr + }) + if !ok { + return + } + v.Meta.Add("label", kv) + if v.IPv4 != "" { + r.peers.Put(v.IPv4, v) + } + if v.IPv6 != "" { + r.peers.Put(v.IPv6, v) + } +} + func (r *VirtualNIC) AddRoute(dst *net.IPNet, via net.IP) bool { r.init() r.peersMutex.Lock()