@@ -718,6 +718,8 @@ func (s *Server) handleMessage(msg map[string]interface{}, remoteAddr string) (r
718718 return s .handleJoinNetwork (msg )
719719 case "leave_network" :
720720 return s .handleLeaveNetwork (msg )
721+ case "delete_network" :
722+ return s .handleDeleteNetwork (msg )
721723 case "lookup" :
722724 return s .handleLookup (msg )
723725 case "resolve" :
@@ -1327,6 +1329,50 @@ func (s *Server) handleLeaveNetwork(msg map[string]interface{}) (map[string]inte
13271329 }, nil
13281330}
13291331
1332+ func (s * Server ) handleDeleteNetwork (msg map [string ]interface {}) (map [string ]interface {}, error ) {
1333+ if err := s .requireAdminToken (msg ); err != nil {
1334+ return nil , err
1335+ }
1336+
1337+ netID := jsonUint16 (msg , "network_id" )
1338+
1339+ // Cannot delete backbone
1340+ if netID == 0 {
1341+ return nil , fmt .Errorf ("cannot delete the backbone network" )
1342+ }
1343+
1344+ s .mu .Lock ()
1345+ defer s .mu .Unlock ()
1346+
1347+ network , ok := s .networks [netID ]
1348+ if ! ok {
1349+ return nil , fmt .Errorf ("network %d: %w" , netID , protocol .ErrNetworkNotFound )
1350+ }
1351+
1352+ // Remove network from all member nodes
1353+ for _ , memberID := range network .Members {
1354+ if node , ok := s .nodes [memberID ]; ok {
1355+ for i , n := range node .Networks {
1356+ if n == netID {
1357+ node .Networks = append (node .Networks [:i ], node .Networks [i + 1 :]... )
1358+ break
1359+ }
1360+ }
1361+ }
1362+ }
1363+
1364+ name := network .Name
1365+ delete (s .networks , netID )
1366+ s .save ()
1367+
1368+ slog .Info ("deleted network" , "network_id" , netID , "name" , name )
1369+
1370+ return map [string ]interface {}{
1371+ "type" : "delete_network_ok" ,
1372+ "network_id" : netID ,
1373+ }, nil
1374+ }
1375+
13301376func (s * Server ) handleLookup (msg map [string ]interface {}) (map [string ]interface {}, error ) {
13311377 nodeID := jsonUint32 (msg , "node_id" )
13321378
@@ -2028,9 +2074,36 @@ func (s *Server) handleListNetworks() (map[string]interface{}, error) {
20282074func (s * Server ) handleListNodes (msg map [string ]interface {}) (map [string ]interface {}, error ) {
20292075 netID := jsonUint16 (msg , "network_id" )
20302076
2031- // Backbone (network 0) node listing is restricted to prevent enumeration
2077+ // Backbone (network 0) node listing is restricted to prevent enumeration.
2078+ // Admin token bypasses this restriction.
20322079 if netID == 0 {
2033- return nil , fmt .Errorf ("listing backbone nodes is not permitted (use lookup with a specific node_id)" )
2080+ if err := s .requireAdminToken (msg ); err != nil {
2081+ return nil , fmt .Errorf ("listing backbone nodes is not permitted (use lookup with a specific node_id)" )
2082+ }
2083+ // Admin-authenticated: list all registered nodes
2084+ s .mu .RLock ()
2085+ defer s .mu .RUnlock ()
2086+ nodes := make ([]map [string ]interface {}, 0 , len (s .nodes ))
2087+ for _ , node := range s .nodes {
2088+ entry := map [string ]interface {}{
2089+ "node_id" : node .ID ,
2090+ "address" : protocol.Addr {Network : 0 , Node : node .ID }.String (),
2091+ }
2092+ if node .Hostname != "" {
2093+ entry ["hostname" ] = node .Hostname
2094+ }
2095+ if node .TaskExec {
2096+ entry ["task_exec" ] = true
2097+ }
2098+ if node .Public {
2099+ entry ["real_addr" ] = node .RealAddr
2100+ }
2101+ nodes = append (nodes , entry )
2102+ }
2103+ return map [string ]interface {}{
2104+ "type" : "list_nodes_ok" ,
2105+ "nodes" : nodes ,
2106+ }, nil
20342107 }
20352108
20362109 s .mu .RLock ()
0 commit comments