+ GET /control/clients/find: add "disallowed" property

This commit is contained in:
Simon Zolin 2020-07-24 14:30:29 +03:00
parent 07db05dd80
commit dd3027afe7
9 changed files with 113 additions and 26 deletions

View File

@ -940,7 +940,7 @@ Error response (Client not found):
### API: Find clients by IP
This method returns the list of clients (manual and auto-clients) matching the IP list.
For auto-clients only `name`, `ids` and `whois_info` fields are set. Other fields are empty.
For auto-clients only `name`, `ids`, `whois_info`, `disallowed` fields are set. Other fields are empty.
Request:
@ -966,11 +966,18 @@ Response:
key: "value"
...
}
"disallowed": "..."
}
}
...
]
`disallowed`:
* "": IP is allowed
* not "", e.g. "127.0.0.0/24" - IP is disallowed by "disallowed IP list", and the string contains the matched rule (IP or CIDR)
* "not-in-allowed-list" - IP is disallowed by "allowed IP list"
## DNS general settings

View File

@ -80,43 +80,43 @@ func processIPCIDRArray(dst *map[string]bool, dstIPNet *[]net.IPNet, src []strin
}
// IsBlockedIP - return TRUE if this client should be blocked
func (a *accessCtx) IsBlockedIP(ip string) bool {
func (a *accessCtx) IsBlockedIP(ip string) (bool, string) {
a.lock.Lock()
defer a.lock.Unlock()
if len(a.allowedClients) != 0 || len(a.allowedClientsIPNet) != 0 {
_, ok := a.allowedClients[ip]
if ok {
return false
return false, ""
}
if len(a.allowedClientsIPNet) != 0 {
ipAddr := net.ParseIP(ip)
for _, ipnet := range a.allowedClientsIPNet {
if ipnet.Contains(ipAddr) {
return false
return false, ""
}
}
}
return true
return true, "not-in-allowed-list"
}
_, ok := a.disallowedClients[ip]
if ok {
return true
return true, ip
}
if len(a.disallowedClientsIPNet) != 0 {
ipAddr := net.ParseIP(ip)
for _, ipnet := range a.disallowedClientsIPNet {
if ipnet.Contains(ipAddr) {
return true
return true, ipnet.String()
}
}
}
return false
return false, ""
}
// IsBlockedDomain - return TRUE if this domain should be blocked

View File

@ -298,3 +298,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
p.ServeHTTP(w, r)
}
}
// IsBlockedIP - return TRUE if this client should be blocked
func (s *Server) IsBlockedIP(ip string) (bool, string) {
return s.access.IsBlockedIP(ip)
}

View File

