Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/systemd query events #1728

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open

Conversation

vlabo
Copy link
Member

@vlabo vlabo commented Nov 5, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a DNS listener to enhance DNS query handling and management.
    • Added functionality to manage resolver states, allowing the system to recognize when the Portmaster resolver is disabled.
  • Bug Fixes

    • Improved error handling for resolver configurations and invalid parameters.
  • Enhancements

    • Updated self-check logic to be responsive to network changes.
    • Enhanced DNS request management when the Portmaster resolver is disabled.
  • Documentation

    • Clarified comments throughout the codebase for better understanding of functionalities.

Copy link
Contributor

coderabbitai bot commented Nov 5, 2024

📝 Walkthrough

Walkthrough

The pull request introduces updates to the dependency management in the go.mod file, adding new direct dependencies and replacing an existing one. It also enhances the Compat module's self-check functionality by introducing a resolver check. The PreventBypassing function in the firewall package is modified to handle DNS requests more flexibly based on the resolver's status. New files are added to manage DNS listener functionality and define data structures for the systemd-resolver varlink DNS event protocol. The Instance struct is updated to incorporate the DNS listener capabilities, and the ResolverModule now tracks its disabled state.

Changes

File Change Summary
go.mod - Added dependencies: github.com/maruel/panicparse/v2 v2.3.1, github.com/varlink/go v0.4.0.
- Replaced github.com/tc-hib/winres with github.com/dhaavi/winres v0.2.2.
- Removed indirect dependency github.com/maruel/panicparse/v2 v2.3.1.
service/compat/module.go - Added Resolver() method to instance interface.
- Updated selfcheckTaskFunc to check if the resolver is disabled.
- Modified start() function to trigger self-check on network change.
service/firewall/bypassing.go - Modified PreventBypassing to allow requests if the Portmaster resolver is disabled.
service/firewall/interception/dnslistener/module.go - Introduced DNSListener struct with methods for managing DNS listener functionality.
service/firewall/interception/dnslistener/varlinktypes.go - Added data structures for the systemd-resolver varlink DNS event protocol.
service/firewall/module.go - Added Resolver() method to instance interface.
- Updated mgr field formatting.
service/firewall/packet_handler.go - Modified DNS redirection logic in filterHandler and refined fastTrackedPermit for specific protocols.
service/instance.go - Added dnslistener *dnslistener.DNSListener field to Instance struct.
- Introduced DNSListener() method.
service/resolver/main.go - Added IsDisabled field to ResolverModule struct.
- Updated New function to initialize IsDisabled.
service/resolver/resolvers.go - Added logic in loadResolvers to set the module's disabled state if no resolvers are configured.

Possibly related PRs

  • Fix starting/stopping SPN + more #1668: This PR includes an update to the go.mod file where the dependency github.com/maruel/panicparse/v2 v2.3.1 is added, which is directly related to the changes in the main PR that also adds this dependency.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Outside diff range and nitpick comments (15)
service/firewall/bypassing.go (2)

49-49: Consider strengthening the system resolver check.

The TODO comment suggests uncertainty about the specificity of the check. Consider adding additional validation such as verifying the process path or using a more comprehensive identification method.


46-56: Document the resolver disabled behavior.

Given that this introduces significant new behavior when the resolver is disabled, consider adding a function-level comment explaining:

  • When and why the resolver might be disabled
  • Security implications of the disabled state
  • Interaction with systemd-resolver
service/firewall/interception/dnslistener/varlinktypes.go (3)

1-4: Enhance package documentation.

Consider adding more detailed documentation about:

  • The varlink protocol and its role in systemd-resolver
  • The relationship between these types and the DNS event handling
  • Any relevant systemd-resolver documentation references
 package dnslistener

-// List of struct that define the systemd-resolver varlink dns event protocol.
+// Package dnslistener provides types for interacting with systemd-resolver's varlink DNS event protocol.
+// These types facilitate the communication between the application and systemd-resolver for DNS query events.
+//
+// For more information about the protocol, see:
+// https://www.freedesktop.org/software/systemd/man/org.freedesktop.resolve1.html

5-9: Add field documentation and consider using DNS-specific types.

The struct would benefit from:

  1. Documentation explaining the purpose of each field
  2. Using DNS-specific constants for Class and Type fields
