Pull request 2200: 6312-client-ipv6-zone

Updates #6312.

Squashed commit of the following:

commit bd9146ee161a67fa41763070f985e1e73b85823b
Merge: 58d2fd98d 856cc40cf
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Apr 24 18:09:19 2024 +0300

    Merge branch 'master' into 6312-client-ipv6-zone

commit 58d2fd98d3e82c84638d58dd4d74d13a9a8fbca6
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Apr 24 18:00:56 2024 +0300

    client: imp naming

commit 922a14b036d829c2775feb7bb3e6beb6aa49692e
Merge: 6f4d58fe1 60f48e2d0
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Apr 24 14:29:00 2024 +0300

    Merge branch 'master' into 6312-client-ipv6-zone

commit 6f4d58fe1c42504e8345bff24dbb3f523e8c5f85
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Apr 24 14:27:55 2024 +0300

    client: imp docs

commit fa292eee828cd6f27f62b782675aa1f998e44518
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Apr 22 19:20:28 2024 +0300

    client: fix typo

commit 599414be0ccd3f9deb044e022a8ac0006c96b467
Merge: 502571756 762ef4a6d
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Apr 22 18:42:06 2024 +0300

    Merge branch 'master' into 6312-client-ipv6-zone

commit 502571756400a00445086b5ba412e03fca65e39f
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Apr 22 18:39:22 2024 +0300

    all: imp code; add tests

commit 155b2fef500a0d835f49957d9f30b0870712f6f2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Apr 16 19:56:00 2024 +0300

    all: upd chlog; imp code

commit 7a4426c5d0a511cd3865884c00328b8c130746bf
Merge: e9c1cbb85 48c6242a7
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Apr 16 19:52:00 2024 +0300

    Merge branch 'master' into 6312-client-ipv6-zone

commit e9c1cbb85e4afa173969d5bedfaaaf92716b7fad
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Apr 10 16:23:07 2024 +0300

    client: client ipv6 zone
This commit is contained in:
Stanislav Chzhen 2024-04-24 19:08:54 +03:00
parent 856cc40cf3
commit c1ee2c7e5e
5 changed files with 129 additions and 24 deletions

View file

