Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1789c96c7f | ||
|
|
8811c8817e | ||
|
|
5aa0ca9319 | ||
|
|
90054974bc | ||
|
|
9f774d776c | ||
|
|
8ead755b67 | ||
|
|
90ebc4d8c9 | ||
|
|
400b76d47b | ||
|
|
8aa8be2921 | ||
|
|
52575d0247 | ||
|
|
7e1b4ca6fe | ||
|
|
a234b63da1 | ||
|
|
94e783d572 | ||
|
|
91403d0b95 | ||
|
|
d6a059e395 | ||
|
|
e31c0c456a | ||
|
|
836d0db563 | ||
|
|
a0abad6644 | ||
|
|
1122e71cf3 | ||
|
|
e32c18faab | ||
|
|
f893df7e64 |
2
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -3,7 +3,7 @@ name: Bug report
|
||||
about: Create a bug report to help us improve AdGuard Home
|
||||
---
|
||||
|
||||
<!-- As an open-source project with a dedicated but small maintainer team, it can sometimes take a long time for issues to be addressed so please be patient and we will get back to you as soon as we can. -->
|
||||
Have a question or an idea? Please search it [on our forum](https://github.com/AdguardTeam/AdGuardHome/discussions) to make sure it was not yet asked. If you cannot find what you had in mind, please [submit it here](https://github.com/AdguardTeam/AdGuardHome/discussions/new).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
6
.github/ISSUE_TEMPLATE/Feature_request.md
vendored
@@ -1,11 +1,9 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for AdGuard Home
|
||||
|
||||
about: Suggest a feature request for AdGuard Home
|
||||
---
|
||||
|
||||
<!-- As an open-source project with a dedicated but small maintainer team, it can sometimes take a long time for issues to be addressed so please be patient and we will get back to you as soon as we can.
|
||||
-->
|
||||
Have a question or an idea? Please search it [on our forum](https://github.com/AdguardTeam/AdGuardHome/discussions) to make sure it was not yet asked. If you cannot find what you had in mind, please [submit it here](https://github.com/AdguardTeam/AdGuardHome/discussions/new).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
|
||||
8
.github/stale.yml
vendored
8
.github/stale.yml
vendored
@@ -1,20 +1,22 @@
|
||||
# Number of days of inactivity before an issue becomes stale.
|
||||
'daysUntilStale': 60
|
||||
'daysUntilStale': 90
|
||||
# Number of days of inactivity before a stale issue is closed.
|
||||
'daysUntilClose': 7
|
||||
'daysUntilClose': 15
|
||||
# Issues with these labels will never be considered stale.
|
||||
'exemptLabels':
|
||||
- 'bug'
|
||||
- 'enhancement'
|
||||
- 'feature request'
|
||||
- 'localization'
|
||||
- 'needs investigation'
|
||||
- 'recurrent'
|
||||
- 'research'
|
||||
# Label to use when marking an issue as stale.
|
||||
'staleLabel': 'wontfix'
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable.
|
||||
'markComment': >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable.
|
||||
'closeComment': false
|
||||
|
||||
38
CHANGELOG.md
38
CHANGELOG.md
@@ -13,9 +13,34 @@ and this project adheres to
|
||||
## [v0.106.0] - 2021-04-26
|
||||
-->
|
||||
|
||||
<!--
|
||||
## [v0.105.2] - 2021-02-24
|
||||
-->
|
||||
## [v0.105.2] - 2021-03-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- Incomplete hostnames with trailing zero-bytes handling ([#2582]).
|
||||
- Wrong DNS-over-TLS ALPN configuration ([#2681]).
|
||||
- Inconsistent responses for messages with EDNS0 and AD when DNS caching is
|
||||
enabled ([#2600]).
|
||||
- Incomplete OpenWRT detection ([#2757]).
|
||||
- DHCP lease's `expired` field incorrect time format ([#2692]).
|
||||
- Incomplete DNS upstreams validation ([#2674]).
|
||||
- Wrong parsing of DHCP options of the `ip` type ([#2688]).
|
||||
|
||||
[#2582]: https://github.com/AdguardTeam/AdGuardHome/issues/2582
|
||||
[#2600]: https://github.com/AdguardTeam/AdGuardHome/issues/2600
|
||||
[#2674]: https://github.com/AdguardTeam/AdGuardHome/issues/2674
|
||||
[#2681]: https://github.com/AdguardTeam/AdGuardHome/issues/2681
|
||||
[#2688]: https://github.com/AdguardTeam/AdGuardHome/issues/2688
|
||||
[#2692]: https://github.com/AdguardTeam/AdGuardHome/issues/2692
|
||||
[#2757]: https://github.com/AdguardTeam/AdGuardHome/issues/2757
|
||||
|
||||
### Security
|
||||
|
||||
- Session token doesn't contain user's information anymore ([#2470]).
|
||||
|
||||
[#2470]: https://github.com/AdguardTeam/AdGuardHome/issues/2470
|
||||
|
||||
|
||||
|
||||
## [v0.105.1] - 2021-02-15
|
||||
|
||||
@@ -198,11 +223,12 @@ and this project adheres to
|
||||
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.2...HEAD
|
||||
[v0.105.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.1...v0.105.2
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.0...HEAD
|
||||
[v0.106.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.2...v0.106.0
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.1...HEAD
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.2...HEAD
|
||||
[v0.105.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.1...v0.105.2
|
||||
[v0.105.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.0...v0.105.1
|
||||
[v0.105.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.104.3...v0.105.0
|
||||
[v0.104.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.104.2...v0.104.3
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, {
|
||||
useEffect,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import propTypes from 'prop-types';
|
||||
import throttle from 'lodash/throttle';
|
||||
@@ -25,19 +25,21 @@ const InfiniteTable = ({
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const loader = useRef(null);
|
||||
const loadingRef = useRef(null);
|
||||
|
||||
const {
|
||||
isEntireLog,
|
||||
processingGetLogs,
|
||||
} = useSelector((state) => state.queryLogs, shallowEqual);
|
||||
|
||||
const isEntireLog = useSelector((state) => state.queryLogs.isEntireLog);
|
||||
const processingGetLogs = useSelector((state) => state.queryLogs.processingGetLogs);
|
||||
const loading = isLoading || processingGetLogs;
|
||||
|
||||
const listener = useCallback(() => {
|
||||
if (loader.current && isScrolledIntoView(loader.current)) {
|
||||
if (!loadingRef.current && loader.current && isScrolledIntoView(loader.current)) {
|
||||
dispatch(getLogs());
|
||||
}
|
||||
}, [loader.current, isScrolledIntoView, getLogs]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
loadingRef.current = processingGetLogs;
|
||||
}, [processingGetLogs]);
|
||||
|
||||
useEffect(() => {
|
||||
listener();
|
||||
|
||||
2
go.mod
2
go.mod
@@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.33.9
|
||||
github.com/AdguardTeam/dnsproxy v0.35.5
|
||||
github.com/AdguardTeam/golibs v0.4.4
|
||||
github.com/AdguardTeam/urlfilter v0.14.3
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
|
||||
4
go.sum
4
go.sum
@@ -18,8 +18,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/AdguardTeam/dnsproxy v0.33.9 h1:HUwywkhUV/M73E7qWcBAF+SdsNq742s82Lvox4pr/tM=
|
||||
github.com/AdguardTeam/dnsproxy v0.33.9/go.mod h1:dkI9VWh43XlOzF2XogDm1EmoVl7PANOR4isQV6X9LZs=
|
||||
github.com/AdguardTeam/dnsproxy v0.35.5 h1:SsRF0eDzuLGaSUDKABIu9Mn1joi4v4kvEU1vju2DQPQ=
|
||||
github.com/AdguardTeam/dnsproxy v0.35.5/go.mod h1:dkI9VWh43XlOzF2XogDm1EmoVl7PANOR4isQV6X9LZs=
|
||||
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o=
|
||||
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
|
||||
@@ -19,7 +19,12 @@ import (
|
||||
|
||||
const (
|
||||
defaultDiscoverTime = time.Second * 3
|
||||
leaseExpireStatic = 1
|
||||
// leaseExpireStatic is used to define the Expiry field for static
|
||||
// leases.
|
||||
//
|
||||
// TODO(e.burkov): Remove it when static leases determining mechanism
|
||||
// will be improved.
|
||||
leaseExpireStatic = 1
|
||||
)
|
||||
|
||||
var webHandlersRegistered = false
|
||||
@@ -37,12 +42,24 @@ type Lease struct {
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface for *Lease.
|
||||
func (l *Lease) MarshalJSON() ([]byte, error) {
|
||||
var expiryStr string
|
||||
if expiry := l.Expiry; expiry.Unix() != leaseExpireStatic {
|
||||
// The front-end is waiting for RFC 3999 format of the time
|
||||
// value. It also shouldn't got an Expiry field for static
|
||||
// leases.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2692.
|
||||
expiryStr = expiry.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
type lease Lease
|
||||
return json.Marshal(&struct {
|
||||
HWAddr string `json:"mac"`
|
||||
Expiry string `json:"expires,omitempty"`
|
||||
*lease
|
||||
}{
|
||||
HWAddr: l.HWAddr.String(),
|
||||
Expiry: expiryStr,
|
||||
lease: (*lease)(l),
|
||||
})
|
||||
}
|
||||
@@ -248,14 +265,10 @@ const (
|
||||
LeasesAll = LeasesDynamic | LeasesStatic
|
||||
)
|
||||
|
||||
// Leases returns the list of current DHCP leases (thread-safe)
|
||||
func (s *Server) Leases(flags int) []Lease {
|
||||
result := s.srv4.GetLeases(flags)
|
||||
|
||||
v6leases := s.srv6.GetLeases(flags)
|
||||
result = append(result, v6leases...)
|
||||
|
||||
return result
|
||||
// Leases returns the list of active IPv4 and IPv6 DHCP leases. It's safe for
|
||||
// concurrent use.
|
||||
func (s *Server) Leases(flags int) (leases []Lease) {
|
||||
return append(s.srv4.GetLeases(flags), s.srv6.GetLeases(flags)...)
|
||||
}
|
||||
|
||||
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
|
||||
@@ -293,14 +306,22 @@ func parseOptionString(s string) (uint8, []byte) {
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
case "ip":
|
||||
ip := net.ParseIP(sval)
|
||||
if ip == nil {
|
||||
return 0, nil
|
||||
}
|
||||
val = ip
|
||||
|
||||
// Most DHCP options require IPv4, so do not put the 16-byte
|
||||
// version if we can. Otherwise, the clients will receive weird
|
||||
// data that looks like four IPv4 addresses.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2688.
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
val = ip4
|
||||
} else {
|
||||
val = ip
|
||||
}
|
||||
default:
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
package dhcpd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -130,36 +129,51 @@ func TestOptions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
optStr string
|
||||
wantCode uint8
|
||||
wantVal []byte
|
||||
wantCode uint8
|
||||
}{{
|
||||
name: "all_right_hex",
|
||||
optStr: " 12 hex abcdef ",
|
||||
wantCode: 12,
|
||||
name: "success_hex",
|
||||
optStr: "12 hex abcdef",
|
||||
wantVal: []byte{0xab, 0xcd, 0xef},
|
||||
wantCode: 12,
|
||||
}, {
|
||||
name: "bad_hex",
|
||||
optStr: " 12 hex abcdef1 ",
|
||||
optStr: "12 hex abcdefx",
|
||||
wantVal: nil,
|
||||
wantCode: 0,
|
||||
}, {
|
||||
name: "all_right_ip",
|
||||
name: "success_ip",
|
||||
optStr: "123 ip 1.2.3.4",
|
||||
wantVal: net.IP{1, 2, 3, 4},
|
||||
wantCode: 123,
|
||||
}, {
|
||||
name: "success_ipv6",
|
||||
optStr: "123 ip ::1234",
|
||||
wantVal: net.IP{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0x12, 0x34,
|
||||
},
|
||||
wantCode: 123,
|
||||
wantVal: net.IPv4(1, 2, 3, 4),
|
||||
}, {
|
||||
name: "bad_code",
|
||||
optStr: "256 ip 1.1.1.1",
|
||||
wantVal: nil,
|
||||
wantCode: 0,
|
||||
}, {
|
||||
name: "negative_code",
|
||||
optStr: "-1 ip 1.1.1.1",
|
||||
wantVal: nil,
|
||||
wantCode: 0,
|
||||
}, {
|
||||
name: "bad_ip",
|
||||
optStr: "12 ip 1.1.1.1x",
|
||||
wantVal: nil,
|
||||
wantCode: 0,
|
||||
}, {
|
||||
name: "bad_mode",
|
||||
wantVal: nil,
|
||||
optStr: "12 x 1.1.1.1",
|
||||
wantCode: 0,
|
||||
}}
|
||||
@@ -167,9 +181,9 @@ func TestOptions(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
code, val := parseOptionString(tc.optStr)
|
||||
require.EqualValues(t, tc.wantCode, code)
|
||||
require.Equal(t, tc.wantCode, code)
|
||||
if tc.wantVal != nil {
|
||||
assert.True(t, bytes.Equal(tc.wantVal, val))
|
||||
assert.Equal(t, tc.wantVal, val)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -463,7 +464,16 @@ func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (*Lease, bool) {
|
||||
}
|
||||
|
||||
if lease.Expiry.Unix() != leaseExpireStatic {
|
||||
lease.Hostname = string(hostname)
|
||||
// The trimming is required since some devices include trailing
|
||||
// zero-byte in DHCP option length calculation.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2582.
|
||||
//
|
||||
// TODO(e.burkov): Remove after the trimming for hostname option
|
||||
// will be added into github.com/insomniacslk/dhcp module.
|
||||
hostnameStr := strings.TrimRight(string(hostname), "\x00")
|
||||
|
||||
lease.Hostname = hostnameStr
|
||||
s.commitLease(lease)
|
||||
} else if len(lease.Hostname) != 0 {
|
||||
o := &optFQDN{
|
||||
|
||||
@@ -276,14 +276,24 @@ func (s *Server) prepareUpstreamSettings() error {
|
||||
upstreams = s.conf.UpstreamDNS
|
||||
}
|
||||
upstreams = filterOutComments(upstreams)
|
||||
upstreamConfig, err := proxy.ParseUpstreamsConfig(upstreams, s.conf.BootstrapDNS, DefaultTimeout)
|
||||
upstreamConfig, err := proxy.ParseUpstreamsConfig(upstreams,
|
||||
upstream.Options{
|
||||
Bootstrap: s.conf.BootstrapDNS,
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dns: proxy.ParseUpstreamsConfig: %w", err)
|
||||
}
|
||||
|
||||
if len(upstreamConfig.Upstreams) == 0 {
|
||||
log.Info("Warning: no default upstream servers specified, using %v", defaultDNS)
|
||||
uc, err := proxy.ParseUpstreamsConfig(defaultDNS, s.conf.BootstrapDNS, DefaultTimeout)
|
||||
log.Info("warning: no default upstream servers specified, using %v", defaultDNS)
|
||||
uc, err := proxy.ParseUpstreamsConfig(defaultDNS,
|
||||
upstream.Options{
|
||||
Bootstrap: s.conf.BootstrapDNS,
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("dns: failed to parse default upstreams: %v", err)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/utils"
|
||||
@@ -149,7 +150,7 @@ func (req *dnsConfig) checkBootstrap() (string, error) {
|
||||
return boot, fmt.Errorf("invalid bootstrap server address: empty")
|
||||
}
|
||||
|
||||
if _, err := upstream.NewResolver(boot, 0); err != nil {
|
||||
if _, err := upstream.NewResolver(boot, upstream.Options{Timeout: 0}); err != nil {
|
||||
return boot, fmt.Errorf("invalid bootstrap server address: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -314,6 +315,16 @@ func ValidateUpstreams(upstreams []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := proxy.ParseUpstreamsConfig(upstreams,
|
||||
upstream.Options{
|
||||
Bootstrap: []string{},
|
||||
Timeout: DefaultTimeout,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var defaultUpstreamFound bool
|
||||
for _, u := range upstreams {
|
||||
d, err := validateUpstream(u)
|
||||
|
||||
@@ -2,13 +2,10 @@ package home
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -20,8 +17,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
cookieTTL = 365 * 24 // in hours
|
||||
// cookieTTL is given in hours.
|
||||
cookieTTL = 365 * 24
|
||||
sessionCookieName = "agh_session"
|
||||
|
||||
// sessionTokenSize is the length of session token in bytes.
|
||||
sessionTokenSize = 16
|
||||
)
|
||||
|
||||
type session struct {
|
||||
@@ -285,16 +286,29 @@ type loginJSON struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func getSession(u *User) ([]byte, error) {
|
||||
maxSalt := big.NewInt(math.MaxUint32)
|
||||
salt, err := rand.Int(rand.Reader, maxSalt)
|
||||
// newSessionToken returns cryptographically secure randomly generated slice of
|
||||
// bytes of sessionTokenSize length.
|
||||
//
|
||||
// TODO(e.burkov): Think about using byte array instead of byte slice.
|
||||
func newSessionToken() (data []byte, err error) {
|
||||
randData := make([]byte, sessionTokenSize)
|
||||
|
||||
_, err = rand.Read(randData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := []byte(fmt.Sprintf("%s%s%s", salt, u.Name, u.PasswordHash))
|
||||
hash := sha256.Sum256(d)
|
||||
return hash[:], nil
|
||||
return randData, nil
|
||||
}
|
||||
|
||||
// cookieTimeFormat is the format to be used in (time.Time).Format for cookie's
|
||||
// expiry field.
|
||||
const cookieTimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
|
||||
|
||||
// cookieExpiryFormat returns the formatted exp to be used in cookie string.
|
||||
// It's quite simple for now, but probably will be expanded in the future.
|
||||
func cookieExpiryFormat(exp time.Time) (formatted string) {
|
||||
return exp.Format(cookieTimeFormat)
|
||||
}
|
||||
|
||||
func (a *Auth) httpCookie(req loginJSON) (string, error) {
|
||||
@@ -303,24 +317,23 @@ func (a *Auth) httpCookie(req loginJSON) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
sess, err := getSession(&u)
|
||||
sess, err := newSessionToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
expire := now.Add(cookieTTL * time.Hour)
|
||||
expstr := expire.Format(time.RFC1123)
|
||||
expstr = expstr[:len(expstr)-len("UTC")] // "UTC" -> "GMT"
|
||||
expstr += "GMT"
|
||||
|
||||
s := session{}
|
||||
s.userName = u.Name
|
||||
s.expire = uint32(now.Unix()) + a.sessionTTL
|
||||
a.addSession(sess, &s)
|
||||
a.addSession(sess, &session{
|
||||
userName: u.Name,
|
||||
expire: uint32(now.Unix()) + a.sessionTTL,
|
||||
})
|
||||
|
||||
return fmt.Sprintf("%s=%s; Path=/; HttpOnly; Expires=%s",
|
||||
sessionCookieName, hex.EncodeToString(sess), expstr), nil
|
||||
return fmt.Sprintf(
|
||||
"%s=%s; Path=/; HttpOnly; Expires=%s",
|
||||
sessionCookieName, hex.EncodeToString(sess),
|
||||
cookieExpiryFormat(now.Add(cookieTTL*time.Hour)),
|
||||
), nil
|
||||
}
|
||||
|
||||
func handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package home
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -11,6 +13,7 @@ import (
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -24,14 +27,34 @@ func prepareTestDir() string {
|
||||
return dir
|
||||
}
|
||||
|
||||
func TestNewSessionToken(t *testing.T) {
|
||||
// Successful case.
|
||||
token, err := newSessionToken()
|
||||
require.Nil(t, err)
|
||||
assert.Len(t, token, sessionTokenSize)
|
||||
|
||||
// Break the rand.Reader.
|
||||
prevReader := rand.Reader
|
||||
t.Cleanup(func() {
|
||||
rand.Reader = prevReader
|
||||
})
|
||||
rand.Reader = &bytes.Buffer{}
|
||||
|
||||
// Unsuccessful case.
|
||||
token, err = newSessionToken()
|
||||
require.NotNil(t, err)
|
||||
assert.Empty(t, token)
|
||||
}
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
dir := prepareTestDir()
|
||||
defer func() { _ = os.RemoveAll(dir) }()
|
||||
t.Cleanup(func() { _ = os.RemoveAll(dir) })
|
||||
fn := filepath.Join(dir, "sessions.db")
|
||||
|
||||
users := []User{
|
||||
{Name: "name", PasswordHash: "$2y$05$..vyzAECIhJPfaQiOK17IukcQnqEgKJHy0iETyYqxn3YXJl8yZuo2"},
|
||||
}
|
||||
users := []User{{
|
||||
Name: "name",
|
||||
PasswordHash: "$2y$05$..vyzAECIhJPfaQiOK17IukcQnqEgKJHy0iETyYqxn3YXJl8yZuo2",
|
||||
}}
|
||||
a := InitAuth(fn, nil, 60)
|
||||
s := session{}
|
||||
|
||||
@@ -41,7 +64,7 @@ func TestAuth(t *testing.T) {
|
||||
assert.Equal(t, checkSessionNotFound, a.checkSession("notfound"))
|
||||
a.RemoveSession("notfound")
|
||||
|
||||
sess, err := getSession(&users[0])
|
||||
sess, err := newSessionToken()
|
||||
assert.Nil(t, err)
|
||||
sessStr := hex.EncodeToString(sess)
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/util"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/utils"
|
||||
)
|
||||
@@ -295,7 +296,12 @@ func (clients *clientsContainer) FindUpstreams(ip string) *proxy.UpstreamConfig
|
||||
}
|
||||
|
||||
if c.upstreamConfig == nil {
|
||||
config, err := proxy.ParseUpstreamsConfig(c.Upstreams, config.DNS.BootstrapDNS, dnsforward.DefaultTimeout)
|
||||
config, err := proxy.ParseUpstreamsConfig(c.Upstreams,
|
||||
upstream.Options{
|
||||
Bootstrap: config.DNS.BootstrapDNS,
|
||||
Timeout: dnsforward.DefaultTimeout,
|
||||
},
|
||||
)
|
||||
if err == nil {
|
||||
c.upstreamConfig = &config
|
||||
}
|
||||
|
||||
@@ -320,6 +320,7 @@ func run(args options) {
|
||||
go func() {
|
||||
err := startDNSServer()
|
||||
if err != nil {
|
||||
closeDNSServer()
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -146,7 +146,7 @@ func TestHome(t *testing.T) {
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// test DNS over UDP
|
||||
r, err := upstream.NewResolver("127.0.0.1:5354", 3*time.Second)
|
||||
r, err := upstream.NewResolver("127.0.0.1:5354", upstream.Options{Timeout: 3 * time.Second})
|
||||
assert.Nil(t, err)
|
||||
addrs, err := r.LookupIPAddr(context.TODO(), "static.adguard.com")
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -21,7 +21,7 @@ type onChangedT func()
|
||||
// AutoHosts - automatic DNS records
|
||||
type AutoHosts struct {
|
||||
// lock protects table and tableReverse.
|
||||
lock sync.Mutex
|
||||
lock sync.RWMutex
|
||||
// table is the host-to-IPs map.
|
||||
table map[string][]net.IP
|
||||
// tableReverse is the IP-to-hosts map.
|
||||
@@ -119,15 +119,14 @@ func (a *AutoHosts) Process(host string, qtype uint16) []net.IP {
|
||||
}
|
||||
|
||||
var ipsCopy []net.IP
|
||||
a.lock.Lock()
|
||||
a.lock.RLock()
|
||||
defer a.lock.RUnlock()
|
||||
|
||||
if ips, ok := a.table[host]; ok {
|
||||
ipsCopy = make([]net.IP, len(ips))
|
||||
copy(ipsCopy, ips)
|
||||
}
|
||||
|
||||
a.lock.Unlock()
|
||||
|
||||
log.Debug("AutoHosts: answer: %s -> %v", host, ipsCopy)
|
||||
return ipsCopy
|
||||
}
|
||||
@@ -145,8 +144,8 @@ func (a *AutoHosts) ProcessReverse(addr string, qtype uint16) (hosts []string) {
|
||||
|
||||
ipStr := ipReal.String()
|
||||
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
a.lock.RLock()
|
||||
defer a.lock.RUnlock()
|
||||
|
||||
hosts = a.tableReverse[ipStr]
|
||||
|
||||
@@ -161,8 +160,8 @@ func (a *AutoHosts) ProcessReverse(addr string, qtype uint16) (hosts []string) {
|
||||
|
||||
// List returns an IP-to-hostnames table. It is safe for concurrent use.
|
||||
func (a *AutoHosts) List() (ipToHosts map[string][]string) {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
a.lock.RLock()
|
||||
defer a.lock.RUnlock()
|
||||
|
||||
ipToHosts = make(map[string][]string, len(a.tableReverse))
|
||||
for k, v := range a.tableReverse {
|
||||
@@ -339,10 +338,13 @@ func (a *AutoHosts) updateHosts() {
|
||||
}
|
||||
}
|
||||
|
||||
a.lock.Lock()
|
||||
a.table = table
|
||||
a.tableReverse = tableRev
|
||||
a.lock.Unlock()
|
||||
func() {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
a.table = table
|
||||
a.tableReverse = tableRev
|
||||
}()
|
||||
|
||||
a.notify()
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
@@ -64,16 +66,43 @@ func SplitNext(str *string, splitBy byte) string {
|
||||
return strings.TrimSpace(s)
|
||||
}
|
||||
|
||||
// IsOpenWRT checks if OS is OpenWRT.
|
||||
// IsOpenWRT returns true if host OS is OpenWRT.
|
||||
func IsOpenWRT() bool {
|
||||
if runtime.GOOS != "linux" {
|
||||
return false
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadFile("/etc/os-release")
|
||||
const etcDir = "/etc"
|
||||
|
||||
// TODO(e.burkov): Take care of dealing with fs package after updating
|
||||
// Go version to 1.16.
|
||||
fileInfos, err := ioutil.ReadDir(etcDir)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.Contains(string(body), "OpenWrt")
|
||||
// fNameSubstr is a part of a name of the desired file.
|
||||
const fNameSubstr = "release"
|
||||
osNameData := []byte("OpenWrt")
|
||||
|
||||
for _, fileInfo := range fileInfos {
|
||||
if fileInfo.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.Contains(fileInfo.Name(), fNameSubstr) {
|
||||
continue
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadFile(filepath.Join(etcDir, fileInfo.Name()))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if bytes.Contains(body, osNameData) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1279,6 +1279,8 @@
|
||||
'type': 'string'
|
||||
'edns_cs_enabled':
|
||||
'type': 'boolean'
|
||||
'disable_ipv6':
|
||||
'type': 'boolean'
|
||||
'dnssec_enabled':
|
||||
'type': 'boolean'
|
||||
'cache_size':
|
||||
|
||||
@@ -11,8 +11,10 @@ set -e -f -u
|
||||
readonly awk_program='/^v[0-9]+\.[0-9]+\.[0-9]+.*$/ {
|
||||
if (!$4) {
|
||||
# The last tag is a full release version, so bump the
|
||||
# minor one to get the next one.
|
||||
# minor release number and zero the patch release number
|
||||
# to get the next release.
|
||||
$2++;
|
||||
$3 = 0;
|
||||
}
|
||||
|
||||
print($1 "." $2 "." $3);
|
||||
|
||||
Reference in New Issue
Block a user