+// ResourceKey represents a unique identifier for a DNS resource record.
 type ResourceKey struct {
+	// Class represents the DNS class (e.g., IN for Internet)
 	Class int    `json:"class"`
+	// Type represents the DNS record type (e.g., A, AAAA, MX)
 	Type  int    `json:"type"`
+	// Name is the domain name for this resource
 	Name  string `json:"name"`
 }

Consider defining constants for common DNS classes and types:

// DNS Classes
const (
    ClassIN    = 1 // Internet
    ClassCS    = 2 // CSNET
    ClassCH    = 3 // CHAOS
    ClassHS    = 4 // Hesiod
)

// DNS Types
const (
    TypeA     = 1  // IPv4 address
    TypeNS    = 2  // Nameserver
    TypeCNAME = 5  // Canonical name
    TypeSOA   = 6  // Start of authority
    TypePTR   = 12 // Pointer
    TypeMX    = 15 // Mail exchange
    TypeTXT   = 16 // Text
    TypeAAAA  = 28 // IPv6 address
)

65-69: Add struct and field documentation.

The struct would benefit from clear documentation explaining its purpose and the significance of each field.

+// Answer represents a DNS response containing either a parsed resource record
+// or the raw DNS response data.
 type Answer struct {
+	// RR is the parsed DNS resource record, if available
 	RR      *ResourceRecord `json:"rr,omitempty"`
+	// Raw contains the unparsed DNS response string
 	Raw     string          `json:"raw"`
+	// IfIndex is the network interface index where this answer was received
 	IfIndex *int            `json:"ifindex,omitempty"`
 }
service/compat/module.go (2)

102-106: Consider standardizing skip handling with errSelfcheckSkipped.

The early return for disabled resolver is logically sound, but for consistency with other skip conditions (like the one handled by errSelfcheckSkipped), consider using the same error pattern.

 res := module.instance.Resolver()
 if res.IsDisabled.IsSet() {
-    log.Debugf("compat: skipping self-check: resolver is disabled")
-    return nil
+    return nil, fmt.Errorf("%w: resolver is disabled", errSelfcheckSkipped)
 }

192-192: LGTM! Consider documenting interface changes.

The new Resolver() method is a good addition for accessing resolver state. Consider adding interface documentation to explain the contract, especially regarding initialization guarantees and thread safety requirements.

go.mod (1)

Line range hint 5-6: Track temporary winres dependency replacement.

The TODO comment indicates this is a temporary fix waiting for upstream PR #4. Consider:

  1. Adding a GitHub issue to track the removal of this replacement
  2. Adding a link to the upstream PR for better context

Would you like me to create a GitHub issue to track this?

service/resolver/main.go (2)

32-33: Add documentation for the exported field.

Since IsDisabled is an exported field that other packages may use, please add a documentation comment explaining its purpose, when it's set, and how it should be used.

+// IsDisabled indicates whether the resolver module is currently disabled.
+// This is typically set when no resolvers are configured.
 IsDisabled abool.AtomicBool

32-33: Consider reflecting the disabled state in the state manager.

The module uses mgr.StateMgr for state management, but the new IsDisabled state is not reflected there. Consider adding the disabled state to the state manager to maintain consistency and enable proper monitoring.

This could be done in the loadResolvers function (where IsDisabled is set) by adding:

if module.IsDisabled.IsSet() {
    module.states.Add("resolver:disabled", "The resolver module is currently disabled as no resolvers are configured")
} else {
    module.states.Remove("resolver:disabled")
}

Also applies to: 272-274

service/instance.go (2)

192-195: Fix error message for consistency

The error message uses "dns-listener" with a hyphen, while other module names in error messages don't use hyphens. Consider changing for consistency:

-		return instance, fmt.Errorf("create dns-listener module: %w", err)
+		return instance, fmt.Errorf("create dnslistener module: %w", err)

473-476: Fix comment style for consistency

The comment uses "dns-listener" with a hyphen, while other module names in comments don't use hyphens. Consider changing for consistency:

-// DNSListener returns the dns-listener module.
+// DNSListener returns the dnslistener module.
service/firewall/packet_handler.go (1)

Line range hint 447-459: Security review of DNS redirection logic.

The implementation maintains robust security controls while adding flexibility:

  1. Multiple validation layers (resolver status, nameserver IP, port checks)
  2. Special handling for broadcast queries
  3. Proper separation between system and user DNS queries

