Skip to content

Conversation

@ekrekeler
Copy link

@ekrekeler ekrekeler commented Jun 22, 2025

📋 Overview

Provide a clear summary of the purpose and scope of this pull request:

  • What problem does this pull request address?

    • Adds additional transport methods and related options to the DNS monitor.
    • Changes the way DNS answers are evaluated to provide more granular control in the conditions logic.
  • What features or functionality does this pull request introduce or enhance?

    • Additional transport methods besides the standard UDP: DNS over TCP, DNS over TLS (DoT), and DNS over HTTPS (DoH).
    • Proper validation of text input in form fields for DNS monitor such as hostname, resolver server, and DoH query URL
    • Option to relax certificate validation for secure transport methods DoT and DoH.
    • Option to disable server-side DNSSEC validation. Before, node DNS client had DNSSEC support bit unset.
    • Options for DoH transport method to use GET or POST method, and send requests using HTTP/2.
    • Meaningful error handling for connection timeouts and bad responses, and other transport issues.
    • Record types A, AAAA, NS, and MX are evaluated as an array in conditions.
    • Record types CAA and SOA now support evaluating against rrtype-specific fields in conditions.

🔄 Changes

🛠️ Type of change

  • 🐛 Bugfix (a non-breaking change that resolves an issue)
  • ✨ New feature (a non-breaking change that adds new functionality)
  • ⚠️ Breaking change (a fix or feature that alters existing functionality in a way that could cause issues)
    • Conditions for DNS monitor are evaluated differently than before
  • 🎨 User Interface (UI) updates
  • 📄 New Documentation (addition of new documentation)
    • The only reason for new documentation is to inform users of best practices for configuring the various transport methods and condition variables. If this is needed, I can draft a PR for the wiki pages.
  • 📄 Documentation Update (modification of existing documentation)
  • 📄 Documentation Update Required (the change requires updates to related documentation)
  • 🔧 Other (please specify):

🔗 Related Issues

📄 Checklist *

  • 🔍 My code adheres to the style guidelines of this project.
  • ✅ I ran ESLint and other code linters for modified files.
  • 🛠️ I have reviewed and tested my code.
  • 📝 I have commented my code, especially in hard-to-understand areas (e.g., using JSDoc for methods).
  • ⚠️ My changes generate no new warnings.
  • 🤖 My code needed automated testing. I have added them (this is an optional task).
  • 📄 Documentation updates are included (if applicable).
  • 🔒 I have considered potential security impacts and mitigated risks.
  • 🧰 Dependency updates are listed and explained.
  • 📚 I have read and understood the Pull Request guidelines.

📷 Screenshots or Visual Changes

This is the EditMonitor page before changes
Before

This is the EditMonitor page after changes, with new components in red:
After

ℹ️ Additional Context

Provide any relevant details to assist reviewers in understanding the changes.

Click here for more details:

This PR is primarily intended to bring DNS over TLS and DNS over HTTPS support to the DNS monitor. I found some areas for improvement along the way that I will describe as best I can.

The built-in node dns resolver in server/util-server.js has been replaced with dgram, Socket, https, and http2 built-in node modules. I would have loved to bring in support for DNS over QUIC as well, but opted not to because there is no built-in node module for QUIC. I am using the external module dns-packet for encoding/decoding DNS packet data because it is very easy to manipulate packet-level data without needing to make adjustments for each transport type. I settled on it after finding its use in other projects including dohdec and tangerine. I'm also using ip-address for identifying and manipulating IP addresses.

The biggest changes besides the transport methods are the condition variables and logic. Excluding TXT, the RRTYPES that are expected to return more than one record are passed to the expression evaluator as an array. This allows for more meaningful and/or logic in conditions, but also requires to specify the full value of each record that should match. I did it this way because using Array.some() in the DNS monitor was conflicting with the evaluator's ability to correctly evaluate multiple conditions. For example, before if I configured a query for one.one.one.one for type A, and a condition for the records to contain values 1.1.1.1 and 1.0.0.1, it would always evaluate the condition to false no matter what the answers were. The solution I came up with was to pass the list of answers to the evaluator and let it decide if it contained the exact value (or not).

Due the reason for changes made in PR #5768, I configured the answers for TXT records to be passed to the evaluator as a pipe-separated string (txt_record_1|txt_record_2), so the string operators could still be used in this respect. The reason the TXT record answers needed to be flattened in the first place is because they use strings that have a 255 character limit (RFC 1035). In order to overcome this limitation on values longer than 255 characters, the value is split into 255-character length strings that are later reconstructed by the DNS client. There can be multiple TXT records for a DNS name, and each TXT record can have multiple strings associated to it. Flattening the answers will not match properly in conditions for records that exceed 255 characters and thus use multiple strings. In the code for this PR, I've made sure the TXT answers are properly reconstructed before sending to the evaluator.

Record types CAA and SOA are expected to return a single answer. This allows for using any of those record types' RDATA fields for condition variables.

I updated the regular expressions in src/util-frontend.js that are used for validating hostnames and IP addresses. This is because DNS names have a bit more flexibility than normal hostnames and FQDNs, plus I wanted to require IP for some DNS transport methods, and hostnames for others. I first converted the existing patterns to JS RegExp enclosed in forward slash (/) for proper linting. To get these to work with the Vue :pattern directive, I used the RegExp.source attribute which provides the pattern in an escaped string. Then I updated the patterns for hostname, IPv4, and IPv6 to match what I needed in the DNS monitor form. Finally, I created some parameters that can be used to switch between the different combinations of patterns for different scenarios, retaining the functionality for the MQTT monitor. There are a couple places where I needed to tell ESLint to ignore escapes (\) that are actually necessary for the pattern to work.

Smaller changes and improvements I made include:

  • Changed monitor variable names related to DNS monitor in various files to follow camelCase
  • Test for EditMonitor DNS form, and tests for DNS monitor for each transport method
  • English translation for all new fields in EditMonitor, plus a few corrections for existing fields
  • Centered the text in dropdowns using vue-multiselect

💬 Requested Feedback

Given the changes made, I would like to know how current users feel about them and if any new documentation should be created. Personally, I feel that the descriptions on the EditMonitor form are adequate for guidance on configuring the different transport methods. However, the changes to conditions might warrant a quick guide on how to configure the logic for different record types.

I also need some assistance confirming that IPv6 is working for the different transport methods. I don't have IPv6 with my ISP, so I have not been able to test it extensively against IPv6 resolvers.

// Similar to hostNameRegexPattern, except the hostname pattern
// can also match root (.) and top-level domains (.com, .org),
// and may contain underscores (_)
const dnsNamePattern = /^(\.|(\.?[a-zA-Z0-9\-_]+)+)$/;

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '-'.
*/
export function urlPathRegexPattern(qstr = false, tmpl = false) {
// Matches any URL path, including empty string
const pathRegexPattern = /^\/?(([a-zA-Z0-9\-_%])+\/)*[a-zA-Z0-9\-_%]*(\?([a-zA-Z0-9\-_%]+=[a-zA-Z0-9\-_%]*&?)+)?$/;

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with '?%=' and containing many repetitions of '%%='.
// Matches any URL path, including empty string
const pathRegexPattern = /^\/?(([a-zA-Z0-9\-_%])+\/)*[a-zA-Z0-9\-_%]*(\?([a-zA-Z0-9\-_%]+=[a-zA-Z0-9\-_%]*&?)+)?$/;
// Ensures a URL path follows query string format
const queryRegexPattern = /^\/?(([a-zA-Z0-9\-_%])+\/)*[a-zA-Z0-9\-_%]*\?([a-zA-Z0-9\-_%]+=[a-zA-Z0-9\-_%]*&?)+$/;

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with '?%=' and containing many repetitions of '%%='.
Copy link
Collaborator

@CommanderStorm CommanderStorm left a comment

Choose a reason for hiding this comment

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

Could you split this PR up into multiple PRs?

The PR changes 8 things as noted by you.. We can group related things, but +900 -90 lines (discounting tests/..) is not omething that I can review.
For such large PRs, it is waaay to simple to miss bugs/...

I looked over the changes and found the following:

  • the inital migration should not change. Please use a migration instead
  • naming for migrations follows YYYY-MM-DD format.
  • Removal of the record ConditionVariable likely breaks existing monitors. Adding variables is fine, but for replacement, you need to add a migration
  • Regarding changging of the hostname regex, I think we need to change this fundamentally. See #3929 (comment)
@CommanderStorm CommanderStorm added the pr:please address review comments this PR needs a bit more work to be mergable label Jun 22, 2025
@ekrekeler
Copy link
Author

ekrekeler commented Jun 23, 2025

ACK. Let me work on making this PR exclusively for the new DNS transport methods and related features. Changes to regex and condition variables/logic can get separate PRs.

So question about the database and migrations. Do you mean that I need to add new columns in a migration, and leave the knex_init_db.js file untouched?

@CommanderStorm
Copy link
Collaborator

CommanderStorm commented Jun 23, 2025

Yes, correct. The migration is already in db/knex_migrations/2025-22-02-0000-dns-trasnsport.js, the (partially different) changes to db/knex_init_db.js just need to be reverted

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs:resolve-merge-conflict pr:please address review comments this PR needs a bit more work to be mergable

2 participants