From 806421392d24a6e2b6355f7a3aa1573c5b9ab730 Mon Sep 17 00:00:00 2001 From: modem7 Date: Sat, 8 Aug 2026 13:52:28 +0100 Subject: [PATCH 1/2] Migrate to Debian, run non-root, split CI, align with org scaffolding Alpine dropped the dhcrelay package entirely starting at 3.21 (upstream ISC-DHCP has had no releases since 2022); Debian trixie still ships and security-patches isc-dhcp-relay, so that's the new base. The process now runs as a non-root user with only NET_RAW/NET_BIND_SERVICE via setcap, verified empirically to still bind port 67 and relay correctly (NET_ADMIN, previously granted, turns out to be unnecessary). - Dockerfile: debian:trixie-slim, setcap+non-root, OCI labels, a real pgrep-free healthcheck, and an entrypoint.sh that builds the dhcrelay command from DHCRELAY_* env vars (falling back to passthrough for any explicit command, so existing compose overrides keep working). - docker-compose.yml: cap_drop: ALL + minimal cap_add, env-var config, drops the obsolete `version:` key. - CI split: hadolint now lives in .github/workflows/lint.yml (GitHub Actions); .woodpecker.yml (replacing .drone.yml) builds/pushes on push-to-master + manual events, tagging images with the resolved isc-dhcp-relay version instead of a hardcoded one. - .github/workflows/dhcrelay-freshness.yml: weekly check comparing Debian's current package version against the published image tag, opens a tracking issue if stale (manual Woodpecker rebuild fixes it). - renovate.json now just extends the shared org preset; .hadolint.yaml overrides DL3008 for the intentionally-unpinned package. - .github/settings.yml + autoassign.yml brought in line with the rest of the account (labelsync.yml/labels.yml removed, now inherited via settings.yml). - README updated for the new compose shape, env vars, and split DHCPv4/DHCPv6 command examples; removed the now-unused Links/ and version_check.txt (Alpine-specific). Addresses #63. --- .drone.yml | 64 --------------- .github/config/labels.yml | 30 ------- .github/settings.yml | 22 ++++++ .github/workflows/CI.yml | 29 ------- .github/workflows/autoassign.yml | 25 +++++- .github/workflows/dhcrelay-freshness.yml | 49 ++++++++++++ .github/workflows/labelsync.yml | 22 ------ .github/workflows/lint.yml | 25 ++++++ .hadolint.yaml | 2 +- .woodpecker.yml | 99 ++++++++++++++++++++++++ Dockerfile | 41 ++++++++-- Links/DHCP Alpine Packages.url | 6 -- README.md | 99 +++++++++++++++++------- docker-compose.yml | 13 +++- entrypoint.sh | 34 ++++++++ renovate.json | 5 +- version_check.txt | 1 - 17 files changed, 368 insertions(+), 198 deletions(-) delete mode 100644 .drone.yml delete mode 100644 .github/config/labels.yml create mode 100644 .github/settings.yml delete mode 100644 .github/workflows/CI.yml create mode 100644 .github/workflows/dhcrelay-freshness.yml delete mode 100644 .github/workflows/labelsync.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .woodpecker.yml delete mode 100644 Links/DHCP Alpine Packages.url create mode 100644 entrypoint.sh delete mode 100644 version_check.txt diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 2107ff0..0000000 --- a/.drone.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- - -kind: pipeline -type: docker -name: latest - -platform: - os: linux - arch: amd64 - -steps: -- name: Lint Dockerfile - image: hadolint/hadolint:latest-alpine - pull: if-not-exists - commands: - - hadolint --version - - hadolint Dockerfile* - -- name: latest - image: thegeeklab/drone-docker-buildx - privileged: true - settings: - repo: modem7/dhcprelay - purge: true - compress: true - build_args: BUILDKIT_INLINE_CACHE=1 - use_cache: true - cache_from: "modem7/dhcprelay:latest" - platforms: # if it doesn't work run docker run --privileged --rm tonistiigi/binfmt --install all - - linux/amd64 - - linux/arm64 - username: - from_secret: docker_username - password: - from_secret: docker_password - tags: - - latest - - 4.4.3 - -- name: pushrm-dockerhub - image: chko/docker-pushrm - environment: - DOCKER_USER: - from_secret: docker_username - DOCKER_PASS: - from_secret: docker_password - PUSHRM_FILE: README.md - PUSHRM_SHORT: Docker DHCP Relay - PUSHRM_TARGET: modem7/dhcprelay - when: - status: - - success - -- name: slack - image: themaz/drone-slack - settings: - webhook: - from_secret: slack_hook - when: - status: [ success, failure ] - -trigger: - event: - - custom \ No newline at end of file diff --git a/.github/config/labels.yml b/.github/config/labels.yml deleted file mode 100644 index 17b99eb..0000000 --- a/.github/config/labels.yml +++ /dev/null @@ -1,30 +0,0 @@ -- name: "bug" - color: "d73a4a" - description: "Something isn't working" -- name: "dependencies" - color: "C62109" - description: "Pull requests that update a dependency file" -- name: "documentation" - color: "0075ca" - description: "Improvements or additions to documentation" -- name: "duplicate" - color: "cfd3d7" - description: "This issue or pull request already exists" -- name: "enhancement" - color: "a2eeef" - description: "New feature or request" -- name: "good first issue" - color: "7057ff" - description: "Good for newcomers" -- name: "help wanted" - color: "008672" - description: "Extra attention is needed" -- name: "invalid" - color: "e4e669" - description: "This doesn't seem right" -- name: "question" - color: "d876e3" - description: "Further information is requested" -- name: "wontfix" - color: "#ffffff" - description: "This will not be worked on" diff --git a/.github/settings.yml b/.github/settings.yml new file mode 100644 index 0000000..a5036a6 --- /dev/null +++ b/.github/settings.yml @@ -0,0 +1,22 @@ +_extends: .github +# https://github.com/apps/settings +# https://github.com/repository-settings/app + +repository: + description: Docker DHCP Relay + topics: docker, dhcp, dhcp-relay, isc-dhcp + + private: false + has_issues: true + has_wiki: false + has_downloads: true + has_projects: false + + default_branch: master + + allow_squash_merge: true + allow_rebase_merge: true + allow_merge_commit: false + + enable_automated_security_fixes: true + enable_vulnerability_alerts: true diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml deleted file mode 100644 index be64a95..0000000 --- a/.github/workflows/CI.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Docker build CI - -on: - push: - paths: - - Dockerfile - pull_request: - paths: - - Dockerfile - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - name: Set up Docker - steps: - - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build - uses: docker/build-push-action@v6 - with: - context: . - file: ./Dockerfile - pull: false - push: false \ No newline at end of file diff --git a/.github/workflows/autoassign.yml b/.github/workflows/autoassign.yml index ee72637..0199e61 100644 --- a/.github/workflows/autoassign.yml +++ b/.github/workflows/autoassign.yml @@ -1,14 +1,31 @@ -name: Issue assignment +name: Issue and PR assignment on: issues: types: [opened] + pull_request: + types: [opened] jobs: - auto-assign: + auto-assign-issue: + if: github.event_name == 'issues' runs-on: ubuntu-latest + permissions: + issues: write steps: - name: 'Auto-assign issue' - uses: pozil/auto-assign-issue@v1 + uses: pozil/auto-assign-issue@v4.0.1 + with: + assignees: modem7 + + auto-assign-pr: + if: github.event_name == 'pull_request' && github.actor != 'renovate[bot]' + runs-on: ubuntu-latest + permissions: + pull-requests: write + issues: write + steps: + - name: 'Auto-assign PR' + uses: pozil/auto-assign-issue@v4.0.1 with: - assignees: modem7 \ No newline at end of file + assignees: modem7 diff --git a/.github/workflows/dhcrelay-freshness.yml b/.github/workflows/dhcrelay-freshness.yml new file mode 100644 index 0000000..b8ca592 --- /dev/null +++ b/.github/workflows/dhcrelay-freshness.yml @@ -0,0 +1,49 @@ +name: Check dhcrelay freshness + +on: + schedule: + # Weekly - Debian security backports to isc-dhcp-relay land on the order + # of weeks/months, not days, so there's no value checking more often. + - cron: "0 6 * * 1" + workflow_dispatch: + +permissions: + contents: read + issues: write + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Resolve current Debian package version + id: debian + run: | + docker run --rm debian:trixie-slim sh -c \ + "apt-get update -qq && apt-cache policy isc-dhcp-relay | awk '/Candidate:/ {print \$2}'" \ + > debian_version.txt + echo "version=$(cat debian_version.txt)" >> "$GITHUB_OUTPUT" + + - name: Resolve currently published image version + id: published + run: | + published=$(curl -fsS "https://hub.docker.com/v2/repositories/modem7/dhcprelay/tags?page_size=100" \ + | jq -r '.results[].name' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1) + echo "version=$published" >> "$GITHUB_OUTPUT" + + - name: Compare and open a tracking issue if stale + if: steps.published.outputs.version != '' && !startsWith(steps.debian.outputs.version, steps.published.outputs.version) + env: + GH_TOKEN: ${{ github.token }} + DEBIAN_VERSION: ${{ steps.debian.outputs.version }} + PUBLISHED_VERSION: ${{ steps.published.outputs.version }} + run: | + set -eu + existing=$(gh issue list --label dependencies --state open --search "dhcrelay version is out of date in:title" --json number --jq 'length') + if [ "$existing" -gt 0 ]; then + echo "An open freshness issue already exists, skipping." + else + gh issue create \ + --title "dhcrelay version is out of date" \ + --label dependencies \ + --body "Debian trixie currently offers isc-dhcp-relay ${DEBIAN_VERSION}, but the latest published image tag is ${PUBLISHED_VERSION}. Trigger a rebuild via the Woodpecker pipeline's manual event to pick up the update. This issue needs closing manually once the new image is published." + fi diff --git a/.github/workflows/labelsync.yml b/.github/workflows/labelsync.yml deleted file mode 100644 index 13979bf..0000000 --- a/.github/workflows/labelsync.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Label Manager - -on: - push: - paths: - - '.github/config/labels.yml' - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - - - name: Synchronize labels - uses: julb/action-manage-label@v1 - with: - from: .github/config/labels.yml - skip_delete: false - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..d360468 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: Lint Dockerfile + +on: + push: + paths: + - Dockerfile + - .github/workflows/lint.yml + pull_request: + paths: + - Dockerfile + - .github/workflows/lint.yml + workflow_dispatch: + +jobs: + hadolint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v7.0.1 + + - name: Run hadolint + run: | + docker run --rm -v "$PWD":/work -w /work \ + hadolint/hadolint:v2.15.1-alpine@sha256:a1d49ae1a4e83c1dbad26b8c1ad7588c8bd1e04f4866b34ad3cac50335198552 \ + sh -c "hadolint --version && hadolint Dockerfile" diff --git a/.hadolint.yaml b/.hadolint.yaml index f28ea1b..40b098c 100644 --- a/.hadolint.yaml +++ b/.hadolint.yaml @@ -1,3 +1,3 @@ override: style: - - DL3018 \ No newline at end of file + - DL3008 diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..a0311ed --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,99 @@ +when: + - event: [push, manual] + branch: master + path: + # Scoped to what actually gets baked into the image - docs/CI-only + # changes elsewhere shouldn't trigger a rebuild/republish. + include: + - Dockerfile + - entrypoint.sh + - .woodpecker.yml + +steps: + # Resolves the DHCPv4/v6 relay version tag (e.g. "4.4.3") from Debian's + # live apt index for isc-dhcp-relay, rather than a version pinned in the + # Dockerfile - the package is deliberately left unpinned there so every + # rebuild picks up Debian's latest security backport automatically. + - name: prepare-tags + image: debian:trixie-slim + commands: + - apt-get update -qq + - pkg_ver=$(apt-cache policy isc-dhcp-relay | awk '/Candidate:/ {print $2}') + - relay_ver=$(echo "$pkg_ver" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+') + - printf "latest\n%s\n" "$relay_ver" > .tags + - echo "Tags to publish:" && cat .tags + + - name: build-and-push + image: woodpeckerci/plugin-docker-buildx + privileged: true + depends_on: [prepare-tags] + settings: + repo: modem7/dhcprelay + dockerfile: Dockerfile + context: . + purge: true + compress: true + build_args: + BUILDKIT_INLINE_CACHE: "1" + cache_from: + - type=registry\,ref=modem7/dhcprelay:latest + platforms: linux/amd64,linux/arm64 + username: + from_secret: docker_username + password: + from_secret: docker_password + tags_file: .tags + + - name: pushrm-dockerhub + image: chko/docker-pushrm + depends_on: + - build-and-push + environment: + DOCKER_USER: + from_secret: docker_username + DOCKER_PASS: + from_secret: docker_password + PUSHRM_FILE: README.md + PUSHRM_SHORT: Docker DHCP Relay + PUSHRM_TARGET: modem7/dhcprelay + when: + - status: [success] + + # Single dynamic-status notifier, replacing notify-slack-success/failure. + # CI_PIPELINE_STATUS must stay bare ($VAR, not ${VAR}) - Woodpecker + # resolves ${VAR} at compile time, before this value exists + # (woodpecker-ci/woodpecker#6826). + - name: notify-slack + image: alpine + depends_on: + - build-and-push + environment: + SLACK_WEBHOOK: + from_secret: slack_hook + commands: + - apk add --no-cache curl jq >/dev/null + - COMMIT_SHORT=$(echo "$CI_COMMIT_SHA" | cut -c1-10) + - > + PAYLOAD=$(jq -n + --arg status "$CI_PIPELINE_STATUS" + --arg branch "$CI_COMMIT_BRANCH" + --arg output "${CI_REPO}#${CI_PIPELINE_NUMBER}" + --arg output_url "$CI_PIPELINE_URL" + --arg build "$CI_PIPELINE_NUMBER" + --arg commit "$COMMIT_SHORT" + --arg commit_url "$CI_PIPELINE_FORGE_URL" + --arg author "$CI_COMMIT_AUTHOR" + --arg message "$CI_COMMIT_MESSAGE" + '{attachments:[{color:(if $status == "success" then "good" else "danger" end),fields:[ + {title:"Status",value:$status,short:true}, + {title:"Branch",value:$branch,short:true}, + {title:"Output",value:("<"+$output_url+"|"+$output+">"),short:true}, + {title:"Build Number",value:$build,short:true}, + {title:"Commit",value:("<"+$commit_url+"|"+$commit+">"),short:true}, + {title:"Author",value:$author,short:true}, + {title:"Commit Message",value:$message,short:false} + ]}]}') + - > + curl -fsS -X POST -H 'Content-type: application/json' --data "$PAYLOAD" "$SLACK_WEBHOOK" + when: + - status: [success, failure] diff --git a/Dockerfile b/Dockerfile index 88a60ee..3d6dc70 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,35 @@ # syntax = docker/dockerfile:1 -FROM alpine:3.20.3 -RUN apk add --no-cache \ - dhcrelay>=4.4.3_p1-r4 \ - tzdata -EXPOSE 67 67/udp -# HEALTHCHECK CMD nc -uzvw3 127.0.0.1 67 || exit 1 -ENTRYPOINT ["dhcrelay", "-d"] -LABEL maintainer="modem7" \ No newline at end of file +FROM debian:trixie-slim + +LABEL org.opencontainers.image.title="dhcprelay" \ + org.opencontainers.image.description="ISC DHCP Relay Agent (dhcrelay) in a minimal container" \ + org.opencontainers.image.source="https://github.com/modem7/DHCP-Relay" \ + org.opencontainers.image.licenses="MIT" + +# isc-dhcp-relay is deliberately unpinned (hadolint DL3008) so every rebuild +# picks up Debian's latest security backport - upstream ISC-DHCP itself has +# had no releases since 2022, so Debian's own patching is what keeps this +# current. libcap2-bin is a build-only dependency, removed after setcap runs. +# hadolint ignore=DL3008 +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + isc-dhcp-relay \ + libcap2-bin \ + tzdata \ + && setcap cap_net_raw,cap_net_bind_service+eip /usr/sbin/dhcrelay \ + && apt-get purge -y --auto-remove libcap2-bin \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r -g 999 dhcp \ + && useradd -r -u 999 -g dhcp -M -s /usr/sbin/nologin dhcp + +COPY --chmod=755 entrypoint.sh /usr/local/bin/entrypoint.sh + +USER 999:999 + +EXPOSE 67/udp 547/udp + +HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=5s \ + CMD ["sh", "-c", "[ \"$(cat /proc/1/comm)\" = dhcrelay ]"] + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/Links/DHCP Alpine Packages.url b/Links/DHCP Alpine Packages.url deleted file mode 100644 index 8129d07..0000000 --- a/Links/DHCP Alpine Packages.url +++ /dev/null @@ -1,6 +0,0 @@ -[{000214A0-0000-0000-C000-000000000046}] -Prop3=19,11 -[InternetShortcut] -IDList= -URL=https://pkgs.alpinelinux.org/packages?name=dhcrelay&branch=v3.20 -HotKey=0 diff --git a/README.md b/README.md index 883a025..23a871e 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,115 @@ # ISC DHCP Relay Agent -![Docker Pulls](https://img.shields.io/docker/pulls/modem7/dhcprelay) -![Docker Image Size (tag)](https://img.shields.io/docker/image-size/modem7/dhcprelay/latest) -[![Build Status](https://drone.modem7.com/api/badges/modem7/DHCP-Relay/status.svg)](https://drone.modem7.com/modem7/DHCP-Relay) +![Docker Pulls](https://img.shields.io/docker/pulls/modem7/dhcprelay) +![Docker Image Size (tag)](https://img.shields.io/docker/image-size/modem7/dhcprelay/latest) +[![status-badge](https://woodpecker.modem7.com/api/badges/10/status.svg?events=push%2Cmanual)](https://woodpecker.modem7.com/repos/10) +[![Lint Dockerfile](https://github.com/modem7/DHCP-Relay/actions/workflows/lint.yml/badge.svg)](https://github.com/modem7/DHCP-Relay/actions/workflows/lint.yml) [![GitHub latest commit](https://badgen.net/github/last-commit/modem7/DHCP-Relay)](https://GitHub.com/modem7/DHCP-Relay/commit/) [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/modem7) A simple ISC DHCP Relay Agent. -The Internet Systems Consortium DHCP Relay Agent, dhcrelay, provides a means for relaying DHCP and BOOTP requests from a subnet to which no DHCP server is directly connected to one or more DHCP servers on other subnets. It supports both DHCPv4/BOOTP and DHCPv6 protocols. +The Internet Systems Consortium DHCP Relay Agent, dhcrelay, provides a means for relaying DHCP and BOOTP requests from a subnet to which no DHCP server is directly connected to one or more DHCP servers on other subnets. It supports both DHCPv4/BOOTP and DHCPv6 protocols. More info can be found here: https://linux.die.net/man/8/dhcrelay +> **Note:** upstream ISC-DHCP (including `dhcrelay`) has had no releases since 2022 and is EOL - +> see [#63](https://github.com/modem7/DHCP-Relay/issues/63). This image is built on Debian, which +> continues to backport security fixes to its packaged `isc-dhcp-relay` even though upstream +> doesn't. There's no drop-in replacement for `dhcrelay`'s simple CLI-flag relay model yet; ISC's +> own recommended successor, [Kea](https://www.isc.org/kea/), uses a different JSON-config +> paradigm and would be a separate image. + # Tags | Tag | Description | | :----: | --- | -| Latest | Latest release built upon the latest version. | -| 4.4.x | Versioned release. | +| Latest | Latest built image. | +| 4.4.x | The `isc-dhcp-relay` version baked into that build (e.g. `4.4.3`). | # Configuration -In this config, udp port 67 must be free on the host. - -```bash -version: "2.4" +In this config, UDP port 67 (DHCPv4) and/or 547 (DHCPv6) must be free on the host. +```yaml services: ############# ##DHCPRelay## ############# - + #DHCPRelay - DHCP Relay between host network and Docker bridge dhcprelay: image: modem7/dhcprelay:latest container_name: DHCPRelay - command: ["-id", "eno1", "-iu", "br_pihole", "172.33.0.100"] #https://fedoramagazine.org/build-network-bridge-fedora/ + environment: + DHCRELAY_DOWN_INTERFACE: eno1 + DHCRELAY_UP_INTERFACE: br_pihole #https://fedoramagazine.org/build-network-bridge-fedora/ + DHCRELAY_SERVERS: 172.33.0.100 + cap_drop: + - ALL cap_add: - - NET_ADMIN + - NET_RAW + - NET_BIND_SERVICE network_mode: host restart: always mem_limit: 20m mem_reservation: 5m ``` +The container runs as a non-root user; `NET_RAW` (to open the relay's raw socket) and +`NET_BIND_SERVICE` (to bind port 67 as non-root) are the only capabilities it needs - +`cap_drop: ALL` removes everything else. + +If you'd rather pass `dhcrelay` flags directly (e.g. to replicate an existing setup, or use flags +the env vars don't cover), override `command:` instead - any command given is passed straight +through to `dhcrelay`, bypassing the env vars entirely: + +```yaml + command: ["-id", "eno1", "-iu", "br_pihole", "172.33.0.100"] +``` + +## Environment variables + +| Variable | Required | Description | +| --- | :---: | --- | +| `DHCRELAY_DOWN_INTERFACE` | Yes | Downstream (client-facing) interface. | +| `DHCRELAY_UP_INTERFACE` | Yes | Upstream (server-facing) interface. | +| `DHCRELAY_SERVERS` | DHCPv4 only | Space-separated DHCP server IP(s) to relay to. | +| `DHCRELAY_MODE` | No | `4` (default) or `6` for DHCPv6 relay mode. | +| `DHCRELAY_EXTRA_ARGS` | No | Extra flags appended as-is, e.g. extra `-id`/`-iu` pairs for additional interfaces. | + # Commands explanation https://linux.die.net/man/8/dhcrelay -```bash --i ifname -Listen for DHCPv4/BOOTP queries on interface ifname. Multiple interfaces may be specified by using more than one -i option. If no interfaces are specified on the command line, dhcrelay will identify all network interfaces, eliminating non-broadcast interfaces if possible, and attempt to listen on all of them. --d -Force dhcrelay to run as a foreground process. Useful when running dhcrelay under a debugger, or running out of inittab on System V systems. +## DHCPv4 relay -eno1 -Your NIC (you can find this with ifconfig -a) +```bash +dhcrelay -id eno1 -iu br_pihole 172.33.0.100 +``` +```text +-id ifname Downstream interface: listen for client DHCPv4/BOOTP requests here. +-iu ifname Upstream interface: forward requests towards the DHCP server here. +eno1 Your NIC facing clients (find it with `ip -o link show`). +br_pihole Your Docker network bridge facing the DHCP server. +172.33.0.100 The DHCP server's IP address - typically your PiHole bridge IP. +``` --u [address%]ifname -Specifies the ''upper'' network interface for DHCPv6 relay mode: the interface to which queries from clients and other relay agents should be forwarded. At least one -u option must be included in the command line when running in DHCPv6 mode. The interface name ifname is a mandatory parameter. The destination unicast or multicast address can be specified by address%; if not specified, the relay agent will forward to the DHCPv6 All_DHCP_Relay_Agents_and_Servers multicast address. +## DHCPv6 relay + +```bash +dhcrelay -6 -id eno1 -iu br_pihole +``` +```text +-6 DHCPv6 relay mode. +-id ifname Downstream interface: listen for client requests here. +-iu ifname Upstream interface: the address or interface to forward to. Defaults to the + DHCPv6 All_DHCP_Relay_Agents_and_Servers multicast address if no address is given. +``` -br_pihole -Your Docker network bridge name. +## Shared flags -172.33.0.100 -The destination IP address for the packets. Typically your PiHole bridge IP address. +```text +-d Force dhcrelay to run in the foreground - this is how the container's entrypoint + always runs it, so container logs show relay activity. ``` diff --git a/docker-compose.yml b/docker-compose.yml index 5560229..39dc321 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,21 @@ ############# ##DHCPRelay## ############# - + #DHCPRelay - DHCP Relay between host network and PiHole bridge +services: dhcprelay: image: modem7/dhcprelay:latest container_name: DHCPRelay - command: ["-id", "eno1", "-iu", "br_pihole", "172.33.0.100"] #https://fedoramagazine.org/build-network-bridge-fedora/ + environment: + DHCRELAY_DOWN_INTERFACE: eno1 + DHCRELAY_UP_INTERFACE: br_pihole #https://fedoramagazine.org/build-network-bridge-fedora/ + DHCRELAY_SERVERS: 172.33.0.100 + cap_drop: + - ALL cap_add: - - NET_ADMIN + - NET_RAW + - NET_BIND_SERVICE network_mode: host restart: always mem_limit: 20m diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..eef9f8d --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/sh +set -eu + +# Passthrough: any args given (e.g. via compose `command:`) go straight to +# dhcrelay, unchanged - this keeps existing configs working as-is. +if [ "$#" -gt 0 ]; then + exec dhcrelay -d "$@" +fi + +# Otherwise build the command line from env vars, so the image is usable +# without hand-editing a compose `command:` array. +if [ -z "${DHCRELAY_DOWN_INTERFACE:-}" ] || [ -z "${DHCRELAY_UP_INTERFACE:-}" ]; then + echo "dhcrelay: no arguments and no DHCRELAY_* env vars set." >&2 + echo "Set DHCRELAY_DOWN_INTERFACE and DHCRELAY_UP_INTERFACE (and DHCRELAY_SERVERS for DHCPv4), or pass dhcrelay flags directly as the container command." >&2 + exit 1 +fi + +set -- -id "$DHCRELAY_DOWN_INTERFACE" -iu "$DHCRELAY_UP_INTERFACE" + +if [ "${DHCRELAY_MODE:-4}" = "6" ]; then + set -- -6 "$@" +else + if [ -z "${DHCRELAY_SERVERS:-}" ]; then + echo "dhcrelay: DHCRELAY_SERVERS is required in DHCPv4 mode (space-separated DHCP server IPs)." >&2 + exit 1 + fi + # Intentional word-splitting: DHCRELAY_SERVERS is a space-separated list. + # shellcheck disable=SC2086 + set -- "$@" $DHCRELAY_SERVERS +fi + +# Intentional word-splitting: DHCRELAY_EXTRA_ARGS is a space-separated list. +# shellcheck disable=SC2086 +exec dhcrelay -d "$@" ${DHCRELAY_EXTRA_ARGS:-} diff --git a/renovate.json b/renovate.json index 19dad9a..1832612 100644 --- a/renovate.json +++ b/renovate.json @@ -1,7 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["config:base"], - "assignees": ["modem7"], - "labels": ["dependencies"], - "timezone": ["Europe/London"] + "extends": ["github>modem7/renovate-config"] } diff --git a/version_check.txt b/version_check.txt deleted file mode 100644 index e19c309..0000000 --- a/version_check.txt +++ /dev/null @@ -1 +0,0 @@ -docker run -it --rm alpine:edge sh -c "apk update && clear && apk info -d dhcrelay" \ No newline at end of file From 1caaf8ef8a22fcf9abe78f6343327ab361bb7aba Mon Sep 17 00:00:00 2001 From: modem7 Date: Sat, 8 Aug 2026 13:54:04 +0100 Subject: [PATCH 2/2] README: summarize this update's changes, note repo is moving to Kea Adds a maintenance-mode notice with a placeholder link to the future Kea-based repo, and a "What changed" summary of the non-root/healthcheck/ env-var/freshness-check work from this PR. --- README.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 23a871e..deda0d1 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,29 @@ The Internet Systems Consortium DHCP Relay Agent, dhcrelay, provides a means for More info can be found here: https://linux.die.net/man/8/dhcrelay -> **Note:** upstream ISC-DHCP (including `dhcrelay`) has had no releases since 2022 and is EOL - -> see [#63](https://github.com/modem7/DHCP-Relay/issues/63). This image is built on Debian, which -> continues to backport security fixes to its packaged `isc-dhcp-relay` even though upstream -> doesn't. There's no drop-in replacement for `dhcrelay`'s simple CLI-flag relay model yet; ISC's -> own recommended successor, [Kea](https://www.isc.org/kea/), uses a different JSON-config -> paradigm and would be a separate image. +> [!IMPORTANT] +> **This repo is now in maintenance mode.** The changes below are the last planned update here. +> Upstream ISC-DHCP (including `dhcrelay`) has had no releases since 2022 and is EOL - see +> [#63](https://github.com/modem7/DHCP-Relay/issues/63). Rather than keep patching around a dead +> upstream, future work is moving to [Kea](https://www.isc.org/kea/), ISC's supported successor, +> in a new repo: **[modem7/kea-dhcp-relay](#) _(placeholder - link to be added once that repo +> exists)_**. This image will keep receiving Debian's security backports (see the weekly freshness +> check below) but no further feature work is planned here. + +## What changed in this update + +- Base image moved from Alpine (which dropped the `dhcrelay` package entirely as of 3.21) to + `debian:trixie-slim`, which still packages and security-patches `isc-dhcp-relay`. +- The container now runs as a **non-root user**, with only the two capabilities it actually + needs (`NET_RAW`, `NET_BIND_SERVICE`) - verified by testing, not just added out of caution. +- A real `HEALTHCHECK` (process-liveness based) replaces the old commented-out one, which + wouldn't have worked against `dhcrelay`'s raw-socket relay model. +- Configuration can now be done via `DHCRELAY_*` environment variables instead of hand-editing + the compose `command:` array (the old style still works unchanged - see below). +- A weekly check compares Debian's current `isc-dhcp-relay` version against the published image + tag and opens a tracking issue if it's drifted, so security patches don't go unnoticed. +- CI/build tagging now reflects the actual `isc-dhcp-relay` version baked into the image (e.g. + `4.4.3`) instead of a hardcoded, driftable tag. # Tags | Tag | Description |