Consider adding debug logging when DNS redirection is skipped due to disabled resolver to aid in troubleshooting.

Add debug logging:

 case dnsQueryInterception() &&
   module.instance.Resolver().IsDisabled.IsNotSet() &&
   pkt.IsOutbound() &&
+  // Log when redirection is skipped due to disabled resolver
+  func() bool {
+    if module.instance.Resolver().IsDisabled.IsSet() {
+      log.Tracer(pkt.Ctx()).Debugf("filter: skipping DNS redirection, resolver is disabled: %s", pkt)
+    }
+    return true
+  }() &&
   pkt.Info().DstPort == 53 &&
service/firewall/interception/dnslistener/module.go (2)

9-14: Organize imports according to gci recommendations

The imports are not properly organized as indicated by the gci static analysis tool. Consider running gci with --skip-generated -s standard -s default to sort and group imports according to Go standards.

🧰 Tools
🪛 GitHub Check: Linter

[failure] 9-9:
File is not gci-ed with --skip-generated -s standard -s default (gci)


[failure] 14-14:
File is not gci-ed with --skip-generated -s standard -s default (gci)


144-146: Handle error from info.Save() appropriately

Currently, when info.Save() returns an error, it is logged but not returned or handled further. Consider whether this error should be propagated or if additional error handling is necessary.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 145f5e6 and 811a3d9.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (10)
  • go.mod (2 hunks)
  • service/compat/module.go (3 hunks)
  • service/firewall/bypassing.go (1 hunks)
  • service/firewall/interception/dnslistener/module.go (1 hunks)
  • service/firewall/interception/dnslistener/varlinktypes.go (1 hunks)
  • service/firewall/module.go (3 hunks)
  • service/firewall/packet_handler.go (1 hunks)
  • service/instance.go (5 hunks)
  • service/resolver/main.go (2 hunks)
  • service/resolver/resolvers.go (2 hunks)
🧰 Additional context used
🪛 GitHub Check: Linter
service/firewall/interception/dnslistener/module.go

[failure] 9-9:
File is not gci-ed with --skip-generated -s standard -s default (gci)


[failure] 14-14:
File is not gci-ed with --skip-generated -s standard -s default (gci)


[failure] 48-48:
type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)


[failure] 51-51:
non-wrapping format verb for fmt.Errorf. Use %w to format errors (errorlint)


[failure] 60-60:
type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)


[failure] 63-63:
non-wrapping format verb for fmt.Errorf. Use %w to format errors (errorlint)

🔇 Additional comments (13)
service/firewall/bypassing.go (2)

46-56: Verify interaction with secure DNS bypass reporting.

The new exceptions for disabled resolver state are placed before the secure DNS filter list checks. This means connections that would normally trigger secure DNS bypass reporting might be allowed when the resolver is disabled.

Let's check the interaction:

#!/bin/bash
# Description: Verify how secure DNS bypass reporting works with disabled resolver

# Test: Check for any conditions or checks around secure DNS bypass reporting
rg "ReportSecureDNSBypassIssue"

46-56: Verify security implications of bypass exceptions.

The new conditional block creates exceptions to bypass prevention when the Portmaster resolver is disabled. While the intent is clear, we should ensure these exceptions don't create security vulnerabilities.

Let's verify the impact and usage:

✅ Verification successful

The bypass exceptions are properly implemented with adequate security measures

The verification reveals that the bypass exceptions are well-integrated into the system's security architecture:

  1. The system has comprehensive DNS bypass prevention:

    • Bypass attempts trigger security notifications via ReportSecureDNSBypassIssue
    • There's a global setting Block Secure DNS Bypassing that's enabled by default
    • The firewall maintains protection even when bypassing is attempted
  2. The localhost and system resolver exceptions are specifically handled:

    • System resolver checks are consistently implemented across the codebase
    • Localhost scope checks are used in multiple security contexts with proper validation
    • The exceptions only apply when the Portmaster resolver is explicitly disabled
  3. The conditional block maintains security by:

    • Only allowing necessary traffic when the resolver is disabled
    • Properly identifying system resolver processes
    • Limiting localhost exceptions to DNS port 53
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other security measures or validations when resolver is disabled

