Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions .github/workflows/qualify-authoritative-network.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Qualify authoritative DNS and OS networks

on:
workflow_dispatch:
pull_request:
branches: [main]
paths:
- '.github/workflows/qualify-authoritative-network.yml'
- 'scripts/qualification/**'
- 'DnsClientX/**'
- 'DnsClientX.Tests/**'

permissions:
contents: read

jobs:
authoritative:
name: BIND interoperability (${{ matrix.os }}, ${{ matrix.framework }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
framework: [net8.0, net10.0]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
dotnet-version: |
8.x
10.x
- name: Install independent BIND tools on Linux
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install --yes bind9 bind9-utils dnsutils
sudo systemctl stop named
sudo install -d -o "$(id -u)" -g "$(id -g)" -m 0700 /var/lib/bind/dnsclientx-qualification
- name: Install independent BIND tools on macOS
if: runner.os == 'macOS'
env:
HOMEBREW_NO_AUTO_UPDATE: '1'
run: brew install bind
- name: Qualify private anchors, aliases, denial, UPDATE and authenticated transfers
shell: bash
run: |
if [ "${{ runner.os }}" = "macOS" ]; then
python3 scripts/qualification/qualify-bind.py --framework '${{ matrix.framework }}' --output artifacts/bind --tool-directory "$(brew --prefix bind)/bin"
else
python3 scripts/qualification/qualify-bind.py --framework '${{ matrix.framework }}' --output artifacts/bind --lab-root /var/lib/bind/dnsclientx-qualification
fi
- name: Keep independent evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: bind-${{ matrix.os }}-${{ matrix.framework }}
path: |
artifacts/bind/*.log
artifacts/bind/producer.json
artifacts/bind/results/
retention-days: 7
if-no-files-found: error

linux-network:
name: Linux OS network (${{ matrix.framework }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
framework: [net8.0, net10.0]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
dotnet-version: |
8.x
10.x
- name: Install disposable kernel-network lab tools
run: |
sudo apt-get update
sudo apt-get install --yes bind9 bind9-utils dnsutils iproute2 util-linux
sudo systemctl stop named
sudo install -d -o root -g root -m 0700 /var/lib/bind/dnsclientx-qualification
- name: Build before entering isolated namespaces
run: dotnet build DnsClientX.Tests/DnsClientX.Tests.csproj -c Release -f ${{ matrix.framework }} --artifacts-path artifacts/build
- name: Qualify actual resolver discovery, IPv6, search domains and adapter changes
shell: bash
run: |
host_network=$(readlink /proc/self/ns/net)
host_mount=$(readlink /proc/self/ns/mnt)
dotnet_path=$(command -v dotnet)
sudo env "PATH=$(dirname "$dotnet_path"):$PATH" unshare --net --mount --propagation private --fork \
python3 scripts/qualification/qualify-linux-network.py \
--host-network "$host_network" --host-mount "$host_mount" \
--framework '${{ matrix.framework }}' --artifacts "$PWD/artifacts/build" --output "$PWD/artifacts/network" \
--lab-root /var/lib/bind/dnsclientx-qualification
- name: Keep OS network evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: linux-network-${{ matrix.framework }}
path: |
artifacts/network/*.log
artifacts/network/namespace-receipt.json
artifacts/network/results/
retention-days: 7
if-no-files-found: error
45 changes: 41 additions & 4 deletions .github/workflows/qualify-quic-pool.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Qualify QUIC pool lifetime
name: Qualify native encrypted DNS

on:
workflow_dispatch:
Expand All @@ -9,15 +9,43 @@ on:
- 'DnsClientX/ProtocolDnsQuic/DnsQuicConnectionPool.cs'
- 'DnsClientX/ProtocolDnsQuic/DnsWireResolveQuic.cs'
- 'DnsClientX/Network/DnsTlsCertificateTrust.cs'
- 'DnsClientX/ProtocolDnsHttp3/**'
- 'DnsClientX/ProtocolDnsWire/DnsWireResolve.cs'
- 'DnsClientX/DnsHttp*.cs'
- 'DnsClientX/DnsClientX.cs'
- 'DnsClientX/DnsClientX.Http*.cs'
- 'DnsClientX/DnsClientX.Resolve.cs'
- 'DnsClientX/DnsClientX.Dispose.cs'
- 'DnsClientX/Configuration*.cs'
- 'DnsClientX/Definitions/DnsResolverEndpoint.cs'
- 'DnsClientX/Network/DnsServerResolver.cs'
- 'DnsClientX/Network/DnsBootstrapResolver.cs'
- 'DnsClientX.Tests/DnsQuicConnectionPool*'
- 'DnsClientX.Tests/NativeEncryptedDns*'
- 'DnsClientX.Tests/TestUtilities.cs'
- 'DnsClientX.Tests/DnsClientX.Tests.csproj'
push:
branches: [main]
paths:
- '.github/workflows/qualify-quic-pool.yml'
- 'DnsClientX/ProtocolDnsQuic/DnsQuicConnectionPool.cs'
- 'DnsClientX/ProtocolDnsQuic/DnsWireResolveQuic.cs'
- 'DnsClientX/Network/DnsTlsCertificateTrust.cs'
- 'DnsClientX/ProtocolDnsHttp3/**'
- 'DnsClientX/ProtocolDnsWire/DnsWireResolve.cs'
- 'DnsClientX/DnsHttp*.cs'
- 'DnsClientX/DnsClientX.cs'
- 'DnsClientX/DnsClientX.Http*.cs'
- 'DnsClientX/DnsClientX.Resolve.cs'
- 'DnsClientX/DnsClientX.Dispose.cs'
- 'DnsClientX/Configuration*.cs'
- 'DnsClientX/Definitions/DnsResolverEndpoint.cs'
- 'DnsClientX/Network/DnsServerResolver.cs'
- 'DnsClientX/Network/DnsBootstrapResolver.cs'
- 'DnsClientX.Tests/DnsQuicConnectionPool*'
- 'DnsClientX.Tests/NativeEncryptedDns*'
- 'DnsClientX.Tests/TestUtilities.cs'
- 'DnsClientX.Tests/DnsClientX.Tests.csproj'

permissions:
contents: read
Expand All @@ -30,7 +58,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
os: [ubuntu-latest, windows-latest, macos-latest]
framework: [net8.0, net10.0]
env:
DNSCLIENTX_REQUIRE_QUIC: '1'
Expand All @@ -48,8 +76,17 @@ jobs:
sudo apt-get update
sudo apt-get install --yes libmsquic
dpkg-query -W libmsquic
- name: Verify pool lifetime with native loopback connections
run: dotnet test DnsClientX.Tests/DnsClientX.Tests.csproj -c Release -f ${{ matrix.framework }} --filter FullyQualifiedName~DnsQuicConnectionPool --logger trx --results-directory artifacts/quic-pool
- name: Install macOS QUIC platform runtime
if: runner.os == 'macOS'
shell: bash
env:
HOMEBREW_NO_AUTO_UPDATE: '1'
run: |
brew install libmsquic openssl@3
brew list --versions libmsquic openssl@3
echo "DYLD_FALLBACK_LIBRARY_PATH=$(brew --prefix)/lib:$(brew --prefix openssl@3)/lib" >> "$GITHUB_ENV"
- name: Verify encrypted DNS with native loopback connections
run: dotnet test DnsClientX.Tests/DnsClientX.Tests.csproj -c Release -f ${{ matrix.framework }} --filter "FullyQualifiedName~DnsQuicConnectionPool|FullyQualifiedName~NativeEncryptedDns" --logger trx --results-directory artifacts/quic-pool
- name: Keep native qualification results
if: always()
uses: actions/upload-artifact@v7
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/test-dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ jobs:
test-windows:
name: 'Windows'
runs-on: windows-latest
timeout-minutes: 10
# SDK setup and restore can take over eight minutes before three test targets run.
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@v7
Expand Down
8 changes: 8 additions & 0 deletions DnsClientX.PowerShell/CmdletTestDnsBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public sealed class DnsBenchmarkResult {
/// </summary>
public string Target { get; set; } = string.Empty;

/// <summary>Gets or sets the stable configured resolver candidate identity.</summary>
public string CandidateId { get; set; } = string.Empty;

/// <summary>
/// Resolver address observed on the fastest successful attempt for this candidate.
/// </summary>
Expand Down Expand Up @@ -238,6 +241,9 @@ public sealed class DnsBenchmarkSummary {
/// </summary>
public string RecommendedTarget { get; set; } = "none";

/// <summary>Gets or sets the stable configured resolver candidate identity.</summary>
public string RecommendedCandidateId { get; set; } = string.Empty;

/// <summary>
/// Resolver observed on the recommended target's fastest successful attempt.
/// </summary>
Expand Down Expand Up @@ -621,6 +627,7 @@ private ResolverQueryRunOptions CreateQueryRunOptions() {
private static DnsBenchmarkResult ToDnsBenchmarkResult(ResolverBenchmarkReportResult result) {
return new DnsBenchmarkResult {
Target = result.Target,
CandidateId = result.CandidateId,
Resolver = result.Resolver,
Transport = result.Transport,
Domains = result.Domains,
Expand Down Expand Up @@ -670,6 +677,7 @@ private static DnsBenchmarkSummary ToDnsBenchmarkSummary(ResolverBenchmarkReport
RequiredMinSuccessPercent = summary.RequiredMinSuccessPercent,
RequiredMinSuccessfulCandidates = summary.RequiredMinSuccessfulCandidates,
RecommendedTarget = summary.RecommendedTarget,
RecommendedCandidateId = summary.RecommendedCandidateId,
RecommendedResolver = summary.RecommendedResolver,
RecommendedTransport = summary.RecommendedTransport,
RecommendedAverageMs = summary.RecommendedAverageMs,
Expand Down
30 changes: 29 additions & 1 deletion DnsClientX.PowerShell/CmdletTestDnsProbe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public sealed class DnsProbeResult {
/// </summary>
public string Target { get; set; } = string.Empty;

/// <summary>Gets or sets the stable configured resolver candidate identity.</summary>
public string CandidateId { get; set; } = string.Empty;

/// <summary>
/// Resolver address observed for the candidate.
/// </summary>
Expand Down Expand Up @@ -191,6 +194,9 @@ public sealed class DnsProbeSummary {
/// </summary>
public string FastestSuccessTarget { get; set; } = "none";

/// <summary>Gets or sets the stable configured resolver candidate identity.</summary>
public string FastestSuccessCandidateId { get; set; } = string.Empty;

/// <summary>
/// Resolver observed for the fastest successful candidate.
/// </summary>
Expand All @@ -211,6 +217,9 @@ public sealed class DnsProbeSummary {
/// </summary>
public string FastestConsensusTarget { get; set; } = "none";

/// <summary>Gets or sets the stable configured resolver candidate identity.</summary>
public string FastestConsensusCandidateId { get; set; } = string.Empty;

/// <summary>
/// Resolver observed for the fastest consensus candidate.
/// </summary>
Expand All @@ -236,6 +245,9 @@ public sealed class DnsProbeSummary {
/// </summary>
public string RecommendedTarget { get; set; } = "none";

/// <summary>Gets or sets the stable configured resolver candidate identity.</summary>
public string RecommendedCandidateId { get; set; } = string.Empty;

/// <summary>
/// Resolver observed for the recommended candidate.
/// </summary>
Expand Down Expand Up @@ -275,6 +287,15 @@ public sealed class DnsProbeSummary {
/// Runtime capability warnings captured during the probe run.
/// </summary>
public string[] RuntimeCapabilityWarnings { get; set; } = Array.Empty<string>();

/// <summary>Gets or sets readable labels of candidates outside the largest answer group.</summary>
public string[] MismatchedTargets { get; set; } = Array.Empty<string>();

/// <summary>Gets or sets configured identities corresponding to <see cref="MismatchedTargets"/>.</summary>
public string[] MismatchedCandidateIds { get; set; } = Array.Empty<string>();

/// <summary>Gets or sets successful answer variants and their responder identities.</summary>
public ResolverProbeAnswerVariant[] AnswerVariants { get; set; } = Array.Empty<ResolverProbeAnswerVariant>();
}

/// <summary>
Expand Down Expand Up @@ -612,6 +633,7 @@ private ResolverQueryRunOptions CreateQueryRunOptions() {
private static DnsProbeResult ToDnsProbeResult(ResolverProbeReportResult result) {
return new DnsProbeResult {
Target = result.Target,
CandidateId = result.CandidateId,
Resolver = result.Resolver,
RequestFormat = result.RequestFormat,
Transport = result.Transport,
Expand Down Expand Up @@ -652,23 +674,29 @@ private static DnsProbeSummary ToDnsProbeSummary(ResolverProbeReportSummary summ
ConsensusTotal = summary.ConsensusTotal,
ConsensusPercent = summary.ConsensusPercent,
FastestSuccessTarget = summary.FastestSuccessTarget,
FastestSuccessCandidateId = summary.FastestSuccessCandidateId,
FastestSuccessResolver = summary.FastestSuccessResolver,
FastestSuccessTransport = summary.FastestSuccessTransport,
FastestSuccessMs = summary.FastestSuccessMs,
FastestConsensusTarget = summary.FastestConsensusTarget,
FastestConsensusCandidateId = summary.FastestConsensusCandidateId,
FastestConsensusResolver = summary.FastestConsensusResolver,
FastestConsensusTransport = summary.FastestConsensusTransport,
FastestConsensusMs = summary.FastestConsensusMs,
RecommendationAvailable = summary.RecommendationAvailable,
RecommendedTarget = summary.RecommendedTarget,
RecommendedCandidateId = summary.RecommendedCandidateId,
RecommendedResolver = summary.RecommendedResolver,
RecommendedTransport = summary.RecommendedTransport,
RecommendedAverageMs = summary.RecommendedAverageMs,
RecommendationSource = summary.RecommendationSource,
RecommendationStatus = summary.RecommendationStatus,
RecommendationReason = summary.RecommendationReason,
RuntimeUnsupportedCandidateCount = summary.RuntimeUnsupportedCandidateCount,
RuntimeCapabilityWarnings = summary.RuntimeCapabilityWarnings
RuntimeCapabilityWarnings = summary.RuntimeCapabilityWarnings,
MismatchedTargets = summary.MismatchedTargets,
MismatchedCandidateIds = summary.MismatchedCandidateIds,
AnswerVariants = summary.AnswerVariants
};
}

Expand Down
Loading
Loading