Pull request: 3419 client allowlist collision

Updates #3419.

Squashed commit of the following:

commit 370094c00d9c15b1336fbedb1e233bd4436c9898
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Fri Sep 10 17:31:16 2021 +0300

    added link to github issue

commit 407ba9b2db46b887a30ddb081bd37c56e56b0496
Merge: 426c8146 80548233
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Fri Sep 10 17:29:52 2021 +0300

    Merge branch 'master' into 3419-client-allowlist-collision

commit 426c8146cff5c112ebb25192af276c6601200528
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Fri Sep 10 16:28:11 2021 +0300

    fix en

commit d28c6022321828c6bdc55c3f9a4f655b26d146d2
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Fri Sep 10 15:49:12 2021 +0300

    added missing space

commit b374a09327968ca5343c1595d1ab8cf317c15ffe
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Fri Sep 10 15:43:55 2021 +0300

    fixes after review

commit 2be629d66e4703e2f5a85615bf1eaaa92e03c6fd
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Thu Sep 9 14:17:19 2021 +0300

    fixes

commit 5c2aa6201cc0ecf404d4057e354fbb0bdadcdd6d
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Wed Sep 8 15:04:30 2021 +0300

    return empty line to locale file

commit 3631c3772babbd595b1c3de4a7e91be6bac3e80f
Author: Dmitriy Seregin <d.seregin@adguard.com>
Date:   Wed Sep 8 13:57:51 2021 +0300

    all: fix collisions in access lists && expand block/unblock client
This commit is contained in:
Dmitry Seregin
2021-09-10 17:57:09 +03:00
committed by Ainar Garipov
parent 80548233ba
commit 8fdd789474
13 changed files with 238 additions and 65 deletions

View File

@@ -7,6 +7,7 @@ import (
"net/http"
"strings"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/stringutil"
@@ -192,6 +193,60 @@ func (s *Server) handleAccessList(w http.ResponseWriter, r *http.Request) {
}
}
func isUniq(slice []string) (ok bool, uniqueMap map[string]unit) {
exists := make(map[string]unit)
for _, key := range slice {
if _, has := exists[key]; has {
return false, nil
}
exists[key] = unit{}
}
return true, exists
}
func intersect(mapA, mapB map[string]unit) bool {
for key := range mapA {
if _, has := mapB[key]; has {
return true
}
}
return false
}
// validateAccessSet checks the internal accessListJSON lists. To search for
// duplicates, we cannot compare the new stringutil.Set and []string, because
// creating a set for a large array can be an unnecessary algorithmic complexity
func validateAccessSet(list accessListJSON) (err error) {
const (
errAllowedDup errors.Error = "duplicates in allowed clients"
errDisallowedDup errors.Error = "duplicates in disallowed clients"
errBlockedDup errors.Error = "duplicates in blocked hosts"
errIntersect errors.Error = "some items in allowed and " +
"disallowed lists at the same time"
)
ok, allowedClients := isUniq(list.AllowedClients)
if !ok {
return errAllowedDup
}
ok, disallowedClients := isUniq(list.DisallowedClients)
if !ok {
return errDisallowedDup
}
ok, _ = isUniq(list.BlockedHosts)
if !ok {
return errBlockedDup
}
if intersect(allowedClients, disallowedClients) {
return errIntersect
}
return nil
}
func (s *Server) handleAccessSet(w http.ResponseWriter, r *http.Request) {
list := accessListJSON{}
err := json.NewDecoder(r.Body).Decode(&list)
@@ -201,6 +256,13 @@ func (s *Server) handleAccessSet(w http.ResponseWriter, r *http.Request) {
return
}
err = validateAccessSet(list)
if err != nil {
httpError(r, w, http.StatusBadRequest, err.Error())
return
}
var a *accessCtx
a, err = newAccessCtx(list.AllowedClients, list.DisallowedClients, list.BlockedHosts)
if err != nil {

View File

@@ -285,39 +285,70 @@ func toQueryLogWHOIS(wi *RuntimeClientWHOISInfo) (cw *querylog.ClientWHOIS) {
}
}
// findMultiple is a wrapper around Find to make it a valid client finder for
// the query log. err is always nil.
// findMultiple returns info about client. If no information about the client
// is found, it sends the client by default only with the "Disallowed" field
// filled in. err is always nil.
func (clients *clientsContainer) findMultiple(ids []string) (c *querylog.Client, err error) {
var emptyClient *querylog.Client
for _, id := range ids {
var name string
whois := &querylog.ClientWHOIS{}
ip := net.ParseIP(id)
c, ok := clients.Find(id)
if ok {
name = c.Name
} else if ip != nil {
var rc *RuntimeClient
rc, ok = clients.FindRuntimeClient(ip)
if !ok {
continue
}
name = rc.Host
whois = toQueryLogWHOIS(rc.WHOISInfo)
}
disallowed, disallowedRule := clients.dnsServer.IsBlockedClient(ip, id)
return &querylog.Client{
Name: name,
DisallowedRule: disallowedRule,
WHOIS: whois,
Disallowed: disallowed,
}, nil
client := clients.clientInfo(ip, id, disallowed, disallowedRule)
if client.Name == "" && client.DisallowedRule == "" {
emptyClient = client
continue
}
return client, nil
}
return nil, nil
return emptyClient, nil
}
// clientInfo is a wrapper around Find to make it a valid client finder for
// the query log.
func (clients *clientsContainer) clientInfo(
ip net.IP,
id string,
disallowed bool,
rule string,
) (c *querylog.Client) {
whois := &querylog.ClientWHOIS{}
client, ok := clients.Find(id)
if ok {
return &querylog.Client{
Name: client.Name,
DisallowedRule: rule,
WHOIS: whois,
Disallowed: disallowed,
}
}
if ip == nil {
return nil
}
var rc *RuntimeClient
rc, ok = clients.FindRuntimeClient(ip)
if ok {
return &querylog.Client{
Name: rc.Host,
DisallowedRule: rule,
WHOIS: toQueryLogWHOIS(rc.WHOISInfo),
Disallowed: disallowed,
}
}
return &querylog.Client{
Name: "",
DisallowedRule: rule,
WHOIS: &querylog.ClientWHOIS{},
Disallowed: disallowed,
}
}
func (clients *clientsContainer) Find(id string) (c *Client, ok bool) {