# Test 1: Check for any additional security checks or validations when resolver is disabled
rg -A 5 "IsDisabled.IsSet\(\)" 

# Test 2: Check how localhost connections are handled elsewhere
rg -A 5 "IsLocalhost\(\)"

Length of output: 400


Script:

#!/bin/bash
# Let's try a more comprehensive verification approach

# Check for IsDisabled usage with proper quoting
rg -A 5 "IsDisabled\.IsSet"

# Check how localhost connections are validated
rg -A 5 "IsLocalhost"

# Check for system resolver related checks
rg -A 5 "IsSystemResolver"

# Check for other DNS bypass prevention mechanisms
rg -A 5 "DNS.*bypass" -i

# Look for related security validations
rg -A 5 "ReportSecureDNSBypassIssue"

Length of output: 13343

service/firewall/interception/dnslistener/varlinktypes.go (1)

71-79: Add documentation and validate pointer usage.

The struct needs documentation, and some fields might not need to be pointers.

+// QueryResult represents the complete result of a DNS query from systemd-resolver,
+// including the query state, any errors, and the received answers.
 type QueryResult struct {
+	// Ready indicates if the query has completed
 	Ready              *bool          `json:"ready,omitempty"`
+	// State describes the current state of the query
 	State              *string        `json:"state,omitempty"`
+	// Rcode is the DNS response code
 	Rcode              *int           `json:"rcode,omitempty"`
+	// Errno is the system error number, if any
 	Errno              *int           `json:"errno,omitempty"`
+	// Question contains the original DNS query
 	Question           *[]ResourceKey `json:"question,omitempty"`
+	// CollectedQuestions contains additional related queries
 	CollectedQuestions *[]ResourceKey `json:"collectedQuestions,omitempty"`
+	// Answer contains the DNS responses
 	Answer             *[]Answer      `json:"answer,omitempty"`
 }

Consider whether some fields really need to be pointers. For example:

  • Ready could be a non-pointer bool with a default value of false
  • State could be an enum type instead of a string pointer
  • Rcode and Errno could be non-pointer integers with sentinel values (-1) for "not set"
service/firewall/module.go (1)

19-19: LGTM: Clean integration of resolver module access.

The addition of the resolver module access follows the established pattern of module getter methods in the interface. This change maintains consistency with the existing architecture.

Let's verify that all implementations of the instance interface have been updated:

Also applies to: 168-168

✅ Verification successful

Let me gather more information to verify the interface implementation comprehensively.


LGTM: The resolver module integration is properly implemented.

The verification confirms that:

  • The Instance struct is the only implementation of the instance interface
  • The Instance struct has both the required field resolver *resolver.ResolverModule and the method Resolver() *resolver.ResolverModule
  • All interface methods are implemented by the Instance struct
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all potential implementations of the instance interface
# to ensure they've been updated with the new Resolver() method.

# Search for struct types that might implement the interface
ast-grep --pattern 'type $name struct {
  $$$
}'

# Search for interface method implementations
rg -A 1 'func \([^)]+\) Resolver\(\)'

Length of output: 206


Script:

#!/bin/bash
# First, let's find the interface definition to understand all required methods
rg -A 10 "type instance interface" service/firewall/module.go

# Then find all structs that could implement this interface
rg "type.*struct" service/instance.go

# Finally, check if Instance is the only implementation
fd -e go | xargs rg "type.*struct.*{" 

Length of output: 496


Script:

#!/bin/bash
# Let's fix the regex and search for struct implementations
fd -e go | xargs rg "type.*struct"

# Also check if Instance implements all interface methods
rg "func \(i \*Instance\)" service/instance.go

# And verify the resolver field exists in Instance
rg "resolver.*\*resolver\.ResolverModule" service/instance.go

Length of output: 40121

service/compat/module.go (1)

127-128: ⚠️ Potential issue

Potential race condition in resolver state handling.

The early return (lines 102-106) should prevent execution from reaching this point when the resolver is disabled. The fact that we're checking again suggests the resolver state could change during self-check execution. Consider:

  1. Adding atomic operations or proper synchronization
  2. Removing this redundant check
  3. Adding a comment explaining why both checks are necessary

Let's verify if the resolver state can change during execution:

go.mod (2)

37-37: Document new dependency purposes.

