mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-04 19:55:09 -04:00
support for dns custom zones
Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
@@ -26,6 +26,7 @@ type NetworkMapDBStore interface {
|
||||
GetNetworkResources(ctx context.Context, accountId string) ([]nmdata.NetworkResource, error)
|
||||
GetNetworkRouters(ctx context.Context, accountId string) ([]nmdata.NetworkRouter, error)
|
||||
GetNetwork(ctx context.Context, accountId string) (nmdata.Network, error)
|
||||
GetAccountZones(ctx context.Context, accountId string) ([]nmdata.CustomZone, error)
|
||||
}
|
||||
|
||||
type NetworkMapDBStoreImpl struct {
|
||||
|
||||
@@ -2,41 +2,101 @@ package networkmap_pgsql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/miekg/dns"
|
||||
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
|
||||
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
||||
)
|
||||
|
||||
var DnsUnsupportedRecordTypeError = errors.New("unsupported record type")
|
||||
|
||||
const (
|
||||
GetCustomZonesQuery = `
|
||||
select id, public_id, name, description, name_servers, groups, "primary", domains, enabled, search_domains_enabled
|
||||
from name_server_groups
|
||||
where account_id=$1
|
||||
GetAccountZonesQuery = `
|
||||
select zones.id as id, domain, enable_search_domain as search_domain_disabled,
|
||||
r.name as record_name, r.type as record_type, 'IN' record_class, r.ttl as record_ttl, r.content as record_rdata
|
||||
from zones
|
||||
left join records as r on r.zone_id = zones.id
|
||||
where zones.account_id=$1
|
||||
`
|
||||
)
|
||||
|
||||
func (pg *PgStore) GetCustomZones(ctx context.Context, accountId string) ([]nmdata.NameServerGroup, error) {
|
||||
rows, err := pg.pool.Query(ctx, GetNameserversQuery, accountId)
|
||||
func (pg *PgStore) GetAccountZones(ctx context.Context, accountId string) ([]nmdata.CustomZone, error) {
|
||||
rows, err := pg.pool.Query(ctx, GetAccountZonesQuery, accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nsgroups, err := pgx.CollectRows(rows, pgx.RowToStructByName[nameserverGroup])
|
||||
zones, err := pgx.CollectRows(rows, pgx.RowToStructByName[zone])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
toret := make([]nmdata.NameServerGroup, 0, len(nsgroups))
|
||||
for _, nsg := range nsgroups {
|
||||
group := nmdata.NameServerGroup{}
|
||||
toret := make([]nmdata.CustomZone, 0, len(zones))
|
||||
currentZoneId := ""
|
||||
for _, z := range zones {
|
||||
zone := nmdata.CustomZone{}
|
||||
err := networkmapdb.FromSqlTypesToSharedTypes(
|
||||
reflect.ValueOf(&nsg), reflect.ValueOf(&group))
|
||||
reflect.ValueOf(&z), reflect.ValueOf(&zone))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
toret = append(toret, group)
|
||||
|
||||
rtype, rdata, err := recordTypeAndRdata(z.RecordType.String, z.RecordRData.String)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
record := nmdata.SimpleRecord{
|
||||
Name: z.RecordName.String,
|
||||
Class: z.RecordClass.String,
|
||||
TTL: int(z.RecordTTL.Int64),
|
||||
RData: rdata,
|
||||
Type: rtype,
|
||||
}
|
||||
zone.Records = []nmdata.SimpleRecord{record}
|
||||
|
||||
if len(toret) == 0 {
|
||||
toret = append(toret, zone)
|
||||
currentZoneId = z.Id
|
||||
continue
|
||||
}
|
||||
|
||||
if z.Id == currentZoneId {
|
||||
lastZone := &toret[len(toret)-1]
|
||||
lastZone.Records = append(lastZone.Records, record)
|
||||
continue
|
||||
}
|
||||
|
||||
toret = append(toret, zone)
|
||||
currentZoneId = z.Id
|
||||
}
|
||||
return toret, nil
|
||||
}
|
||||
|
||||
type zone struct {
|
||||
Id string `nmap:"skip"`
|
||||
Domain sql.NullString
|
||||
SearchDomainDisabled sql.NullBool
|
||||
RecordName sql.NullString `nmap:"skip"`
|
||||
RecordType sql.NullString `nmap:"skip"`
|
||||
RecordClass sql.NullString `nmap:"skip"`
|
||||
RecordTTL sql.NullInt64 `nmap:"skip"`
|
||||
RecordRData sql.NullString `nmap:"skip"`
|
||||
}
|
||||
|
||||
func recordTypeAndRdata(t, rdata string) (int, string, error) {
|
||||
switch t {
|
||||
case "A":
|
||||
return int(dns.TypeA), rdata, nil
|
||||
case "AAAA":
|
||||
return int(dns.TypeAAAA), rdata, nil
|
||||
case "CNAME":
|
||||
return int(dns.TypeCNAME), dns.Fqdn(rdata), nil
|
||||
default:
|
||||
return 0, "", fmt.Errorf("record type: %s %w", t, DnsUnsupportedRecordTypeError)
|
||||
}
|
||||
}
|
||||
|
||||
38
management/internals/network_map_db/pgsql/dns_test.go
Normal file
38
management/internals/network_map_db/pgsql/dns_test.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package networkmap_pgsql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRecordTypeAndRdata(t *testing.T) {
|
||||
var tests = []struct {
|
||||
recordType string
|
||||
expectedRecordType int
|
||||
rdata string
|
||||
expectedRdata string
|
||||
expectedErr error
|
||||
}{
|
||||
{recordType: "A", expectedRecordType: 1, rdata: "test.com", expectedRdata: "test.com", expectedErr: nil},
|
||||
{recordType: "AAAA", expectedRecordType: 28, rdata: "test.com", expectedRdata: "test.com", expectedErr: nil},
|
||||
{recordType: "CNAME", expectedRecordType: 5, rdata: "test.com", expectedRdata: "test.com.", expectedErr: nil},
|
||||
{recordType: "CNAME", expectedRecordType: 5, rdata: "test.com.", expectedRdata: "test.com.", expectedErr: nil},
|
||||
{recordType: "TypeMX", expectedErr: DnsUnsupportedRecordTypeError},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.recordType, func(t *testing.T) {
|
||||
recordType, rdata, err := recordTypeAndRdata(tt.recordType, tt.rdata)
|
||||
|
||||
if tt.expectedErr != nil {
|
||||
assert.ErrorIs(t, err, DnsUnsupportedRecordTypeError)
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, recordType, tt.expectedRecordType)
|
||||
assert.Equal(t, rdata, tt.expectedRdata)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -193,6 +193,28 @@ func TestGetNetwork(t *testing.T) {
|
||||
// )
|
||||
}
|
||||
|
||||
func TestGetAccountZones(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
s, err := NewPostgresqlStore(ctx, "postgresql://root:netbird@localhost:5432/netbird")
|
||||
assert.NoError(t, err)
|
||||
// err = loadSQL(ctx, s.pool, initDb)
|
||||
//assert.NoError(t, err)
|
||||
|
||||
zones, err := s.GetAccountZones(ctx, "d4g66rjl0ubs73b2q3b0") //"ckd7ee2fic3c73dtendg")
|
||||
assert.NoError(t, err)
|
||||
|
||||
fmt.Print(zones)
|
||||
// assert.Contains(t,
|
||||
// groups,
|
||||
// nmdata.Group{Name: "test-group-1", PublicID: "public-id-1", Resources: []nmdata.Resource{{ID: "cui7q2jl0ubs73d8qpi0", Type: "host"}}},
|
||||
// )
|
||||
// assert.Contains(t,
|
||||
// groups,
|
||||
// nmdata.Group{Name: "All", PublicID: "d9aejspvcsu517nkh4a0", Resources: []nmdata.Resource{{ID: "cui7olrl0ubs73d8qpe0", Type: "subnet"}, {ID: "cui7q2jl0ubs73d8qpi0", Type: "host"}}},
|
||||
// )
|
||||
}
|
||||
|
||||
func loadSQL(ctx context.Context, pool *pgxpool.Pool, initdb string) error {
|
||||
queries := strings.Split(string(initdb), ";")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user