From ed942f3e31a29ec60440ef66b6839a8b828bcfab Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Tue, 19 Mar 2019 18:47:22 +0300 Subject: [PATCH] + control: /clients: get the list of clients' IP addresses and names from /etc/hosts --- clients.go | 92 ++++++++++++++++++++++++++++++++++++++++++++ control.go | 1 + openapi/openapi.yaml | 36 +++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 clients.go diff --git a/clients.go b/clients.go new file mode 100644 index 00000000..87a5c3fe --- /dev/null +++ b/clients.go @@ -0,0 +1,92 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "os" + "runtime" + "strings" + + "github.com/AdguardTeam/golibs/log" +) + +// Client information +type Client struct { + IP string + Name string + //Source source // Hosts file / User settings / DHCP +} + +type clientJSON struct { + IP string `json:"ip"` + Name string `json:"name"` +} + +var clients []Client +var clientsFilled bool + +// Parse system 'hosts' file and fill clients array +func fillClientInfo() { + hostsFn := "/etc/hosts" + if runtime.GOOS == "windows" { + hostsFn = os.ExpandEnv("$SystemRoot\\system32\\drivers\\etc\\hosts") + } + + d, e := ioutil.ReadFile(hostsFn) + if e != nil { + log.Info("Can't read file %s: %v", hostsFn, e) + return + } + + lines := strings.Split(string(d), "\n") + for _, ln := range lines { + ln = strings.TrimSpace(ln) + if len(ln) == 0 || ln[0] == '#' { + continue + } + + fields := strings.Fields(ln) + if len(fields) < 2 { + continue + } + + var c Client + c.IP = fields[0] + c.Name = fields[1] + clients = append(clients, c) + log.Tracef("%s -> %s", c.IP, c.Name) + } + + log.Info("Added %d client aliases from %s", len(clients), hostsFn) + clientsFilled = true +} + +// respond with information about configured clients +func handleGetClients(w http.ResponseWriter, r *http.Request) { + log.Tracef("%s %v", r.Method, r.URL) + + if !clientsFilled { + fillClientInfo() + } + + data := []clientJSON{} + for _, c := range clients { + cj := clientJSON{ + IP: c.IP, + Name: c.Name, + } + data = append(data, cj) + } + w.Header().Set("Content-Type", "application/json") + e := json.NewEncoder(w).Encode(data) + if e != nil { + httpError(w, http.StatusInternalServerError, "Failed to encode to json: %v", e) + return + } +} + +// RegisterClientsHandlers registers HTTP handlers +func RegisterClientsHandlers() { + http.HandleFunc("/control/clients", postInstall(optionalAuth(ensureGET(handleGetClients)))) +} diff --git a/control.go b/control.go index be0d61b2..39fe1c66 100644 --- a/control.go +++ b/control.go @@ -1063,6 +1063,7 @@ func registerControlHandlers() { http.HandleFunc("/control/dhcp/find_active_dhcp", postInstall(optionalAuth(ensurePOST(handleDHCPFindActiveServer)))) RegisterTLSHandlers() + RegisterClientsHandlers() http.HandleFunc("/dns-query", postInstall(handleDOH)) } diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index d8b1072c..569d94d7 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -39,6 +39,9 @@ tags: - name: dhcp description: 'Built-in DHCP server controls' + - + name: clients + description: 'Clients list operations' - name: install description: 'First-time install configuration handlers' @@ -668,6 +671,22 @@ paths: application/json: enabled: false + # -------------------------------------------------- + # Clients list methods + # -------------------------------------------------- + + /clients: + get: + tags: + - clients + operationId: clientsStatus + summary: 'Get information about configured clients' + responses: + 200: + description: OK + schema: + $ref: "#/definitions/Clients" + # -------------------------------------------------- # I18N methods # -------------------------------------------------- @@ -1317,6 +1336,23 @@ definitions: description: "Network interfaces dictionary (key is the interface name)" additionalProperties: $ref: "#/definitions/NetInterface" + Client: + type: "object" + description: "Client information" + properties: + ip: + type: "string" + description: "IP address" + example: "127.0.0.1" + name: + type: "string" + description: "Name" + example: "localhost" + Clients: + type: "array" + items: + $ref: "#/definitions/Client" + description: "Clients array" InitialConfiguration: type: "object" description: "AdGuard Home initial configuration (for the first-install wizard)"