Two new direct dependencies have been added:

  1. github.com/maruel/panicparse/v2: Consider documenting why this debugging tool is needed
  2. github.com/varlink/go: Required for systemd-resolver DNS event protocol integration
#!/bin/bash
# Check for usage of new dependencies in codebase
echo "Checking panicparse usage..."
rg "panicparse" --type go

echo "Checking varlink usage..."
rg "varlink" --type go

Consider adding comments in the code or documentation explaining the purpose of these dependencies.

Also applies to: 61-61


Line range hint 3-3: Verify Go 1.22.0 compatibility requirements.

Go 1.22.0 is a very recent version (released Feb 2024). Please ensure all deployment environments and CI/CD pipelines support this version.

service/instance.go (4)

22-22: LGTM!

The import is correctly placed and follows the project's import grouping convention.


78-78: LGTM!

The dnslistener field is correctly placed and follows the established pattern for module fields.


297-297: LGTM!

The dnslistener module is correctly registered in the service group, maintaining the logical grouping with other interception-related modules.


78-78: Verify SleepyModule interface implementation

Since this is a new module in the service group, verify if it needs to implement the SleepyModule interface like other modules. This interface is used by the SetSleep method to manage module sleep states.

Also applies to: 192-195, 297-297, 473-476

service/resolver/resolvers.go (1)

401-408: 🛠️ Refactor suggestion

Consider moving the disabled state management after resolver validation.

The current implementation sets the module's disabled state before validating resolvers and potentially loading defaults. This could lead to incorrect state representation if:

  1. The configured resolvers are invalid and defaults are loaded
  2. Other modules check the disabled state while resolvers are being loaded

Consider moving this block after the resolver validation and default loading (after line 440) to ensure the state accurately reflects the final resolver configuration:

-	// If no resolvers are configure set the disabled state. So other modules knows that the users does not want to use Portmaster resolver.
-	if len(newResolverConfig) == 0 {
-		module.IsDisabled.Set()
-	} else {
-		module.IsDisabled.UnSet()
-	}

 	currentResolverConfig = newResolverConfig

 	newResolvers := append(
 		getConfiguredResolvers(newResolverConfig),
 		getSystemResolvers()...,
 	)

 	if len(newResolvers) == 0 {
 		// load defaults directly, overriding config system
 		newResolvers = getConfiguredResolvers(defaultNameServers)
 		...
 	}
+
+	// Set the disabled state after resolver validation and default loading
+	if len(newResolvers) == 0 {
+		module.IsDisabled.Set()
+	} else {
+		module.IsDisabled.UnSet()
+	}

Let's verify the impact of this state management on other modules:

service/firewall/packet_handler.go (1)

447-449: LGTM! Verify DNS redirection behavior.

The additional check for resolver status is correctly implemented, ensuring DNS queries are only redirected when the resolver is enabled.

Let's verify the resolver status handling:

✅ Verification successful

Let me gather more information about the DNS redirection logic to ensure a comprehensive verification.


DNS redirection logic is correctly implemented with resolver status check

The verification confirms that:

  1. The resolver status check IsDisabled.IsNotSet() is consistently used across the codebase for DNS handling
  2. The DNS redirection logic is properly integrated with the resolver status:
    • In packet handling (service/firewall/packet_handler.go)
    • In bypassing logic (service/firewall/bypassing.go)
    • In compatibility checks (service/compat/module.go)
  3. The implementation correctly ensures DNS queries are only redirected when:
    • The resolver is enabled (IsDisabled.IsNotSet())
    • The packet is outbound
    • The destination port is 53
    • The destination is not our nameserver
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent resolver status handling across the codebase

# Test: Search for other DNS redirection logic that might need similar checks
rg -A 5 "DstPort == 53" 

# Test: Search for other resolver status checks to ensure consistent patterns
ast-grep --pattern 'Resolver().IsDisabled'

Length of output: 895


Script:

#!/bin/bash
# Search for DNS query interception function and its usage
ast-grep --pattern 'dnsQueryInterception()'

# Search for resolver status checks in a broader context
rg -A 5 "IsDisabled" 

# Look for nameserver related functions to understand DNS handling
rg -A 5 "RerouteToNameserver"

Length of output: 11331

Comment on lines +11 to +63
type ResourceRecord struct {
Key ResourceKey `json:"key"`
Name *string `json:"name,omitempty"`
Address *[]byte `json:"address,omitempty"`
// Rest of the fields are not used.
// Priority *int `json:"priority,omitempty"`
// Weight *int `json:"weight,omitempty"`
// Port *int `json:"port,omitempty"`
// CPU *string `json:"cpu,omitempty"`
// OS *string `json:"os,omitempty"`
// Items *[]string `json:"items,omitempty"`
// MName *string `json:"mname,omitempty"`
// RName *string `json:"rname,omitempty"`
// Serial *int `json:"serial,omitempty"`
// Refresh *int `json:"refresh,omitempty"`
// Expire *int `json:"expire,omitempty"`
// Minimum *int `json:"minimum,omitempty"`
// Exchange *string `json:"exchange,omitempty"`
// Version *int `json:"version,omitempty"`
// Size *int `json:"size,omitempty"`
// HorizPre *int `json:"horiz_pre,omitempty"`
// VertPre *int `json:"vert_pre,omitempty"`
// Latitude *int `json:"latitude,omitempty"`
// Longitude *int `json:"longitude,omitempty"`
// Altitude *int `json:"altitude,omitempty"`
// KeyTag *int `json:"key_tag,omitempty"`
// Algorithm *int `json:"algorithm,omitempty"`
// DigestType *int `json:"digest_type,omitempty"`
// Digest *string `json:"digest,omitempty"`
// FPType *int `json:"fptype,omitempty"`
// Fingerprint *string `json:"fingerprint,omitempty"`
// Flags *int `json:"flags,omitempty"`
// Protocol *int `json:"protocol,omitempty"`
// DNSKey *string `json:"dnskey,omitempty"`
// Signer *string `json:"signer,omitempty"`
// TypeCovered *int `json:"type_covered,omitempty"`
// Labels *int `json:"labels,omitempty"`
// OriginalTTL *int `json:"original_ttl,omitempty"`
// Expiration *int `json:"expiration,omitempty"`
// Inception *int `json:"inception,omitempty"`
// Signature *string `json:"signature,omitempty"`
// NextDomain *string `json:"next_domain,omitempty"`
// Types *[]int `json:"types,omitempty"`
// Iterations *int `json:"iterations,omitempty"`
// Salt *string `json:"salt,omitempty"`
// Hash *string `json:"hash,omitempty"`
// CertUsage *int `json:"cert_usage,omitempty"`
// Selector *int `json:"selector,omitempty"`
// MatchingType *int `json:"matching_type,omitempty"`
// Data *string `json:"data,omitempty"`
// Tag *string `json:"tag,omitempty"`
// Value *string `json:"value,omitempty"`
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve documentation and consider separating unused fields.

The current approach of commenting out unused fields makes the code harder to maintain and understand.

Consider either:

  1. Moving unused fields to a separate file/type for future implementation
  2. Or documenting why these fields exist and when they might be needed
+// ResourceRecord represents a DNS resource record with its associated data.
+// Currently, only a subset of DNS record types are supported, focusing on
+// name resolution and addressing. Additional fields for other DNS record
+// types are planned for future implementation.
 type ResourceRecord struct {
 	Key     ResourceKey `json:"key"`
+	// Name is the canonical name for CNAME records
 	Name    *string     `json:"name,omitempty"`
+	// Address contains the IP address for A/AAAA records
 	Address *[]byte     `json:"address,omitempty"`
-	// Rest of the fields are not used.
-	// Priority     *int        `json:"priority,omitempty"`
-	// Weight       *int        `json:"weight,omitempty"`
-	// Port         *int        `json:"port,omitempty"`
-	// ... (other commented fields)
 }

Create a new file (e.g., future_types.go) for the unused fields:

// future_types.go

// FutureResourceRecord contains fields for additional DNS record types
// that may be implemented in the future.
type FutureResourceRecord struct {
    Priority     *int        `json:"priority,omitempty"`
    Weight       *int        `json:"weight,omitempty"`
    Port         *int        `json:"port,omitempty"`
    // ... (other fields)
}

Comment on lines +272 to +274
mgr: m,
instance: instance,
IsDisabled: *abool.New(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove unnecessary dereferencing of abool.New().

The abool.New() function returns a pointer to AtomicBool, but the field type is not a pointer. The dereferencing is unnecessary and could be error-prone.

-		IsDisabled: *abool.New(),
+		IsDisabled: abool.New(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mgr: m,
instance: instance,
IsDisabled: *abool.New(),
mgr: m,
instance: instance,
IsDisabled: abool.New(),

Comment on lines +39 to +41
if err != nil {
log.Errorf("dnslistener: failed to connect to systemd-resolver varlink service: %s", err)
return nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Return error instead of nil on connection failure

In the Start() method, when failing to establish a varlink connection, the error is logged but nil is returned. Consider returning the error to allow the caller to handle it appropriately.

Apply this diff to fix the issue:

if err != nil {
	log.Errorf("dnslistener: failed to connect to systemd-resolver varlink service: %s", err)
-	return nil
+	return err
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if err != nil {
log.Errorf("dnslistener: failed to connect to systemd-resolver varlink service: %s", err)
return nil
if err != nil {
log.Errorf("dnslistener: failed to connect to systemd-resolver varlink service: %s", err)
return err

if varlinkErr, ok := err.(*varlink.Error); ok {
return fmt.Errorf("failed to issue Varlink call: %+v", varlinkErr.Parameters)
} else {
return fmt.Errorf("failed to issue Varlink call: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Wrap errors using %w in fmt.Errorf

When returning errors with fmt.Errorf, use the %w verb to wrap the original error and maintain the error chain.

Apply this diff to refactor:

-return fmt.Errorf("failed to issue Varlink call: %v", err)
+return fmt.Errorf("failed to issue Varlink call: %w", err)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return fmt.Errorf("failed to issue Varlink call: %v", err)
return fmt.Errorf("failed to issue Varlink call: %w", err)
🧰 Tools
🪛 GitHub Check: Linter

[failure] 51-51:
non-wrapping format verb for fmt.Errorf. Use %w to format errors (errorlint)

if varlinkErr, ok := err.(*varlink.Error); ok {
return fmt.Errorf("failed to receive Varlink reply: %+v", varlinkErr.Parameters)
} else {
return fmt.Errorf("failed to receive Varlink reply: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Wrap errors using %w in fmt.Errorf

Again, use %w to wrap errors when returning them with fmt.Errorf.

Apply this diff to refactor:

-return fmt.Errorf("failed to receive Varlink reply: %v", err)
+return fmt.Errorf("failed to receive Varlink reply: %w", err)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return fmt.Errorf("failed to receive Varlink reply: %v", err)
return fmt.Errorf("failed to receive Varlink reply: %w", err)
🧰 Tools
🪛 GitHub Check: Linter

[failure] 63-63:
non-wrapping format verb for fmt.Errorf. Use %w to format errors (errorlint)

Comment on lines +60 to +63
if varlinkErr, ok := err.(*varlink.Error); ok {
return fmt.Errorf("failed to receive Varlink reply: %+v", varlinkErr.Parameters)
} else {
return fmt.Errorf("failed to receive Varlink reply: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use errors.As for error type assertions

Similar to the previous case, use errors.As to handle wrapped errors when checking for specific error types.

Apply this diff to fix the issue:

-if varlinkErr, ok := err.(*varlink.Error); ok {
+var varlinkErr *varlink.Error
+if errors.As(err, &varlinkErr) {

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Check: Linter

[failure] 60-60:
type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)


[failure] 63-63:
non-wrapping format verb for fmt.Errorf. Use %w to format errors (errorlint)

Comment on lines +48 to +51
if varlinkErr, ok := err.(*varlink.Error); ok {
return fmt.Errorf("failed to issue Varlink call: %+v", varlinkErr.Parameters)
} else {
return fmt.Errorf("failed to issue Varlink call: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use errors.As for error type assertions

Type assertions on errors may fail on wrapped errors. Use errors.As to check for specific error types, ensuring wrapped errors are properly handled.

Apply this diff to fix the issue:

-if varlinkErr, ok := err.(*varlink.Error); ok {
+var varlinkErr *varlink.Error
+if errors.As(err, &varlinkErr) {

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Check: Linter

[failure] 48-48:
type assertion on error will fail on wrapped errors. Use errors.As to check for specific errors (errorlint)


[failure] 51-51:
non-wrapping format verb for fmt.Errorf. Use %w to format errors (errorlint)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant