mirror of
https://github.com/fosrl/olm.git
synced 2026-03-09 20:26:47 +00:00
Compare commits
1 Commits
dev
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7b590a23e |
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.25-alpine AS builder
|
||||
FROM golang:1.26-alpine AS builder
|
||||
|
||||
# Set the working directory inside the container
|
||||
WORKDIR /app
|
||||
|
||||
@@ -447,20 +447,19 @@ func (p *DNSProxy) checkLocalRecords(query *dns.Msg, question dns.Question) *dns
|
||||
return nil
|
||||
}
|
||||
|
||||
ips, exists := p.recordStore.GetRecords(question.Name, recordType)
|
||||
if !exists {
|
||||
// Domain not found in local records, forward to upstream
|
||||
ips := p.recordStore.GetRecords(question.Name, recordType)
|
||||
if len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Debug("Found %d local record(s) for %s", len(ips), question.Name)
|
||||
|
||||
// Create response message (NODATA if no records, otherwise with answers)
|
||||
// Create response message
|
||||
response := new(dns.Msg)
|
||||
response.SetReply(query)
|
||||
response.Authoritative = true
|
||||
|
||||
// Add answer records (loop is a no-op if ips is empty)
|
||||
// Add answer records
|
||||
for _, ip := range ips {
|
||||
var rr dns.RR
|
||||
if question.Qtype == dns.TypeA {
|
||||
@@ -731,9 +730,8 @@ func (p *DNSProxy) RemoveDNSRecord(domain string, ip net.IP) {
|
||||
p.recordStore.RemoveRecord(domain, ip)
|
||||
}
|
||||
|
||||
// GetDNSRecords returns all IP addresses for a domain and record type.
|
||||
// The second return value indicates whether the domain exists.
|
||||
func (p *DNSProxy) GetDNSRecords(domain string, recordType RecordType) ([]net.IP, bool) {
|
||||
// GetDNSRecords returns all IP addresses for a domain and record type
|
||||
func (p *DNSProxy) GetDNSRecords(domain string, recordType RecordType) []net.IP {
|
||||
return p.recordStore.GetRecords(domain, recordType)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func TestCheckLocalRecordsNODATAForAAAA(t *testing.T) {
|
||||
proxy := &DNSProxy{
|
||||
recordStore: NewDNSRecordStore(),
|
||||
}
|
||||
|
||||
// Add an A record for a domain (no AAAA record)
|
||||
ip := net.ParseIP("10.0.0.1")
|
||||
err := proxy.recordStore.AddRecord("myservice.internal", ip)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add A record: %v", err)
|
||||
}
|
||||
|
||||
// Query AAAA for domain with only A record - should return NODATA
|
||||
query := new(dns.Msg)
|
||||
query.SetQuestion("myservice.internal.", dns.TypeAAAA)
|
||||
response := proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response == nil {
|
||||
t.Fatal("Expected NODATA response, got nil (would forward to upstream)")
|
||||
}
|
||||
if response.Rcode != dns.RcodeSuccess {
|
||||
t.Errorf("Expected Rcode NOERROR (0), got %d", response.Rcode)
|
||||
}
|
||||
if len(response.Answer) != 0 {
|
||||
t.Errorf("Expected empty answer section for NODATA, got %d answers", len(response.Answer))
|
||||
}
|
||||
if !response.Authoritative {
|
||||
t.Error("Expected response to be authoritative")
|
||||
}
|
||||
|
||||
// Query A for same domain - should return the record
|
||||
query = new(dns.Msg)
|
||||
query.SetQuestion("myservice.internal.", dns.TypeA)
|
||||
response = proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response == nil {
|
||||
t.Fatal("Expected response with A record, got nil")
|
||||
}
|
||||
if len(response.Answer) != 1 {
|
||||
t.Fatalf("Expected 1 answer, got %d", len(response.Answer))
|
||||
}
|
||||
aRecord, ok := response.Answer[0].(*dns.A)
|
||||
if !ok {
|
||||
t.Fatal("Expected A record in answer")
|
||||
}
|
||||
if !aRecord.A.Equal(ip.To4()) {
|
||||
t.Errorf("Expected IP %v, got %v", ip.To4(), aRecord.A)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckLocalRecordsNODATAForA(t *testing.T) {
|
||||
proxy := &DNSProxy{
|
||||
recordStore: NewDNSRecordStore(),
|
||||
}
|
||||
|
||||
// Add an AAAA record for a domain (no A record)
|
||||
ip := net.ParseIP("2001:db8::1")
|
||||
err := proxy.recordStore.AddRecord("ipv6only.internal", ip)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add AAAA record: %v", err)
|
||||
}
|
||||
|
||||
// Query A for domain with only AAAA record - should return NODATA
|
||||
query := new(dns.Msg)
|
||||
query.SetQuestion("ipv6only.internal.", dns.TypeA)
|
||||
response := proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response == nil {
|
||||
t.Fatal("Expected NODATA response, got nil")
|
||||
}
|
||||
if response.Rcode != dns.RcodeSuccess {
|
||||
t.Errorf("Expected Rcode NOERROR (0), got %d", response.Rcode)
|
||||
}
|
||||
if len(response.Answer) != 0 {
|
||||
t.Errorf("Expected empty answer section, got %d answers", len(response.Answer))
|
||||
}
|
||||
if !response.Authoritative {
|
||||
t.Error("Expected response to be authoritative")
|
||||
}
|
||||
|
||||
// Query AAAA for same domain - should return the record
|
||||
query = new(dns.Msg)
|
||||
query.SetQuestion("ipv6only.internal.", dns.TypeAAAA)
|
||||
response = proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response == nil {
|
||||
t.Fatal("Expected response with AAAA record, got nil")
|
||||
}
|
||||
if len(response.Answer) != 1 {
|
||||
t.Fatalf("Expected 1 answer, got %d", len(response.Answer))
|
||||
}
|
||||
aaaaRecord, ok := response.Answer[0].(*dns.AAAA)
|
||||
if !ok {
|
||||
t.Fatal("Expected AAAA record in answer")
|
||||
}
|
||||
if !aaaaRecord.AAAA.Equal(ip) {
|
||||
t.Errorf("Expected IP %v, got %v", ip, aaaaRecord.AAAA)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckLocalRecordsNonExistentDomain(t *testing.T) {
|
||||
proxy := &DNSProxy{
|
||||
recordStore: NewDNSRecordStore(),
|
||||
}
|
||||
|
||||
// Add a record so the store isn't empty
|
||||
err := proxy.recordStore.AddRecord("exists.internal", net.ParseIP("10.0.0.1"))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add record: %v", err)
|
||||
}
|
||||
|
||||
// Query A for non-existent domain - should return nil (forward to upstream)
|
||||
query := new(dns.Msg)
|
||||
query.SetQuestion("unknown.internal.", dns.TypeA)
|
||||
response := proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response != nil {
|
||||
t.Error("Expected nil for non-existent domain, got response")
|
||||
}
|
||||
|
||||
// Query AAAA for non-existent domain - should also return nil
|
||||
query = new(dns.Msg)
|
||||
query.SetQuestion("unknown.internal.", dns.TypeAAAA)
|
||||
response = proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response != nil {
|
||||
t.Error("Expected nil for non-existent domain, got response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckLocalRecordsNODATAWildcard(t *testing.T) {
|
||||
proxy := &DNSProxy{
|
||||
recordStore: NewDNSRecordStore(),
|
||||
}
|
||||
|
||||
// Add a wildcard A record (no AAAA)
|
||||
ip := net.ParseIP("10.0.0.1")
|
||||
err := proxy.recordStore.AddRecord("*.wildcard.internal", ip)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to add wildcard A record: %v", err)
|
||||
}
|
||||
|
||||
// Query AAAA for wildcard-matched domain - should return NODATA
|
||||
query := new(dns.Msg)
|
||||
query.SetQuestion("host.wildcard.internal.", dns.TypeAAAA)
|
||||
response := proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response == nil {
|
||||
t.Fatal("Expected NODATA response for wildcard match, got nil")
|
||||
}
|
||||
if response.Rcode != dns.RcodeSuccess {
|
||||
t.Errorf("Expected Rcode NOERROR (0), got %d", response.Rcode)
|
||||
}
|
||||
if len(response.Answer) != 0 {
|
||||
t.Errorf("Expected empty answer section, got %d answers", len(response.Answer))
|
||||
}
|
||||
|
||||
// Query A for wildcard-matched domain - should return the record
|
||||
query = new(dns.Msg)
|
||||
query.SetQuestion("host.wildcard.internal.", dns.TypeA)
|
||||
response = proxy.checkLocalRecords(query, query.Question[0])
|
||||
|
||||
if response == nil {
|
||||
t.Fatal("Expected response with A record, got nil")
|
||||
}
|
||||
if len(response.Answer) != 1 {
|
||||
t.Fatalf("Expected 1 answer, got %d", len(response.Answer))
|
||||
}
|
||||
}
|
||||
@@ -18,26 +18,23 @@ const (
|
||||
RecordTypePTR RecordType = RecordType(dns.TypePTR)
|
||||
)
|
||||
|
||||
// recordSet holds A and AAAA records for a single domain or wildcard pattern
|
||||
type recordSet struct {
|
||||
A []net.IP
|
||||
AAAA []net.IP
|
||||
}
|
||||
|
||||
// DNSRecordStore manages local DNS records for A, AAAA, and PTR queries.
|
||||
// Exact domains are stored in a map; wildcard patterns are in a separate map.
|
||||
// DNSRecordStore manages local DNS records for A, AAAA, and PTR queries
|
||||
type DNSRecordStore struct {
|
||||
mu sync.RWMutex
|
||||
exact map[string]*recordSet // normalized FQDN -> A/AAAA records
|
||||
wildcards map[string]*recordSet // wildcard pattern -> A/AAAA records
|
||||
aRecords map[string][]net.IP // domain -> list of IPv4 addresses
|
||||
aaaaRecords map[string][]net.IP // domain -> list of IPv6 addresses
|
||||
aWildcards map[string][]net.IP // wildcard pattern -> list of IPv4 addresses
|
||||
aaaaWildcards map[string][]net.IP // wildcard pattern -> list of IPv6 addresses
|
||||
ptrRecords map[string]string // IP address string -> domain name
|
||||
}
|
||||
|
||||
// NewDNSRecordStore creates a new DNS record store
|
||||
func NewDNSRecordStore() *DNSRecordStore {
|
||||
return &DNSRecordStore{
|
||||
exact: make(map[string]*recordSet),
|
||||
wildcards: make(map[string]*recordSet),
|
||||
aRecords: make(map[string][]net.IP),
|
||||
aaaaRecords: make(map[string][]net.IP),
|
||||
aWildcards: make(map[string][]net.IP),
|
||||
aaaaWildcards: make(map[string][]net.IP),
|
||||
ptrRecords: make(map[string]string),
|
||||
}
|
||||
}
|
||||
@@ -51,37 +48,39 @@ func (s *DNSRecordStore) AddRecord(domain string, ip net.IP) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// Ensure domain ends with a dot (FQDN format)
|
||||
if len(domain) == 0 || domain[len(domain)-1] != '.' {
|
||||
domain = domain + "."
|
||||
}
|
||||
|
||||
// Normalize domain to lowercase FQDN
|
||||
domain = strings.ToLower(dns.Fqdn(domain))
|
||||
|
||||
// Check if domain contains wildcards
|
||||
isWildcard := strings.ContainsAny(domain, "*?")
|
||||
|
||||
isV4 := ip.To4() != nil
|
||||
if !isV4 && ip.To16() == nil {
|
||||
if ip.To4() != nil {
|
||||
// IPv4 address
|
||||
if isWildcard {
|
||||
s.aWildcards[domain] = append(s.aWildcards[domain], ip)
|
||||
} else {
|
||||
s.aRecords[domain] = append(s.aRecords[domain], ip)
|
||||
// Automatically add PTR record for non-wildcard domains
|
||||
s.ptrRecords[ip.String()] = domain
|
||||
}
|
||||
} else if ip.To16() != nil {
|
||||
// IPv6 address
|
||||
if isWildcard {
|
||||
s.aaaaWildcards[domain] = append(s.aaaaWildcards[domain], ip)
|
||||
} else {
|
||||
s.aaaaRecords[domain] = append(s.aaaaRecords[domain], ip)
|
||||
// Automatically add PTR record for non-wildcard domains
|
||||
s.ptrRecords[ip.String()] = domain
|
||||
}
|
||||
} else {
|
||||
return &net.ParseError{Type: "IP address", Text: ip.String()}
|
||||
}
|
||||
|
||||
// Choose the appropriate map based on whether this is a wildcard
|
||||
m := s.exact
|
||||
if isWildcard {
|
||||
m = s.wildcards
|
||||
}
|
||||
|
||||
if m[domain] == nil {
|
||||
m[domain] = &recordSet{}
|
||||
}
|
||||
rs := m[domain]
|
||||
if isV4 {
|
||||
rs.A = append(rs.A, ip)
|
||||
} else {
|
||||
rs.AAAA = append(rs.AAAA, ip)
|
||||
}
|
||||
|
||||
// Add PTR record for non-wildcard domains
|
||||
if !isWildcard {
|
||||
s.ptrRecords[ip.String()] = domain
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -113,61 +112,88 @@ func (s *DNSRecordStore) RemoveRecord(domain string, ip net.IP) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// Ensure domain ends with a dot (FQDN format)
|
||||
if len(domain) == 0 || domain[len(domain)-1] != '.' {
|
||||
domain = domain + "."
|
||||
}
|
||||
|
||||
// Normalize domain to lowercase FQDN
|
||||
domain = strings.ToLower(dns.Fqdn(domain))
|
||||
|
||||
// Check if domain contains wildcards
|
||||
isWildcard := strings.ContainsAny(domain, "*?")
|
||||
|
||||
// Choose the appropriate map
|
||||
m := s.exact
|
||||
if isWildcard {
|
||||
m = s.wildcards
|
||||
}
|
||||
|
||||
rs := m[domain]
|
||||
if rs == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ip == nil {
|
||||
// Remove all records for this domain
|
||||
if !isWildcard {
|
||||
for _, ipAddr := range rs.A {
|
||||
if ptrDomain, exists := s.ptrRecords[ipAddr.String()]; exists && ptrDomain == domain {
|
||||
delete(s.ptrRecords, ipAddr.String())
|
||||
}
|
||||
}
|
||||
for _, ipAddr := range rs.AAAA {
|
||||
if isWildcard {
|
||||
delete(s.aWildcards, domain)
|
||||
delete(s.aaaaWildcards, domain)
|
||||
} else {
|
||||
// For non-wildcard domains, remove PTR records for all IPs
|
||||
if ips, ok := s.aRecords[domain]; ok {
|
||||
for _, ipAddr := range ips {
|
||||
// Only remove PTR if it points to this domain
|
||||
if ptrDomain, exists := s.ptrRecords[ipAddr.String()]; exists && ptrDomain == domain {
|
||||
delete(s.ptrRecords, ipAddr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
delete(m, domain)
|
||||
if ips, ok := s.aaaaRecords[domain]; ok {
|
||||
for _, ipAddr := range ips {
|
||||
// Only remove PTR if it points to this domain
|
||||
if ptrDomain, exists := s.ptrRecords[ipAddr.String()]; exists && ptrDomain == domain {
|
||||
delete(s.ptrRecords, ipAddr.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
delete(s.aRecords, domain)
|
||||
delete(s.aaaaRecords, domain)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Remove specific IP
|
||||
if ip.To4() != nil {
|
||||
rs.A = removeIP(rs.A, ip)
|
||||
if !isWildcard {
|
||||
if ptrDomain, exists := s.ptrRecords[ip.String()]; exists && ptrDomain == domain {
|
||||
delete(s.ptrRecords, ip.String())
|
||||
// Remove specific IPv4 address
|
||||
if isWildcard {
|
||||
if ips, ok := s.aWildcards[domain]; ok {
|
||||
s.aWildcards[domain] = removeIP(ips, ip)
|
||||
if len(s.aWildcards[domain]) == 0 {
|
||||
delete(s.aWildcards, domain)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rs.AAAA = removeIP(rs.AAAA, ip)
|
||||
if !isWildcard {
|
||||
if ips, ok := s.aRecords[domain]; ok {
|
||||
s.aRecords[domain] = removeIP(ips, ip)
|
||||
if len(s.aRecords[domain]) == 0 {
|
||||
delete(s.aRecords, domain)
|
||||
}
|
||||
// Automatically remove PTR record if it points to this domain
|
||||
if ptrDomain, exists := s.ptrRecords[ip.String()]; exists && ptrDomain == domain {
|
||||
delete(s.ptrRecords, ip.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ip.To16() != nil {
|
||||
// Remove specific IPv6 address
|
||||
if isWildcard {
|
||||
if ips, ok := s.aaaaWildcards[domain]; ok {
|
||||
s.aaaaWildcards[domain] = removeIP(ips, ip)
|
||||
if len(s.aaaaWildcards[domain]) == 0 {
|
||||
delete(s.aaaaWildcards, domain)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ips, ok := s.aaaaRecords[domain]; ok {
|
||||
s.aaaaRecords[domain] = removeIP(ips, ip)
|
||||
if len(s.aaaaRecords[domain]) == 0 {
|
||||
delete(s.aaaaRecords, domain)
|
||||
}
|
||||
// Automatically remove PTR record if it points to this domain
|
||||
if ptrDomain, exists := s.ptrRecords[ip.String()]; exists && ptrDomain == domain {
|
||||
delete(s.ptrRecords, ip.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up empty record sets
|
||||
if len(rs.A) == 0 && len(rs.AAAA) == 0 {
|
||||
delete(m, domain)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,56 +205,61 @@ func (s *DNSRecordStore) RemovePTRRecord(ip net.IP) {
|
||||
delete(s.ptrRecords, ip.String())
|
||||
}
|
||||
|
||||
// GetRecords returns all IP addresses for a domain and record type.
|
||||
// The second return value indicates whether the domain exists at all
|
||||
// (true = domain exists, use NODATA if no records; false = NXDOMAIN).
|
||||
func (s *DNSRecordStore) GetRecords(domain string, recordType RecordType) ([]net.IP, bool) {
|
||||
// GetRecords returns all IP addresses for a domain and record type
|
||||
// First checks for exact matches, then checks wildcard patterns
|
||||
func (s *DNSRecordStore) GetRecords(domain string, recordType RecordType) []net.IP {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
// Normalize domain to lowercase FQDN
|
||||
domain = strings.ToLower(dns.Fqdn(domain))
|
||||
|
||||
// Check exact match first
|
||||
if rs, exists := s.exact[domain]; exists {
|
||||
var ips []net.IP
|
||||
if recordType == RecordTypeA {
|
||||
ips = rs.A
|
||||
} else {
|
||||
ips = rs.AAAA
|
||||
}
|
||||
if len(ips) > 0 {
|
||||
out := make([]net.IP, len(ips))
|
||||
copy(out, ips)
|
||||
return out, true
|
||||
}
|
||||
// Domain exists but no records of this type
|
||||
return nil, true
|
||||
}
|
||||
|
||||
// Check wildcard matches
|
||||
var records []net.IP
|
||||
matched := false
|
||||
for pattern, rs := range s.wildcards {
|
||||
if !matchWildcard(pattern, domain) {
|
||||
continue
|
||||
switch recordType {
|
||||
case RecordTypeA:
|
||||
// Check exact match first
|
||||
if ips, ok := s.aRecords[domain]; ok {
|
||||
// Return a copy to prevent external modifications
|
||||
records = make([]net.IP, len(ips))
|
||||
copy(records, ips)
|
||||
return records
|
||||
}
|
||||
matched = true
|
||||
if recordType == RecordTypeA {
|
||||
records = append(records, rs.A...)
|
||||
} else {
|
||||
records = append(records, rs.AAAA...)
|
||||
// Check wildcard patterns
|
||||
for pattern, ips := range s.aWildcards {
|
||||
if matchWildcard(pattern, domain) {
|
||||
records = append(records, ips...)
|
||||
}
|
||||
}
|
||||
if len(records) > 0 {
|
||||
// Return a copy
|
||||
result := make([]net.IP, len(records))
|
||||
copy(result, records)
|
||||
return result
|
||||
}
|
||||
|
||||
case RecordTypeAAAA:
|
||||
// Check exact match first
|
||||
if ips, ok := s.aaaaRecords[domain]; ok {
|
||||
// Return a copy to prevent external modifications
|
||||
records = make([]net.IP, len(ips))
|
||||
copy(records, ips)
|
||||
return records
|
||||
}
|
||||
// Check wildcard patterns
|
||||
for pattern, ips := range s.aaaaWildcards {
|
||||
if matchWildcard(pattern, domain) {
|
||||
records = append(records, ips...)
|
||||
}
|
||||
}
|
||||
if len(records) > 0 {
|
||||
// Return a copy
|
||||
result := make([]net.IP, len(records))
|
||||
copy(result, records)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
return nil, false
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return nil, true
|
||||
}
|
||||
out := make([]net.IP, len(records))
|
||||
copy(out, records)
|
||||
return out, true
|
||||
return records
|
||||
}
|
||||
|
||||
// GetPTRRecord returns the domain name for a PTR record query
|
||||
@@ -257,30 +288,34 @@ func (s *DNSRecordStore) HasRecord(domain string, recordType RecordType) bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
// Normalize domain to lowercase FQDN
|
||||
domain = strings.ToLower(dns.Fqdn(domain))
|
||||
|
||||
switch recordType {
|
||||
case RecordTypeA:
|
||||
// Check exact match
|
||||
if rs, exists := s.exact[domain]; exists {
|
||||
if recordType == RecordTypeA && len(rs.A) > 0 {
|
||||
if _, ok := s.aRecords[domain]; ok {
|
||||
return true
|
||||
}
|
||||
if recordType == RecordTypeAAAA && len(rs.AAAA) > 0 {
|
||||
// Check wildcard patterns
|
||||
for pattern := range s.aWildcards {
|
||||
if matchWildcard(pattern, domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case RecordTypeAAAA:
|
||||
// Check exact match
|
||||
if _, ok := s.aaaaRecords[domain]; ok {
|
||||
return true
|
||||
}
|
||||
// Check wildcard patterns
|
||||
for pattern := range s.aaaaWildcards {
|
||||
if matchWildcard(pattern, domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check wildcard matches
|
||||
for pattern, rs := range s.wildcards {
|
||||
if !matchWildcard(pattern, domain) {
|
||||
continue
|
||||
}
|
||||
if recordType == RecordTypeA && len(rs.A) > 0 {
|
||||
return true
|
||||
}
|
||||
if recordType == RecordTypeAAAA && len(rs.AAAA) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -304,8 +339,10 @@ func (s *DNSRecordStore) Clear() {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.exact = make(map[string]*recordSet)
|
||||
s.wildcards = make(map[string]*recordSet)
|
||||
s.aRecords = make(map[string][]net.IP)
|
||||
s.aaaaRecords = make(map[string][]net.IP)
|
||||
s.aWildcards = make(map[string][]net.IP)
|
||||
s.aaaaWildcards = make(map[string][]net.IP)
|
||||
s.ptrRecords = make(map[string]string)
|
||||
}
|
||||
|
||||
|
||||
@@ -183,34 +183,25 @@ func TestDNSRecordStoreWildcard(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test exact match takes precedence
|
||||
ips, exists := store.GetRecords("exact.autoco.internal.", RecordTypeA)
|
||||
if !exists {
|
||||
t.Error("Expected domain to exist")
|
||||
}
|
||||
ips := store.GetRecords("exact.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IP for exact match, got %d", len(ips))
|
||||
}
|
||||
if len(ips) > 0 && !ips[0].Equal(exactIP) {
|
||||
if !ips[0].Equal(exactIP) {
|
||||
t.Errorf("Expected exact IP %v, got %v", exactIP, ips[0])
|
||||
}
|
||||
|
||||
// Test wildcard match
|
||||
ips, exists = store.GetRecords("host.autoco.internal.", RecordTypeA)
|
||||
if !exists {
|
||||
t.Error("Expected wildcard match to exist")
|
||||
}
|
||||
ips = store.GetRecords("host.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IP for wildcard match, got %d", len(ips))
|
||||
}
|
||||
if len(ips) > 0 && !ips[0].Equal(wildcardIP) {
|
||||
if !ips[0].Equal(wildcardIP) {
|
||||
t.Errorf("Expected wildcard IP %v, got %v", wildcardIP, ips[0])
|
||||
}
|
||||
|
||||
// Test non-match (base domain)
|
||||
ips, exists = store.GetRecords("autoco.internal.", RecordTypeA)
|
||||
if exists {
|
||||
t.Error("Expected base domain to not exist")
|
||||
}
|
||||
ips = store.GetRecords("autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 0 {
|
||||
t.Errorf("Expected 0 IPs for base domain, got %d", len(ips))
|
||||
}
|
||||
@@ -227,10 +218,7 @@ func TestDNSRecordStoreComplexWildcard(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test matching domain
|
||||
ips, exists := store.GetRecords("sub.host-01.autoco.internal.", RecordTypeA)
|
||||
if !exists {
|
||||
t.Error("Expected complex wildcard match to exist")
|
||||
}
|
||||
ips := store.GetRecords("sub.host-01.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IP for complex wildcard match, got %d", len(ips))
|
||||
}
|
||||
@@ -239,19 +227,13 @@ func TestDNSRecordStoreComplexWildcard(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test non-matching domain (missing prefix)
|
||||
ips, exists = store.GetRecords("host-01.autoco.internal.", RecordTypeA)
|
||||
if exists {
|
||||
t.Error("Expected domain without prefix to not exist")
|
||||
}
|
||||
ips = store.GetRecords("host-01.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 0 {
|
||||
t.Errorf("Expected 0 IPs for domain without prefix, got %d", len(ips))
|
||||
}
|
||||
|
||||
// Test non-matching domain (wrong ? position)
|
||||
ips, exists = store.GetRecords("sub.host-012.autoco.internal.", RecordTypeA)
|
||||
if exists {
|
||||
t.Error("Expected domain with wrong ? match to not exist")
|
||||
}
|
||||
ips = store.GetRecords("sub.host-012.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 0 {
|
||||
t.Errorf("Expected 0 IPs for domain with wrong ? match, got %d", len(ips))
|
||||
}
|
||||
@@ -268,10 +250,7 @@ func TestDNSRecordStoreRemoveWildcard(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify it exists
|
||||
ips, exists := store.GetRecords("host.autoco.internal.", RecordTypeA)
|
||||
if !exists {
|
||||
t.Error("Expected domain to exist before removal")
|
||||
}
|
||||
ips := store.GetRecords("host.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IP before removal, got %d", len(ips))
|
||||
}
|
||||
@@ -280,10 +259,7 @@ func TestDNSRecordStoreRemoveWildcard(t *testing.T) {
|
||||
store.RemoveRecord("*.autoco.internal", nil)
|
||||
|
||||
// Verify it's gone
|
||||
ips, exists = store.GetRecords("host.autoco.internal.", RecordTypeA)
|
||||
if exists {
|
||||
t.Error("Expected domain to not exist after removal")
|
||||
}
|
||||
ips = store.GetRecords("host.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 0 {
|
||||
t.Errorf("Expected 0 IPs after removal, got %d", len(ips))
|
||||
}
|
||||
@@ -314,19 +290,19 @@ func TestDNSRecordStoreMultipleWildcards(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test domain matching only the prod pattern and the broad pattern
|
||||
ips, _ := store.GetRecords("host.prod.autoco.internal.", RecordTypeA)
|
||||
ips := store.GetRecords("host.prod.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 2 {
|
||||
t.Errorf("Expected 2 IPs (prod + broad), got %d", len(ips))
|
||||
}
|
||||
|
||||
// Test domain matching only the dev pattern and the broad pattern
|
||||
ips, _ = store.GetRecords("service.dev.autoco.internal.", RecordTypeA)
|
||||
ips = store.GetRecords("service.dev.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 2 {
|
||||
t.Errorf("Expected 2 IPs (dev + broad), got %d", len(ips))
|
||||
}
|
||||
|
||||
// Test domain matching only the broad pattern
|
||||
ips, _ = store.GetRecords("host.test.autoco.internal.", RecordTypeA)
|
||||
ips = store.GetRecords("host.test.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IP (broad only), got %d", len(ips))
|
||||
}
|
||||
@@ -343,7 +319,7 @@ func TestDNSRecordStoreIPv6Wildcard(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test wildcard match for IPv6
|
||||
ips, _ := store.GetRecords("host.autoco.internal.", RecordTypeAAAA)
|
||||
ips := store.GetRecords("host.autoco.internal.", RecordTypeAAAA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IPv6 for wildcard match, got %d", len(ips))
|
||||
}
|
||||
@@ -392,7 +368,7 @@ func TestDNSRecordStoreCaseInsensitive(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, domain := range testCases {
|
||||
ips, _ := store.GetRecords(domain, RecordTypeA)
|
||||
ips := store.GetRecords(domain, RecordTypeA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IP for domain %q, got %d", domain, len(ips))
|
||||
}
|
||||
@@ -416,7 +392,7 @@ func TestDNSRecordStoreCaseInsensitive(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, domain := range wildcardTestCases {
|
||||
ips, _ := store.GetRecords(domain, RecordTypeA)
|
||||
ips := store.GetRecords(domain, RecordTypeA)
|
||||
if len(ips) != 1 {
|
||||
t.Errorf("Expected 1 IP for wildcard domain %q, got %d", domain, len(ips))
|
||||
}
|
||||
@@ -427,7 +403,7 @@ func TestDNSRecordStoreCaseInsensitive(t *testing.T) {
|
||||
|
||||
// Test removal with different case
|
||||
store.RemoveRecord("MYHOST.AUTOCO.INTERNAL", nil)
|
||||
ips, _ := store.GetRecords("myhost.autoco.internal.", RecordTypeA)
|
||||
ips := store.GetRecords("myhost.autoco.internal.", RecordTypeA)
|
||||
if len(ips) != 0 {
|
||||
t.Errorf("Expected 0 IPs after removal, got %d", len(ips))
|
||||
}
|
||||
@@ -776,7 +752,7 @@ func TestAutomaticPTRRecordOnRemove(t *testing.T) {
|
||||
}
|
||||
|
||||
// Verify A record is also gone
|
||||
ips, _ := store.GetRecords(domain, RecordTypeA)
|
||||
ips := store.GetRecords(domain, RecordTypeA)
|
||||
if len(ips) != 0 {
|
||||
t.Errorf("Expected A record to be removed, got %d records", len(ips))
|
||||
}
|
||||
|
||||
2
olm.iss
2
olm.iss
@@ -32,7 +32,7 @@ DefaultGroupName={#MyAppName}
|
||||
DisableProgramGroupPage=yes
|
||||
; Uncomment the following line to run in non administrative install mode (install for current user only).
|
||||
;PrivilegesRequired=lowest
|
||||
OutputBaseFilename=olm_windows_installer
|
||||
OutputBaseFilename=mysetup
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
; Add this to ensure PATH changes are applied and the system is prompted for a restart if needed
|
||||
|
||||
@@ -172,12 +172,6 @@ func (o *Olm) handleConnect(msg websocket.WSMessage) {
|
||||
|
||||
for i := range wgData.Sites {
|
||||
site := wgData.Sites[i]
|
||||
|
||||
if site.PublicKey == "" {
|
||||
logger.Warn("Skipping site %d (%s): no public key available (site may not be connected)", site.SiteId, site.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
var siteEndpoint string
|
||||
// here we are going to take the relay endpoint if it exists which means we requested a relay for this peer
|
||||
if site.RelayEndpoint != "" {
|
||||
|
||||
@@ -37,11 +37,6 @@ func (o *Olm) handleWgPeerAdd(msg websocket.WSMessage) {
|
||||
return
|
||||
}
|
||||
|
||||
if siteConfig.PublicKey == "" {
|
||||
logger.Warn("Skipping add-peer for site %d (%s): no public key available (site may not be connected)", siteConfig.SiteId, siteConfig.Name)
|
||||
return
|
||||
}
|
||||
|
||||
_ = o.holePunchManager.TriggerHolePunch() // Trigger immediate hole punch attempt so that if the peer decides to relay we have already punched close to when we need it
|
||||
|
||||
if err := o.peerManager.AddPeer(siteConfig); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user