Dns dhcpas beta feature (#17)
* add dhcp and dns types * sync dns #12 * add test #12 * implement dhcp #12 * add beta flags
This commit is contained in:
@@ -43,3 +43,5 @@ changelog:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
release:
|
||||
prerelease: auto
|
||||
@@ -13,6 +13,8 @@ Synchronize [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) config to
|
||||
- Rewrites
|
||||
- Services
|
||||
- Clients
|
||||
- DNS Config (BETA)
|
||||
- DHCP Config (BETA)
|
||||
|
||||
### Setup of initial instances
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
const (
|
||||
configCron = "cron"
|
||||
configRunOnStart = "runOnStart"
|
||||
configBeta = "beta"
|
||||
|
||||
configAPIPort = "api.port"
|
||||
configAPIUsername = "api.username"
|
||||
|
||||
@@ -37,6 +37,9 @@ func init() {
|
||||
doCmd.PersistentFlags().String("api-password", "", "Sync API password")
|
||||
_ = viper.BindPFlag(configAPIPassword, doCmd.PersistentFlags().Lookup("api-password"))
|
||||
|
||||
doCmd.PersistentFlags().String("beta", "", "Enable beta features (comma separated list)")
|
||||
_ = viper.BindPFlag(configBeta, doCmd.PersistentFlags().Lookup("beta"))
|
||||
|
||||
doCmd.PersistentFlags().String("origin-url", "", "Origin instance url")
|
||||
_ = viper.BindPFlag(configOriginURL, doCmd.PersistentFlags().Lookup("origin-url"))
|
||||
doCmd.PersistentFlags().String("origin-api-path", "/control", "Origin instance API path")
|
||||
|
||||
@@ -90,6 +90,17 @@ type Client interface {
|
||||
StatsConfig() (*types.IntervalConfig, error)
|
||||
SetStatsConfig(interval int) error
|
||||
Setup() error
|
||||
|
||||
AccessList() (*types.AccessList, error)
|
||||
SetAccessList(*types.AccessList) error
|
||||
|
||||
DNSConfig() (*types.DNSConfig, error)
|
||||
SetDNSConfig(*types.DNSConfig) error
|
||||
|
||||
DHCPServerConfig() (*types.DHCPServerConfig, error)
|
||||
SetDHCPServerConfig(*types.DHCPServerConfig) error
|
||||
AddDHCPStaticLeases(leases ...types.Lease) error
|
||||
DeleteDHCPStaticLeases(leases ...types.Lease) error
|
||||
}
|
||||
|
||||
type client struct {
|
||||
@@ -383,3 +394,58 @@ func (cl *client) Setup() error {
|
||||
req.UserInfo = nil
|
||||
return cl.doPost(req, "/install/configure")
|
||||
}
|
||||
|
||||
func (cl *client) AccessList() (*types.AccessList, error) {
|
||||
al := &types.AccessList{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(al), "/access/list")
|
||||
return al, err
|
||||
}
|
||||
|
||||
func (cl *client) SetAccessList(list *types.AccessList) error {
|
||||
cl.log.Info("Set access list")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(list), "/access/set")
|
||||
}
|
||||
|
||||
func (cl *client) DNSConfig() (*types.DNSConfig, error) {
|
||||
cfg := &types.DNSConfig{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(cfg), "/dns_info")
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func (cl *client) SetDNSConfig(config *types.DNSConfig) error {
|
||||
cl.log.Info("Set dns config list")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(config), "/dns_config")
|
||||
}
|
||||
|
||||
func (cl *client) DHCPServerConfig() (*types.DHCPServerConfig, error) {
|
||||
cfg := &types.DHCPServerConfig{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(cfg), "/dhcp/status")
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func (cl *client) SetDHCPServerConfig(config *types.DHCPServerConfig) error {
|
||||
cl.log.Info("Set dhcp server config")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(config), "/dhcp/set_config")
|
||||
}
|
||||
|
||||
func (cl *client) AddDHCPStaticLeases(leases ...types.Lease) error {
|
||||
for _, l := range leases {
|
||||
cl.log.With("mac", l.HWAddr, "ip", l.IP, "hostname", l.Hostname).Info("Add static dhcp lease")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(l), "/dhcp/add_static_lease")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *client) DeleteDHCPStaticLeases(leases ...types.Lease) error {
|
||||
for _, l := range leases {
|
||||
cl.log.With("mac", l.HWAddr, "ip", l.IP, "hostname", l.Hostname).Info("Delete static dhcp lease")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(l), "/dhcp/remove_static_lease")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -34,6 +34,21 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AccessList mocks base method.
|
||||
func (m *MockClient) AccessList() (*types.AccessList, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AccessList")
|
||||
ret0, _ := ret[0].(*types.AccessList)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AccessList indicates an expected call of AccessList.
|
||||
func (mr *MockClientMockRecorder) AccessList() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessList", reflect.TypeOf((*MockClient)(nil).AccessList))
|
||||
}
|
||||
|
||||
// AddClients mocks base method.
|
||||
func (m *MockClient) AddClients(arg0 ...types.Client) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -52,6 +67,24 @@ func (mr *MockClientMockRecorder) AddClients(arg0 ...interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddClients", reflect.TypeOf((*MockClient)(nil).AddClients), arg0...)
|
||||
}
|
||||
|
||||
// AddDHCPStaticLeases mocks base method.
|
||||
func (m *MockClient) AddDHCPStaticLeases(arg0 ...types.Lease) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddDHCPStaticLeases", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddDHCPStaticLeases indicates an expected call of AddDHCPStaticLeases.
|
||||
func (mr *MockClientMockRecorder) AddDHCPStaticLeases(arg0 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDHCPStaticLeases", reflect.TypeOf((*MockClient)(nil).AddDHCPStaticLeases), arg0...)
|
||||
}
|
||||
|
||||
// AddFilters mocks base method.
|
||||
func (m *MockClient) AddFilters(arg0 bool, arg1 ...types.Filter) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -104,6 +137,36 @@ func (mr *MockClientMockRecorder) Clients() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clients", reflect.TypeOf((*MockClient)(nil).Clients))
|
||||
}
|
||||
|
||||
// DHCPServerConfig mocks base method.
|
||||
func (m *MockClient) DHCPServerConfig() (*types.DHCPServerConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DHCPServerConfig")
|
||||
ret0, _ := ret[0].(*types.DHCPServerConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DHCPServerConfig indicates an expected call of DHCPServerConfig.
|
||||
func (mr *MockClientMockRecorder) DHCPServerConfig() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DHCPServerConfig", reflect.TypeOf((*MockClient)(nil).DHCPServerConfig))
|
||||
}
|
||||
|
||||
// DNSConfig mocks base method.
|
||||
func (m *MockClient) DNSConfig() (*types.DNSConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DNSConfig")
|
||||
ret0, _ := ret[0].(*types.DNSConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DNSConfig indicates an expected call of DNSConfig.
|
||||
func (mr *MockClientMockRecorder) DNSConfig() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DNSConfig", reflect.TypeOf((*MockClient)(nil).DNSConfig))
|
||||
}
|
||||
|
||||
// DeleteClients mocks base method.
|
||||
func (m *MockClient) DeleteClients(arg0 ...types.Client) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -122,6 +185,24 @@ func (mr *MockClientMockRecorder) DeleteClients(arg0 ...interface{}) *gomock.Cal
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClients", reflect.TypeOf((*MockClient)(nil).DeleteClients), arg0...)
|
||||
}
|
||||
|
||||
// DeleteDHCPStaticLeases mocks base method.
|
||||
func (m *MockClient) DeleteDHCPStaticLeases(arg0 ...types.Lease) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "DeleteDHCPStaticLeases", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteDHCPStaticLeases indicates an expected call of DeleteDHCPStaticLeases.
|
||||
func (mr *MockClientMockRecorder) DeleteDHCPStaticLeases(arg0 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDHCPStaticLeases", reflect.TypeOf((*MockClient)(nil).DeleteDHCPStaticLeases), arg0...)
|
||||
}
|
||||
|
||||
// DeleteFilters mocks base method.
|
||||
func (m *MockClient) DeleteFilters(arg0 bool, arg1 ...types.Filter) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -292,6 +373,20 @@ func (mr *MockClientMockRecorder) Services() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Services", reflect.TypeOf((*MockClient)(nil).Services))
|
||||
}
|
||||
|
||||
// SetAccessList mocks base method.
|
||||
func (m *MockClient) SetAccessList(arg0 *types.AccessList) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetAccessList", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetAccessList indicates an expected call of SetAccessList.
|
||||
func (mr *MockClientMockRecorder) SetAccessList(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccessList", reflect.TypeOf((*MockClient)(nil).SetAccessList), arg0)
|
||||
}
|
||||
|
||||
// SetCustomRules mocks base method.
|
||||
func (m *MockClient) SetCustomRules(arg0 types.UserRules) error {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -306,6 +401,34 @@ func (mr *MockClientMockRecorder) SetCustomRules(arg0 interface{}) *gomock.Call
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCustomRules", reflect.TypeOf((*MockClient)(nil).SetCustomRules), arg0)
|
||||
}
|
||||
|
||||
// SetDHCPServerConfig mocks base method.
|
||||
func (m *MockClient) SetDHCPServerConfig(arg0 *types.DHCPServerConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetDHCPServerConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetDHCPServerConfig indicates an expected call of SetDHCPServerConfig.
|
||||
func (mr *MockClientMockRecorder) SetDHCPServerConfig(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDHCPServerConfig", reflect.TypeOf((*MockClient)(nil).SetDHCPServerConfig), arg0)
|
||||
}
|
||||
|
||||
// SetDNSConfig mocks base method.
|
||||
func (m *MockClient) SetDNSConfig(arg0 *types.DNSConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetDNSConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetDNSConfig indicates an expected call of SetDNSConfig.
|
||||
func (mr *MockClientMockRecorder) SetDNSConfig(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDNSConfig", reflect.TypeOf((*MockClient)(nil).SetDNSConfig), arg0)
|
||||
}
|
||||
|
||||
// SetQueryLogConfig mocks base method.
|
||||
func (m *MockClient) SetQueryLogConfig(arg0 bool, arg1 int, arg2 bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
116
pkg/sync/sync.go
116
pkg/sync/sync.go
@@ -141,6 +141,28 @@ func (w *worker) sync() {
|
||||
return
|
||||
}
|
||||
|
||||
o.accessList, err = oc.AccessList()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting access list")
|
||||
return
|
||||
}
|
||||
|
||||
if w.cfg.WithBeta("dns") {
|
||||
o.dnsConfig, err = oc.DNSConfig()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting dns config")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if w.cfg.WithBeta("dhcp") {
|
||||
o.dhcpServerConfig, err = oc.DHCPServerConfig()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting dhcp server config")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
replicas := w.cfg.UniqueReplicas()
|
||||
for _, replica := range replicas {
|
||||
w.syncTo(sl, o, replica)
|
||||
@@ -202,6 +224,20 @@ func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardIn
|
||||
return
|
||||
}
|
||||
|
||||
if w.cfg.WithBeta("dns") {
|
||||
if err = w.syncDNS(o.accessList, o.dnsConfig, rc); err != nil {
|
||||
rl.With("error", err).Error("Error syncing dns")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if w.cfg.WithBeta("dhcp") {
|
||||
if err = w.syncDHCPServer(o.dhcpServerConfig, rc); err != nil {
|
||||
rl.With("error", err).Error("Error syncing dns")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
rl.Info("Sync done")
|
||||
}
|
||||
|
||||
@@ -349,23 +385,23 @@ func (w *worker) syncGeneralSettings(o *origin, rs *types.Status, replica client
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncConfigs(o *origin, replica client.Client) error {
|
||||
qlc, err := replica.QueryLogConfig()
|
||||
func (w *worker) syncConfigs(o *origin, rc client.Client) error {
|
||||
qlc, err := rc.QueryLogConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !o.queryLogConfig.Equals(qlc) {
|
||||
if err = replica.SetQueryLogConfig(o.queryLogConfig.Enabled, o.queryLogConfig.Interval, o.queryLogConfig.AnonymizeClientIP); err != nil {
|
||||
if err = rc.SetQueryLogConfig(o.queryLogConfig.Enabled, o.queryLogConfig.Interval, o.queryLogConfig.AnonymizeClientIP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sc, err := replica.StatsConfig()
|
||||
sc, err := rc.StatsConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if o.statsConfig.Interval != sc.Interval {
|
||||
if err = replica.SetStatsConfig(o.statsConfig.Interval); err != nil {
|
||||
if err = rc.SetStatsConfig(o.statsConfig.Interval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -373,15 +409,63 @@ func (w *worker) syncConfigs(o *origin, replica client.Client) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type origin struct {
|
||||
status *types.Status
|
||||
rewrites *types.RewriteEntries
|
||||
services types.Services
|
||||
filters *types.FilteringStatus
|
||||
clients *types.Clients
|
||||
queryLogConfig *types.QueryLogConfig
|
||||
statsConfig *types.IntervalConfig
|
||||
parental bool
|
||||
safeSearch bool
|
||||
safeBrowsing bool
|
||||
func (w *worker) syncDNS(oal *types.AccessList, odc *types.DNSConfig, rc client.Client) error {
|
||||
al, err := rc.AccessList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !al.Equals(oal) {
|
||||
if err = rc.SetAccessList(oal); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dc, err := rc.DNSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !dc.Equals(odc) {
|
||||
if err = rc.SetDNSConfig(odc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncDHCPServer(osc *types.DHCPServerConfig, rc client.Client) error {
|
||||
sc, err := rc.DHCPServerConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !sc.Equals(osc) {
|
||||
if err = rc.SetDHCPServerConfig(osc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
a, r := sc.StaticLeases.Merge(osc.StaticLeases)
|
||||
|
||||
if err = rc.AddDHCPStaticLeases(a...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = rc.DeleteDHCPStaticLeases(r...); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type origin struct {
|
||||
status *types.Status
|
||||
rewrites *types.RewriteEntries
|
||||
services types.Services
|
||||
filters *types.FilteringStatus
|
||||
clients *types.Clients
|
||||
queryLogConfig *types.QueryLogConfig
|
||||
statsConfig *types.IntervalConfig
|
||||
accessList *types.AccessList
|
||||
dnsConfig *types.DNSConfig
|
||||
dhcpServerConfig *types.DHCPServerConfig
|
||||
parental bool
|
||||
safeSearch bool
|
||||
safeBrowsing bool
|
||||
}
|
||||
|
||||
@@ -369,12 +369,51 @@ var _ = Describe("Sync", func() {
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("syncDNS", func() {
|
||||
var (
|
||||
oal *types.AccessList
|
||||
ral *types.AccessList
|
||||
odc *types.DNSConfig
|
||||
rdc *types.DNSConfig
|
||||
)
|
||||
BeforeEach(func() {
|
||||
oal = &types.AccessList{}
|
||||
ral = &types.AccessList{}
|
||||
odc = &types.DNSConfig{}
|
||||
rdc = &types.DNSConfig{}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().AccessList().Return(ral, nil)
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
err := w.syncDNS(oal, odc, cl)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have access list changes", func() {
|
||||
ral.BlockedHosts = []string{"foo"}
|
||||
cl.EXPECT().AccessList().Return(ral, nil)
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
cl.EXPECT().SetAccessList(oal)
|
||||
err := w.syncDNS(oal, odc, cl)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have dns config changes", func() {
|
||||
rdc.Bootstraps = []string{"foo"}
|
||||
cl.EXPECT().AccessList().Return(ral, nil)
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
cl.EXPECT().SetDNSConfig(odc)
|
||||
err := w.syncDNS(oal, odc, cl)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("sync", func() {
|
||||
|
||||
It("should have no changes", func() {
|
||||
w.cfg = &types.Config{
|
||||
Origin: types.AdGuardInstance{},
|
||||
Replica: types.AdGuardInstance{URL: "foo"},
|
||||
Beta: "dhcp,dns",
|
||||
}
|
||||
// origin
|
||||
cl.EXPECT().Host()
|
||||
@@ -388,6 +427,9 @@ var _ = Describe("Sync", func() {
|
||||
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().DHCPServerConfig().Return(&types.DHCPServerConfig{}, nil)
|
||||
|
||||
// replica
|
||||
cl.EXPECT().Host()
|
||||
@@ -412,6 +454,11 @@ var _ = Describe("Sync", func() {
|
||||
cl.EXPECT().AddClients()
|
||||
cl.EXPECT().UpdateClients()
|
||||
cl.EXPECT().DeleteClients()
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().DHCPServerConfig().Return(&types.DHCPServerConfig{}, nil)
|
||||
cl.EXPECT().AddDHCPStaticLeases().Return(nil)
|
||||
cl.EXPECT().DeleteDHCPStaticLeases().Return(nil)
|
||||
w.sync()
|
||||
})
|
||||
})
|
||||
|
||||
76
pkg/types/dhcp.go
Normal file
76
pkg/types/dhcp.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DHCPServerConfig struct {
|
||||
V4 *V4ServerConfJSON `json:"v4"`
|
||||
V6 *V6ServerConfJSON `json:"v6"`
|
||||
InterfaceName string `json:"interface_name"`
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
Leases Leases `json:"leases,omitempty"`
|
||||
StaticLeases Leases `json:"static_leases,omitempty"`
|
||||
}
|
||||
|
||||
// Equals dhcp server config equal check
|
||||
func (c *DHCPServerConfig) Equals(o *DHCPServerConfig) bool {
|
||||
a, _ := json.Marshal(c)
|
||||
b, _ := json.Marshal(o)
|
||||
return string(a) == string(b)
|
||||
}
|
||||
|
||||
type V4ServerConfJSON struct {
|
||||
GatewayIP net.IP `json:"gateway_ip"`
|
||||
SubnetMask net.IP `json:"subnet_mask"`
|
||||
RangeStart net.IP `json:"range_start"`
|
||||
RangeEnd net.IP `json:"range_end"`
|
||||
LeaseDuration uint32 `json:"lease_duration"`
|
||||
}
|
||||
|
||||
type V6ServerConfJSON struct {
|
||||
RangeStart net.IP `json:"range_start"`
|
||||
RangeEnd net.IP `json:"range_end"`
|
||||
LeaseDuration uint32 `json:"lease_duration"`
|
||||
}
|
||||
|
||||
type Leases []Lease
|
||||
|
||||
// Merge the leases
|
||||
func (l Leases) Merge(other Leases) ([]Lease, []Lease) {
|
||||
current := make(map[string]Lease)
|
||||
|
||||
var adds Leases
|
||||
var removes Leases
|
||||
for _, le := range l {
|
||||
current[le.HWAddr] = le
|
||||
}
|
||||
|
||||
for _, le := range other {
|
||||
if _, ok := current[le.HWAddr]; ok {
|
||||
delete(current, le.HWAddr)
|
||||
} else {
|
||||
adds = append(adds, le)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, removes
|
||||
}
|
||||
|
||||
// Lease contains the necessary information about a DHCP lease
|
||||
type Lease struct {
|
||||
HWAddr string `json:"mac"`
|
||||
IP net.IP `json:"ip"`
|
||||
Hostname string `json:"hostname"`
|
||||
|
||||
// Lease expiration time
|
||||
// 1: static lease
|
||||
Expiry time.Time `json:"expires"`
|
||||
}
|
||||
78
pkg/types/dns.go
Normal file
78
pkg/types/dns.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// https://ha.bakito.net:3000/control/dns_config
|
||||
// {"bootstrap_dns":["1.1.1.1:53"],"upstream_mode":"parallel","upstream_dns":["https://dns10.quad9.net/dns-query"]}
|
||||
// {"bootstrap_dns":["1.1.1.1:53"],"upstream_mode":"","upstream_dns":["https://dns10.quad9.net/dns-query"]}
|
||||
// {"bootstrap_dns":["1.1.1.1:53"],"upstream_mode":"fastest_addr","upstream_dns":["https://dns10.quad9.net/dns-query"]}
|
||||
|
||||
// {"ratelimit":20,"blocking_mode":"default","blocking_ipv4":"0.0.0.0","blocking_ipv6":"::","edns_cs_enabled":true,"disable_ipv6":false,"dnssec_enabled":false}
|
||||
// {"cache_size":4194304,"cache_ttl_max":0,"cache_ttl_min":0}
|
||||
|
||||
// https://ha.bakito.net:3000/control/access/set
|
||||
// {"allowed_clients":["2.2.2.2"],"disallowed_clients":["1.1.1.1"],"blocked_hosts":["version.bind","id.server","hostname.bind"]}
|
||||
// https://ha.bakito.net:3000/control/access/list
|
||||
// {"allowed_clients":[],"disallowed_clients":[],"blocked_hosts":["version.bind","id.server","hostname.bind"]}
|
||||
|
||||
type DNSConfig struct {
|
||||
Upstreams []string `json:"upstream_dns,omitempty"`
|
||||
UpstreamsFile string `json:"upstream_dns_file"`
|
||||
Bootstraps []string `json:"bootstrap_dns,omitempty"`
|
||||
|
||||
ProtectionEnabled bool `json:"protection_enabled"`
|
||||
RateLimit uint32 `json:"ratelimit"`
|
||||
BlockingMode string `json:"blocking_mode,omitempty"`
|
||||
BlockingIPv4 net.IP `json:"blocking_ipv4,omitempty"`
|
||||
BlockingIPv6 net.IP `json:"blocking_ipv6"`
|
||||
EDNSCSEnabled bool `json:"edns_cs_enabled"`
|
||||
DNSSECEnabled bool `json:"dnssec_enabled"`
|
||||
DisableIPv6 bool `json:"disable_ipv6"`
|
||||
UpstreamMode string `json:"upstream_mode,omitempty"`
|
||||
CacheSize uint32 `json:"cache_size"`
|
||||
CacheMinTTL uint32 `json:"cache_ttl_min"`
|
||||
CacheMaxTTL uint32 `json:"cache_ttl_max"`
|
||||
ResolveClients bool `json:"resolve_clients"`
|
||||
LocalPTRUpstreams []string `json:"local_ptr_upstreams,omitempty"`
|
||||
}
|
||||
|
||||
// Equals dns config equal check
|
||||
func (c *DNSConfig) Equals(o *DNSConfig) bool {
|
||||
c.Sort()
|
||||
o.Sort()
|
||||
|
||||
a, _ := json.Marshal(c)
|
||||
b, _ := json.Marshal(o)
|
||||
return string(a) == string(b)
|
||||
}
|
||||
|
||||
// Sort sort dns config
|
||||
func (c *DNSConfig) Sort() {
|
||||
sort.Strings(c.Upstreams)
|
||||
sort.Strings(c.Bootstraps)
|
||||
sort.Strings(c.LocalPTRUpstreams)
|
||||
}
|
||||
|
||||
type AccessList struct {
|
||||
AllowedClients []string `json:"allowed_clients"`
|
||||
DisallowedClients []string `json:"disallowed_clients"`
|
||||
BlockedHosts []string `json:"blocked_hosts"`
|
||||
}
|
||||
|
||||
// Equals access list equal check
|
||||
func (al *AccessList) Equals(o *AccessList) bool {
|
||||
return equals(al.AllowedClients, o.AllowedClients) &&
|
||||
equals(al.DisallowedClients, o.DisallowedClients) &&
|
||||
equals(al.BlockedHosts, o.BlockedHosts)
|
||||
}
|
||||
|
||||
// Sort sort access list
|
||||
func (al *AccessList) Sort() {
|
||||
sort.Strings(al.AllowedClients)
|
||||
sort.Strings(al.DisallowedClients)
|
||||
sort.Strings(al.BlockedHosts)
|
||||
}
|
||||
@@ -5,20 +5,27 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultAPIPath = "/control"
|
||||
)
|
||||
|
||||
var (
|
||||
doOnce sync.Once
|
||||
)
|
||||
|
||||
// Config application configuration struct
|
||||
type Config struct {
|
||||
Origin AdGuardInstance `json:"origin" yaml:"origin"`
|
||||
Replica AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
Cron string `json:"cron,omitempty" yaml:"cron,omitempty"`
|
||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty"`
|
||||
API API `json:"api,omitempty" yaml:"api,omitempty"`
|
||||
Origin AdGuardInstance `json:"origin" yaml:"origin"`
|
||||
Replica AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
Cron string `json:"cron,omitempty" yaml:"cron,omitempty"`
|
||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty"`
|
||||
API API `json:"api,omitempty" yaml:"api,omitempty"`
|
||||
Beta string `json:"beta,omitempty" yaml:"beta,omitempty"`
|
||||
enabledBeta map[string]bool `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// API configuration
|
||||
@@ -50,6 +57,19 @@ func (cfg *Config) UniqueReplicas() []AdGuardInstance {
|
||||
return r
|
||||
}
|
||||
|
||||
func (cfg *Config) WithBeta(name string) bool {
|
||||
doOnce.Do(func() {
|
||||
cfg.enabledBeta = make(map[string]bool)
|
||||
|
||||
features := strings.Split(cfg.Beta, ",")
|
||||
for _, f := range features {
|
||||
cfg.enabledBeta[strings.ToLower(strings.TrimSpace(f))] = true
|
||||
}
|
||||
})
|
||||
return cfg.enabledBeta[name]
|
||||
|
||||
}
|
||||
|
||||
// AdGuardInstance AdguardHome config instance
|
||||
type AdGuardInstance struct {
|
||||
URL string `json:"url" yaml:"url"`
|
||||
@@ -278,8 +298,8 @@ func (cl *Client) Sort() {
|
||||
sort.Strings(cl.Upstreams)
|
||||
}
|
||||
|
||||
// Equal Clients equal check
|
||||
func (cl *Client) Equal(o *Client) bool {
|
||||
// Equals Clients equal check
|
||||
func (cl *Client) Equals(o *Client) bool {
|
||||
cl.Sort()
|
||||
o.Sort()
|
||||
|
||||
@@ -306,7 +326,7 @@ func (clients *Clients) Merge(other *Clients) ([]Client, []Client, []Client) {
|
||||
|
||||
for _, cl := range expected {
|
||||
if oc, ok := current[cl.Name]; ok {
|
||||
if !cl.Equal(&oc) {
|
||||
if !cl.Equals(&oc) {
|
||||
updates = append(updates, cl)
|
||||
}
|
||||
delete(current, cl.Name)
|
||||
|
||||
@@ -305,4 +305,18 @@ var _ = Describe("Types", func() {
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("DNSConfig", func() {
|
||||
Context("Equals", func() {
|
||||
It("should be equal", func() {
|
||||
dc1 := &types.DNSConfig{Upstreams: []string{"a"}}
|
||||
dc2 := &types.DNSConfig{Upstreams: []string{"a"}}
|
||||
Ω(dc1.Equals(dc2)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal", func() {
|
||||
dc1 := &types.DNSConfig{Upstreams: []string{"a"}}
|
||||
dc2 := &types.DNSConfig{Upstreams: []string{"b"}}
|
||||
Ω(dc1.Equals(dc2)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
17
testdata/dhcp-status.json
vendored
Normal file
17
testdata/dhcp-status.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"enabled": false,
|
||||
"interface_name": "docker0",
|
||||
"v4": {
|
||||
"gateway_ip": "172.17.0.1",
|
||||
"subnet_mask": "255.255.255.0",
|
||||
"range_start": "172.17.0.100",
|
||||
"range_end": "172.17.0.200",
|
||||
"lease_duration": 888888
|
||||
},
|
||||
"v6": {
|
||||
"range_start": "",
|
||||
"lease_duration": 0
|
||||
},
|
||||
"leases": [],
|
||||
"static_leases": []
|
||||
}
|
||||
22
testdata/dns-info.json
vendored
Normal file
22
testdata/dns-info.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"upstream_dns": [
|
||||
"https://dns10.quad9.net/dns-query"
|
||||
],
|
||||
"upstream_dns_file": "",
|
||||
"bootstrap_dns": [
|
||||
"1.1.1.1:53"
|
||||
],
|
||||
"protection_enabled": true,
|
||||
"ratelimit": 20,
|
||||
"blocking_mode": "default",
|
||||
"blocking_ipv4": "",
|
||||
"blocking_ipv6": "",
|
||||
"edns_cs_enabled": false,
|
||||
"dnssec_enabled": false,
|
||||
"disable_ipv6": false,
|
||||
"upstream_mode": "",
|
||||
"cache_size": 4194304,
|
||||
"cache_ttl_min": 0,
|
||||
"cache_ttl_max": 0
|
||||
}
|
||||
|
||||
20
testdata/tls-status.json
vendored
Normal file
20
testdata/tls-status.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"enabled": false,
|
||||
"port_https": 443,
|
||||
"port_dns_over_tls": 853,
|
||||
"port_dns_over_quic": 784,
|
||||
"port_dnscrypt": 0,
|
||||
"dnscrypt_config_file": "",
|
||||
"allow_unencrypted_doh": false,
|
||||
"certificate_chain": "",
|
||||
"private_key": "",
|
||||
"certificate_path": "",
|
||||
"private_key_path": "",
|
||||
"valid_cert": false,
|
||||
"valid_chain": false,
|
||||
"not_before": "0001-01-01T00:00:00Z",
|
||||
"not_after": "0001-01-01T00:00:00Z",
|
||||
"dns_names": null,
|
||||
"valid_key": false,
|
||||
"valid_pair": false
|
||||
}
|
||||
Reference in New Issue
Block a user