@ -34,6 +34,8 @@ NOTE: Add new changes BELOW THIS COMMENT.
### Fixed
- Support for link-local subnets, i.e. `fe80::/16`, as client identifiers
([#6312]).
- Issues with QUIC and HTTP/3 upstreams on older Linux kernel versions
([#6422]).
- YouTube restricted mode is not enforced by HTTPS queries on Firefox.
@ -51,6 +53,7 @@ NOTE: Add new changes BELOW THIS COMMENT.
[#5345]: https://github.com/AdguardTeam/AdGuardHome/issues/5345
[#5812]: https://github.com/AdguardTeam/AdGuardHome/issues/5812
[#6192]: https://github.com/AdguardTeam/AdGuardHome/issues/6192
[#6312]: https://github.com/AdguardTeam/AdGuardHome/issues/6312
[#6422]: https://github.com/AdguardTeam/AdGuardHome/issues/6422
[#6854]: https://github.com/AdguardTeam/AdGuardHome/issues/6854
[#6875]: https://github.com/AdguardTeam/AdGuardHome/issues/6875

View file

@ -197,8 +197,10 @@ func (ci *Index) findByIP(ip netip.Addr) (c *Persistent, found bool) {
return ci.uidToClient[uid], true
}
ipWithoutZone := ip.WithZone("")
ci.subnetToUID.Range(func(pref netip.Prefix, id UID) (cont bool) {
if pref.Contains(ip) {
// Remove zone before checking because prefixes strip zones.
if pref.Contains(ipWithoutZone) {
uid, found = id, true
return false
@ -214,6 +216,26 @@ func (ci *Index) findByIP(ip netip.Addr) (c *Persistent, found bool) {
return nil, false
}
// FindByIPWithoutZone finds a persistent client by IP address without zone. It
// strips the IPv6 zone index from the stored IP addresses before comparing,
// because querylog entries don't have it. See TODO on [querylog.logEntry.IP].
//
// Note that multiple clients can have the same IP address with different zones.
// Therefore, the result of this method is indeterminate.
func (ci *Index) FindByIPWithoutZone(ip netip.Addr) (c *Persistent) {
if (ip == netip.Addr{}) {
return nil
}
for addr, uid := range ci.ipToUID {
if addr.WithZone("") == ip {
return ci.uidToClient[uid]
}
}
return nil
}
// find finds persistent client by MAC.
func (ci *Index) findByMAC(mac net.HardwareAddr) (c *Persistent, found bool) {
k := macToKey(mac)

View file

@ -35,27 +35,49 @@ func TestClientIndex(t *testing.T) {
cliID = "client-id"
cliMAC = "11:11:11:11:11:11"
linkLocalIP = "fe80::abcd:abcd:abcd:ab%eth0"
linkLocalSubnet = "fe80::/16"
)
clients := []*Persistent{{
Name: "client1",
IPs: []netip.Addr{
netip.MustParseAddr(cliIP1),
netip.MustParseAddr(cliIPv6),
},
}, {
Name: "client2",
IPs: []netip.Addr{netip.MustParseAddr(cliIP2)},
Subnets: []netip.Prefix{netip.MustParsePrefix(cliSubnet)},
}, {
Name: "client_with_mac",
MACs: []net.HardwareAddr{mustParseMAC(cliMAC)},
}, {
Name: "client_with_id",
ClientIDs: []string{cliID},
}}
var (
clientWithBothFams = &Persistent{
Name: "client1",
IPs: []netip.Addr{
netip.MustParseAddr(cliIP1),
netip.MustParseAddr(cliIPv6),
},
}
ci := newIDIndex(clients)
clientWithSubnet = &Persistent{
Name: "client2",
IPs: []netip.Addr{netip.MustParseAddr(cliIP2)},
Subnets: []netip.Prefix{netip.MustParsePrefix(cliSubnet)},
}
clientWithMAC = &Persistent{
Name: "client_with_mac",
MACs: []net.HardwareAddr{mustParseMAC(cliMAC)},
}
clientWithID = &Persistent{
Name: "client_with_id",
ClientIDs: []string{cliID},
}
clientLinkLocal = &Persistent{
Name: "client_link_local",
Subnets: []netip.Prefix{netip.MustParsePrefix(linkLocalSubnet)},
}
)
ci := newIDIndex([]*Persistent{
clientWithBothFams,
clientWithSubnet,
clientWithMAC,
clientWithID,
clientLinkLocal,
})
testCases := []struct {
want *Persistent
@ -64,19 +86,23 @@ func TestClientIndex(t *testing.T) {
}{{
name: "ipv4_ipv6",
ids: []string{cliIP1, cliIPv6},
want: clients[0],
want: clientWithBothFams,
}, {
name: "ipv4_subnet",
ids: []string{cliIP2, cliSubnetIP},
want: clients[1],
want: clientWithSubnet,
}, {
name: "mac",
ids: []string{cliMAC},
want: clients[2],
want: clientWithMAC,
}, {
name: "client_id",
ids: []string{cliID},
want: clients[3],
want: clientWithID,
}, {
name: "client_link_local_subnet",
ids: []string{linkLocalIP},
want: clientLinkLocal,
}}
for _, tc := range testCases {
@ -221,3 +247,52 @@ func TestMACToKey(t *testing.T) {
_ = macToKey(mac)
})
}
func TestIndex_FindByIPWithoutZone(t *testing.T) {
var (
ip = netip.MustParseAddr("fe80::a098:7654:32ef:ff1")
ipWithZone = netip.MustParseAddr("fe80::1ff:fe23:4567:890a%eth2")
)
var (
clientNoZone = &Persistent{
Name: "client",
IPs: []netip.Addr{ip},
}
clientWithZone = &Persistent{
Name: "client_with_zone",
IPs: []netip.Addr{ipWithZone},
}
)
ci := newIDIndex([]*Persistent{
clientNoZone,
clientWithZone,
})
testCases := []struct {
ip netip.Addr
want *Persistent
name string
}{{
name: "without_zone",
ip: ip,
want: clientNoZone,
}, {
name: "with_zone",
ip: ipWithZone,
want: clientWithZone,
}, {
name: "zero_address",
ip: netip.Addr{},
want: nil,
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c := ci.FindByIPWithoutZone(tc.ip.WithZone(""))
require.Equal(t, tc.want, c)
})
}
}

View file

@ -412,7 +412,11 @@ func (clients *clientsContainer) clientOrArtificial(
}()
cli, ok := clients.find(id)
if ok {
if !ok {
cli = clients.clientIndex.FindByIPWithoutZone(ip)
}
if cli != nil {
return &querylog.Client{
Name: cli.Name,
IgnoreQueryLog: cli.IgnoreQueryLog,

View file

@ -31,6 +31,7 @@ type logEntry struct {
Answer []byte `json:",omitempty"`
OrigAnswer []byte `json:",omitempty"`
// TODO(s.chzhen): Use netip.Addr.
IP net.IP `json:"IP"`
Result filtering.Result