@ -878,20 +878,28 @@ func TestIsBlockedIPAllowed(t *testing.T) {
a := &accessCtx{}
assert.True(t, a.Init([]string{"1.1.1.1", "2.2.0.0/16"}, nil, nil) == nil)
assert.True(t, !a.IsBlockedIP("1.1.1.1"))
assert.True(t, a.IsBlockedIP("1.1.1.2"))
assert.True(t, !a.IsBlockedIP("2.2.1.1"))
assert.True(t, a.IsBlockedIP("2.3.1.1"))
disallowed, _ := a.IsBlockedIP("1.1.1.1")
assert.False(t, disallowed)
disallowed, _ = a.IsBlockedIP("1.1.1.2")
assert.True(t, disallowed)
disallowed, _ = a.IsBlockedIP("2.2.1.1")
assert.False(t, disallowed)
disallowed, _ = a.IsBlockedIP("2.3.1.1")
assert.True(t, disallowed)
}
func TestIsBlockedIPDisallowed(t *testing.T) {
a := &accessCtx{}
assert.True(t, a.Init(nil, []string{"1.1.1.1", "2.2.0.0/16"}, nil) == nil)
assert.True(t, a.IsBlockedIP("1.1.1.1"))
assert.True(t, !a.IsBlockedIP("1.1.1.2"))
assert.True(t, a.IsBlockedIP("2.2.1.1"))
assert.True(t, !a.IsBlockedIP("2.3.1.1"))
disallowed, _ := a.IsBlockedIP("1.1.1.1")
assert.True(t, disallowed)
disallowed, _ = a.IsBlockedIP("1.1.1.2")
assert.False(t, disallowed)
disallowed, _ = a.IsBlockedIP("2.2.1.1")
assert.True(t, disallowed)
disallowed, _ = a.IsBlockedIP("2.3.1.1")
assert.False(t, disallowed)
}
func TestIsBlockedIPBlockedDomain(t *testing.T) {

View File

@ -12,7 +12,8 @@ import (
func (s *Server) beforeRequestHandler(_ *proxy.Proxy, d *proxy.DNSContext) (bool, error) {
ip := ipFromAddr(d.Addr)
if s.access.IsBlockedIP(ip) {
disallowed, _ := s.access.IsBlockedIP(ip)
if disallowed {
log.Tracef("Client IP %s is blocked by settings", ip)
return false, nil
}

View File

@ -80,6 +80,8 @@ type clientsContainer struct {
// dhcpServer is used for looking up clients IP addresses by MAC addresses
dhcpServer *dhcpd.Server
DNSServer *dnsforward.Server
autoHosts *util.AutoHosts // get entries from system hosts-files
testing bool // if TRUE, this object is used for internal tests

View File

@ -21,6 +21,13 @@ type clientJSON struct {
BlockedServices []string `json:"blocked_services"`
Upstreams []string `json:"upstreams"`
WhoisInfo map[string]interface{} `json:"whois_info"`
// * "": IP is allowed
// * not "", e.g. "127.0.0.0/24" - IP is disallowed by "disallowed IP list", and the string contains the matched rule (IP or CIDR)
// * "not-in-allowed-list" - IP is disallowed by "allowed IP list"
Disallowed string `json:"disallowed"`
}
type clientHostJSON struct {
@ -123,15 +130,9 @@ func clientToJSON(c *Client) clientJSON {
return cj
}
type clientHostJSONWithID struct {
IDs []string `json:"ids"`
Name string `json:"name"`
WhoisInfo map[string]interface{} `json:"whois_info"`
}
// Convert ClientHost object to JSON
func clientHostToJSON(ip string, ch ClientHost) clientHostJSONWithID {
cj := clientHostJSONWithID{
func clientHostToJSON(ip string, ch ClientHost) clientJSON {
cj := clientJSON{
Name: ch.Host,
IDs: []string{ip},
}
@ -255,9 +256,21 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http
continue // a client with this IP isn't found
}
cj := clientHostToJSON(ip, ch)
disallowed, disallowedRule := clients.DNSServer.IsBlockedIP(ip)
if disallowed {
cj.Disallowed = disallowedRule
}
el[ip] = cj
} else {
cj := clientToJSON(&c)
disallowed, disallowedRule := clients.DNSServer.IsBlockedIP(ip)
if disallowed {
cj.Disallowed = disallowedRule
}
el[ip] = cj
}

View File

@ -70,6 +70,7 @@ func initDNSServer() error {
p.DHCPServer = Context.dhcpServer
}
Context.dnsServer = dnsforward.NewServer(p)
Context.clients.DNSServer = Context.dnsServer
dnsConfig := generateServerConfig()
err = Context.dnsServer.Prepare(&dnsConfig)
if err != nil {

View File

@ -1757,7 +1757,57 @@ components:
properties:
1.2.3.4:
items:
$ref: "#/components/schemas/Client"
$ref: "#/components/schemas/ClientFindSubEntry"
ClientFindSubEntry:
type: object
properties:
name:
type: string
description: Name
example: localhost
ids:
type: array
description: IP, CIDR or MAC address
items:
type: string
use_global_settings:
type: boolean
filtering_enabled:
type: boolean
parental_enabled:
type: boolean
safebrowsing_enabled:
type: boolean
safesearch_enabled:
type: boolean
use_global_blocked_services:
type: boolean
blocked_services:
type: array
items:
type: string
upstreams:
type: array
items:
type: string
whois_info:
type: array
items:
$ref: "#/components/schemas/WhoisInfo"
disallowed:
description: >
* "": IP is allowed
* not "", e.g. "127.0.0.0/24" - IP is disallowed by "disallowed IP list", and the string contains the matched rule (IP or CIDR)
* "not-in-allowed-list" - IP is disallowed by "allowed IP list"
type: string
WhoisInfo:
type: object
properties:
key:
type: string
Clients:
type: object
properties: