Files
firezone/.github/workflows/_integration_tests.yml
Thomas Eizinger 9de1119b69 feat(connlib): support DNS over TCP (#6944)
At present, `connlib` only supports DNS over UDP on port 53. Responses
over UDP are size-constrained on the IP MTU and thus, not all DNS
responses fit into a UDP packet. RFC9210 therefore mandates that all DNS
resolvers must also support DNS over TCP to overcome this limitation
[0].

Handling UDP packets is easy, handling TCP streams is more difficult
because we need to effectively implement a valid TCP state machine.

Building on top of a lot of earlier work (linked in issue), this is
relatively easy because we can now simply import
`dns_over_tcp::{Client,Server}` which do the heavy lifting of sending
and receiving the correct packets for us.

The main aspects of the integration that are worth pointing out are:

- We can handle at most 10 concurrent DNS TCP connections _per defined
resolver_. The assumption here is that most applications will first
query for DNS records over UDP and only fall back to TCP if the response
is truncated. Additionally, we assume that clients will close the TCP
connections once they no longer need it.
- Errors on the TCP stream to an upstream resolver result in `SERVFAIL`
responses to the client.
- All TCP connections to upstream resolvers get reset when we roam, all
currently ongoing queries will be answered with `SERVFAIL`.
- Upon network reset (i.e. roaming), we also re-allocate new local ports
for all TCP sockets, similar to our UDP sockets.

Resolves: #6140.

[0]: https://www.ietf.org/rfc/rfc9210.html#section-3-5
2024-10-18 03:40:50 +00:00

160 lines
5.2 KiB
YAML

name: Integration Tests
run-name: Triggered from ${{ github.event_name }} by ${{ github.actor }}
on:
workflow_call:
inputs:
domain_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/domain'
domain_tag:
required: false
type: string
default: ${{ github.sha }}
api_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/api'
api_tag:
required: false
type: string
default: ${{ github.sha }}
web_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/web'
web_tag:
required: false
type: string
default: ${{ github.sha }}
elixir_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/elixir'
elixir_tag:
required: false
type: string
default: ${{ github.sha }}
relay_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/debug/relay'
relay_tag:
required: false
type: string
default: ${{ github.sha }}
gateway_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/debug/gateway'
gateway_tag:
required: false
type: string
default: ${{ github.sha }}
client_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/debug/client'
client_tag:
required: false
type: string
default: ${{ github.sha }}
http_test_server_image:
required: false
type: string
default: 'us-east1-docker.pkg.dev/firezone-staging/firezone/debug/http-test-server'
http_test_server_tag:
required: false
type: string
default: ${{ github.sha }}
jobs:
integration-tests:
name: ${{ matrix.test.name }}
runs-on: ubuntu-22.04
permissions:
contents: read
id-token: write
pull-requests: write
env:
DOMAIN_IMAGE: ${{ inputs.domain_image }}
DOMAIN_TAG: ${{ inputs.domain_tag }}
API_IMAGE: ${{ inputs.api_image }}
API_TAG: ${{ inputs.api_tag }}
WEB_IMAGE: ${{ inputs.web_image }}
WEB_TAG: ${{ inputs.web_tag }}
RELAY_IMAGE: ${{ inputs.relay_image }}
RELAY_TAG: ${{ inputs.relay_tag }}
GATEWAY_IMAGE: ${{ inputs.gateway_image }}
GATEWAY_TAG: ${{ inputs.gateway_tag }}
CLIENT_IMAGE: ${{ inputs.client_image }}
CLIENT_TAG: ${{ inputs.client_tag }}
ELIXIR_IMAGE: ${{ inputs.elixir_image }}
ELIXIR_TAG: ${{ inputs.elixir_tag }}
HTTP_TEST_SERVER_IMAGE: ${{ inputs.http_test_server_image }}
HTTP_TEST_SERVER_TAG: ${{ inputs.http_test_server_tag }}
strategy:
fail-fast: false
matrix:
test:
- name: direct-curl-api-down
- name: direct-curl-api-restart
- name: direct-dns-api-down
- name: direct-dns-two-resources
- name: direct-dns
- name: direct-download-roaming-network
# Too noisy can cause flaky tests due to the amount of data
rust_log: debug
- name: dns-nm
- name: tcp-dns
- name: relay-graceful-shutdown
- name: systemd/dns-systemd-resolved
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/gcp-docker-login
id: login
with:
project: firezone-staging
- name: Seed database
run: docker compose run elixir /bin/sh -c 'cd apps/domain && mix ecto.seed'
- name: Start docker compose in the background
run: |
set -xe
if [[ ! -z "${{ matrix.test.rust_log }}" ]]; then
export RUST_LOG="${{ matrix.test.rust_log }}"
fi
# Start one-by-one to avoid variability in service startup order
docker compose up -d dns.httpbin httpbin download.httpbin --no-build
docker compose up -d api web domain --no-build
docker compose up -d otel --no-build
docker compose up -d relay-1 --no-build
docker compose up -d relay-2 --no-build
docker compose up -d gateway --no-build
docker compose up -d client --no-build
# Wait a few seconds for the services to fully start. GH runners are
# slow, so this gives the Client enough time to initialize its tun interface,
# for example.
# Intended to mitigate <https://github.com/firezone/firezone/issues/5830>
sleep 3
- run: ./scripts/tests/${{ matrix.test.name }}.sh
- name: Show Client logs
if: "!cancelled()"
run: docker compose logs client
- name: Show Relay-1 logs
if: "!cancelled()"
run: docker compose logs relay-1
- name: Show Relay-2 logs
if: "!cancelled()"
run: docker compose logs relay-2
- name: Show Gateway logs
if: "!cancelled()"
run: docker compose logs gateway
- name: Show API logs
if: "!cancelled()"
run: docker compose logs api