Compare commits

...

No commits in common. "nextdns-1.7.1" and "main" have entirely different histories.

218 changed files with 9457 additions and 410 deletions

9
.gitattributes vendored
View File

@ -1,9 +0,0 @@
*.md filter=lfs diff=lfs merge=lfs -text
*.sh filter=lfs diff=lfs merge=lfs -text
*.service filter=lfs diff=lfs merge=lfs -text
*.conflist filter=lfs diff=lfs merge=lfs -text
*.yml filter=lfs diff=lfs merge=lfs -text
*.conf filter=lfs diff=lfs merge=lfs -text
*.gitignore filter=lfs diff=lfs merge=lfs -text
*.deb filter=lfs diff=lfs merge=lfs -text
* text !filter !merge !diff

7
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,7 @@
podman-update/build @mazzy89 @boostchicken
run-pihole @boostchicken
on_boot_scripts @boostchicken
wireguard-go @boostchicken
dns-common @boostchicken
container-commmon @boostchicken
on-boot-script/remote_install.sh @gtrabanco

4
.github/FUNDING.yml vendored
View File

@ -1,4 +0,0 @@
# These are supported funding model platforms
github: boostchicken
custom: ["paypal.me/boostchicken"]

44
.github/workflows/nextdns.yml vendored Normal file
View File

@ -0,0 +1,44 @@
# This is a basic workflow to help you get started with Actions
name: NextDNS container
# Controls when the action will run.
on:
workflow_dispatch:
# Triggers the workflow on push or pull request events but only for the master branch
push:
paths:
- nextdns/docker/Dockerfile
schedule:
- cron: "0 0 */15 * *"
jobs:
buildx:
runs-on: ubuntu-latest
steps:
- name: Set the version
id: set_version
run: |
echo VERSION=$(curl --silent "https://api.github.com/repos/nextdns/nextdns/releases/latest" | jq -r '.["tag_name"]')>> $GITHUB_ENV
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
-
name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: build pihole $VERSION
run: docker buildx build --platform=linux/amd64,linux/arm64 --build-arg VERSION=${{ env.VERSION }} nextdns/docker -t boostchicken/nextdns:latest -t boostchicken/nextdns:${{ env.VERSION }} --push

41
.github/workflows/pihole-dote.yml vendored Normal file
View File

@ -0,0 +1,41 @@
# This is a basic workflow to help you get started with Actions
name: Pihole DoTE Container
# Controls when the action will run.
on:
workflow_dispatch:
# Triggers the workflow on push or pull request events but only for the master branch
push:
paths:
- run-pihole/DoTE.Dockerfile
schedule:
- cron: "0 0 */15 * *"
jobs:
buildx:
runs-on: ubuntu-latest
steps:
- name: Set the version
id: set_version
run: |
echo VERSION=$(curl --silent "https://api.github.com/repos/pi-hole/docker-pi-hole/releases/latest" | jq -r '.["tag_name"]')>> $GITHUB_ENV
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
-
name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: build pihole dote
run: docker buildx build --platform=linux/amd64,linux/arm64 --build-arg VERSION=${{ env.VERSION }} run-pihole -f run-pihole/DoTE.Dockerfile -t boostchicken/pihole-dote:latest -t boostchicken/pihole-dote:${{ env.VERSION }} --push

46
.github/workflows/pihole.yml vendored Normal file
View File

@ -0,0 +1,46 @@
# This is a basic workflow to help you get started with Actions
name: Pihole DoH Container
# Controls when the action will run.
on:
workflow_dispatch:
# Triggers the workflow on push or pull request events but only for the master branch
push:
paths:
- run-pihole/Dockerfile
schedule:
- cron: "0 0 */15 * *"
jobs:
buildx:
runs-on: ubuntu-latest
steps:
- name: Set the version
id: set_version
run: |
echo VERSION=$(curl --silent "https://api.github.com/repos/pi-hole/docker-pi-hole/releases/latest" | jq -r '.["tag_name"]')>> $GITHUB_ENV
-
name: Checkout
uses: actions/checkout@v3
-
name: Set up QEMU
uses: docker/setup-qemu-action@v2
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
version: v0.10.1
-
name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: build pihole $VERSION
run: docker buildx build --provenance=false --platform=linux/amd64,linux/arm64 --build-arg VERSION=${{ env.VERSION }} run-pihole -t boostchicken/pihole:latest -t boostchicken/pihole:${{ env.VERSION }} --push

56
.github/workflows/podman-udm.yml vendored Normal file
View File

@ -0,0 +1,56 @@
name: UDM Podman
on:
workflow_dispatch:
push:
branches:
- 'main'
paths:
- 'podman-update/build/Dockerfile'
- 'podman-update/build/podman.Makefile.UDM-Base.patch'
- 'podman-update/build/*.conf'
- 'podman-update/build/*.json'
pull_request_target:
types:
- opened
paths:
- 'podman-update/build/Dockerfile'
- 'podman-update/build/podman.Makefile.UDM-Base.patch'
- 'podman-update/build/*.conf'
- 'podman-update/build/*.json'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Docker Setup QEMU
uses: docker/setup-qemu-action@v2.1.0
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.5.0
- name: Build the Docker image
run: DOCKER_BUILDKIT=1 docker build --file podman-update/build/Dockerfile --build-arg UDM_PLATFORM=UDM-Base --tag boostchicken:udm-podman podman-update/build/
- name: Docker Extract
id: extract
uses: boostchicken-dev/actions-docker-extract@v3
with:
# Docker Image to extract files from
image: boostchicken:udm-podman
# Path (from root) to a file or directory within Image
path: /tmp/install/.
- name: Generate new tag version
id: version
uses: flynshue/version-action@v0.0.1
- name: Upload Podman Install
uses: actions/upload-artifact@v3.1.2
with:
path: ${{ steps.extract.outputs.destination }}
name: podman-udm-${{ steps.version.outputs.version }}
retention-days: 90

57
.github/workflows/podman-udmp-udmse.yml vendored Normal file
View File

@ -0,0 +1,57 @@
name: UDM-SE/PRO Podman
on:
workflow_dispatch:
push:
branches:
- 'main'
paths:
- 'podman-update/build/Dockerfile'
- 'podman-update/build/podman.Makefile.UDM-Pro-SE.patch'
- 'podman-update/build/*.conf'
- 'podman-update/build/*.json'
pull_request_target:
types:
- opened
paths:
- 'podman-update/build/Dockerfile'
- 'podman-update/build/podman.Makefile.UDM-Pro-SE.patch'
- 'podman-update/build/*.conf'
- 'podman-update/build/*.json'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker Setup QEMU
uses: docker/setup-qemu-action@v3.0.0
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Build the Docker image
run: DOCKER_BUILDKIT=1 docker build --file podman-update/build/Dockerfile --build-arg UDM_PLATFORM=UDM-Pro-SE --tag boostchicken:udm-podman podman-update/build/
- name: Docker Extract
id: extract
uses: boostchicken-dev/actions-docker-extract@v3
with:
# Docker Image to extract files from
image: boostchicken:udm-podman
# Path (from root) to a file or directory within Image
path: /tmp/install/.
- name: Generate new tag version
id: version
uses: flynshue/version-action@v0.0.1
- name: Upload Podman Install
uses: actions/upload-artifact@v4
with:
path: ${{ steps.extract.outputs.destination }}
name: podman-udmse-udmpro-${{ steps.version.outputs.version }}
retention-days: 90

5
.gitignore vendored
View File

@ -1 +1,6 @@
/.idea/
/**/debian/files
/**/debian/*.substvars
debhelper-build-stamp
.debhelper
Wiki_Wireguard.md

View File

@ -2,41 +2,66 @@
## Features
1. Run AdguardHome on your UDM with a completely isolated network stack. This will not port conflict or be influenced by any changes on by Ubiquiti
1. Run AdguardHome on your UDM with a completely isolated network stack. This will not port conflict or be influenced by any changes on by Ubiquiti
2. Persists through reboots and firmware updates.
## Requirements
1. You have setup the on boot script described [here](https://github.com/boostchicken/udm-utilities/tree/master/on-boot-script)
1. AdguardHome persists through firmware updates as it will store the configuration in a folder (you need to create this). It needs 2 folders, a Work and Configuration folder. Please create the 2 folders in "/mnt/data/". In my example I created "AdguardHome-Confdir" and "AdguardHome-Workdir"
1. You have setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
1. AdguardHome persists through firmware updates as it will store the configuration in a folder (you need to create this). It needs 2 folders, a Work and Configuration folder. Please create the 2 folders in "/data/". In my example I created "AdguardHome-Confdir" and "AdguardHome-Workdir"
## Customization
* Feel free to change [20-dns.conflist](../cni-plugins/20-dns.conflist) to change the IP address of the container.
* Update [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) with your own values
* If you want IPv6 support use [20-dnsipv6.conflist](../cni-plugins/20-dnsipv6.conflist) and update [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) with the IPv6 addresses. Also, please provide IPv6 servers to podman using --dns arguments.
- Feel free to change [20-dns.conflist](../cni-plugins/20-dns.conflist) to change the IP and MAC address of the container.
- Update [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) with your own values
- If you want IPv6 support use [20-dnsipv6.conflist](../cni-plugins/20-dnsipv6.conflist) and update [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) with the IPv6 addresses. Also, please provide IPv6 servers to podman using --dns arguments.
## Steps
1. On your controller, make a Corporate network with no DHCP server and give it a VLAN. For this example we are using VLAN 5.
1. Copy [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) to /mnt/data/on_boot.d and update its values to reflect your environment
1. Execute /mnt/data/on_boot.d/10-dns.sh
1. Copy [20-dns.conflist](../cni-plugins/20-dns.conflist) to /mnt/data/podman/cni. This will create your podman macvlan network
1. Run the AdguardHome docker container, be sure to make the directories for your persistent AdguardHome configuration. They are mounted as volumes in the command below.
Please note if you have firmware v2 or above you have to copy all files into /data instead of /mnt/data. You can see what version you are running by running: ubnt-device-info firmware
```shell script
mkdir /mnt/data/AdguardHome-Confdir
mkdir /mnt/data/AdguardHome-Workdir
podman run -d --network dns --restart always \
--name adguardhome \
-v "/mnt/data/AdguardHome-Confdir/:/opt/adguardhome/conf/" \
-v "/mnt/data/AdguardHome-Workdir/:/opt/adguardhome/work/" \
--dns=127.0.0.1 --dns=1.1.1.1 \
--hostname adguardhome \
adguard/adguardhome:latest
```
1. Check if you have either `/mnt/data/` or `/data/` and use the correct one below.
2. Copy [05-install-cni-plugins.sh](../cni-plugins/05-install-cni-plugins.sh) to /data/on_boot.d
3. On your controller, make a Corporate network with no DHCP server and give it a VLAN. For this example we are using VLAN 5. You should confirm the bridge is created for this VLAN by running `netstat -r` otherwise the script will fail. If it is not there, initiate a provisioning of the UDM (Controller > UDM > Config > Manage Device > Force provision).
4. Copy [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) to `/data/on_boot.d` and update its values to reflect your environment
5. Copy [20-dns.conflist](../cni-plugins/20-dns.conflist) to `/data/podman/cni` after generating a MAC address. This will create your podman macvlan network.
6. Execute /data/on_boot.d/05-install-cni-plugins.sh
7. Execute `/data/on_boot.d/10-dns.sh`
8. Run the AdguardHome docker container, be sure to make the directories for your persistent AdguardHome configuration. They are mounted as volumes in the command below.
1. Browse to 10.0.5.3:3000 and follow the setup wizard
1. Update your DNS Servers to 10.0.5.3 (or your custom ip) in all your DHCP configs.
1. Access the AdguardHome like you would normally.
```shell script
mkdir /data/AdguardHome-Confdir
mkdir /data/AdguardHome-Workdir
podman run -d --network dns --restart always \
--name adguardhome \
-v "/data/AdguardHome-Confdir/:/opt/adguardhome/conf/" \
-v "/data/AdguardHome-Workdir/:/opt/adguardhome/work/" \
--dns=127.0.0.1 --dns=1.1.1.1 \
--hostname adguardhome \
adguard/adguardhome:latest
```
9. Browse to 10.0.5.3:3000 and follow the setup wizard
10. Update your DNS Servers to 10.0.5.3 (or your custom ip) in all your DHCP configs.
11. Access the AdguardHome like you would normally.
## Troubleshooting
If you get the following error:
```
Error adding network: failed to create macvlan: cannot assign requested address
```
When starting the container then the MAC address you generated is not good. You can cheat at this point and look at the address of `br$VLAN.mac` with `ifconfig br$VLAN.mac` and use that value.
To start over you must remove the container and the macvlan device:
```
podman container rm adguardhome
podman network rm dns -f # expect an error here
ip link delete br$VLAN.mac
```
You can now run `10-dns.sh` again and start the container again.

128
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
Slack (https://join.slack.com/t/boostchicken/shared_invite/zt-fcjszaw4-2ZuNFxIQnrpjxixnm17LXQ).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

3
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,3 @@
All pull requests on any content are welcome!
Anything you find useful.
I will review all PRs, just please include what your changes does and why you did it.

154
README.md
View File

@ -1,62 +1,168 @@
# udm-utilities [![Slack](https://img.shields.io/badge/slack-boostchicken-blue.svg?logo=slack "Boostchicken Slack")](https://join.slack.com/t/boostchicken/shared_invite/zt-fcjszaw4-2ZuNFxIQnrpjxixnm17LXQ)
# unifios-utilities [![Discord](https://img.shields.io:/discord/939817841107034172?label=Discord&logo=Discord&style=for-the-badge "Discord")](https://discord.gg/8zqrQJFghg) [![!Cloudflare](https://img.shields.io/badge/Cloudflare-F38020?style=for-the-badge&logo=Cloudflare&logoColor=white)](https:///www.cloudflare.com)
A collection of things to enhance the capabilities of your Unifi Dream Machine or Dream Machine Pro.
[![UDM Podman](https://github.com/unifi-utilities/unifios-utilities/actions/workflows/podman-udm.yml/badge.svg)](https://github.com/unifi-utilities/unifios-utilities/actions/workflows/podman-udm.yml)
[![UDM-Pro-SE Podman](https://github.com/unifi-utilities/unifios-utilities/actions/workflows/podman-udmp-udmse.yml/badge.svg?branch=main)](https://github.com/unifi-utilities/unifios-utilities/actions/workflows/podman-udmp-udmse.yml)
## Contributing
## Branches
1. [1.12.x](https://github.com/unifi-utilities/unifios-utilities/tree/v1.12.x) - Support for 1.x.x firmware line
1. [main](https://github.com/unifi-utilities/unifios-utilities) - Support for 2.4.x and above
Pull Requests welcome! If you use this functionality to do new cool stuff to your UDM/P please send a PR and share it with the community!
### Current Branch is main, supporting UniFi OS 2.5.x
A collection of things to enhance the capabilities of your Unifi Dream Machine, Dream Machine Pro or UXG-Pro.
### ⚠️ Breaking Changes for UniFi OS 3.x
UniFi OS 3.x no longer supports podman. The utilities in this respository **may not work as documented**. For alternatives, review the documentation in [nspawn-container](https://github.com/unifi-utilities/unifios-utilities/tree/main/nspawn-container) or consider direct installations like [wpa_supplicant-UniFi-OS-3.x for AT&T Fiber](https://github.com/jphamdev/wpa_supplicant-UniFi-OS-3.x).
-----
## Custom Kernel
If you want to do a custom kernel with wireguard support, multicast, multipath routing that is now a possiblity.
Please see the repo and please use at your own risk. This a much larger change than anything in this repo.
[udm-kernel-tools](https://github.com/fabianishere/udm-kernel-tools)
## Custom Podman Builds for UDM-SE
All artifacts can be found on IPFS
[IPFS Gateway](https://unifi.boostchicken.io) ![Cloudflare](https://img.shields.io/badge/Cloudflare-F38020?style=for-the-badge&logo=Cloudflare&logoColor=white)
Extract the zip to the root of your device!
Look at the assets on the Podman workflow.
### UDM Base
Standard Image for base UDM, systemd removed
### UDM Pro / SE
Base build with apparmor, systemd, devicemapper removal, and overlay kept
Works on PRO on 2.x, for 1.x use the UDM Base still.
*Does not work on 3.x use nspawn-container*
## macvlan kernel module for UDR
Ui have stopped building the `macvlan` kernel module into the kernel for the UDR, which means containers cannot
have their own routable IPs out of the box. This module is being built and distributed separately, and can be found
at [macvlan-unifi-udr](https://github.com/whi-tw/macvlan-unifi-udr).
## General Tools
### on-boot-script
### on-boot-script-2.x
Do this first. Enables `init.d` style scripts to run on every boot of your UDM.
Includes examples to run `wpa-supplicant/eap-proxy` and/or `ntop-ng` on startup.
Follow this [readme](https://github.com/unifi-utilities/unifios-utilities/blob/main/on-boot-script/README.md).
Enables init.d style scripts to run on every boot of your UDM. Includes a wpa-supplicant/eap-proxy example.
**It enables complete customization of your UDM/P and fills the gap that config.gateway.json left behind.**
### nspawn-container
Enables containers on UniFiOS 3.x, this replaces podman.
### podman-update
Updates Podman, conmon, and runc to a recent version.This allows docker-compose usage as well.
Works on PRO on 2.x, for 1.x use the UDM Base still.
**Does not working on 3.x use nspawn-container**
### container-common
Apply this after on-boot-script.
Updates container defaults to maintain **stable disk usage footprint** of custom containers.
**Prevents logs filling up UDM storage full**.
### python
If you need python3 on your UDM, generally not recommended, can always use it in unifi-os container
If you need python3 on your UDM, generally not recommended, can always use it in unifi-os container.
## VPN Servers / Clients
| Name | URL | Description |
|------ |----- |------------- |
|wireguard-go | | Run a Wireguard client/server |
| WireGuard kernel module | <https://github.com/tusc/wireguard-kmod> | Uses a prebuilt linux kernel module, without the need to move to a custom kernel. |
| OpenConnect VPN | <https://github.com/shuguet/openconnect-udm> | OpenConnect VPN Client for the UniFi Dream Machine Pro (Unofficial).|
| split-vpn | <https://github.com/peacey/split-vpn> |A split tunnel VPN script for the UDM with policy based routing. This helper script can be used on your UDM to route select VLANs, clients, or even domains through a VPN connection. It supports OpenVPN, WireGuard, and OpenConnect (Cisco AnyConnect) clients running directly on your UDM, and external VPN clients running on other servers on your network. |
| Zerotier | <https://zerotier.com> |ZeroTier provides network control and P2P functionality · Use ZeroTier to create products which run on their own decentralized networks |
### wireguard-go
Run a Wireguard client/server on your UDM/P. Utilizes wireguard-go, not linux kernel modules. The performance will take a hit due to that.
## DNS Providers
Install a DNS server that functions as a network-wide ad and tracker blocker, and which can also securely proxy encrypted DNS requests to an upstream DNS provider.
Begin by following the instructions to setup [on-boot-script](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script) and [dns-common](https://github.com/unifi-utilities/unifios-utilities/tree/main/dns-common/on_boot.d).
Then, follow the guides below to setup either Pi-Hole, NextDNS, or AdGuard Home.
### dns-common
Configurations for DNS containers, both IPv4 and IPv6. Utilizes MacVLAN CNI plugins to completely isolate the network stack.
### run-pihole
Run pihole on your UDM with podman.
Base configuration for DNS server containers, both IPv4 and IPv6.
Utilizes MacVLAN CNI plugins to completely isolate the network stack.
### nextdns
Run NextDNS on your UDM with podman.
### run-pihole
[![!Docker Pulls](https://img.shields.io/docker/pulls/boostchicken/pihole.svg?color=green&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=pulls&logo=docker)](https://hub.docker.com/u/boostchicken)
PiHole w/ DoH Image.
Run Pi-hole on your UDM with podman.
Also contains custom image for Pi-hole with `cloudflared`.
### PiHole with DoTe
[![!Docker Pulls](https://img.shields.io/docker/pulls/pombeirp/pihole-dote.svg?color=green&labelColor=555555&logoColor=ffffff&style=for-the-badge&label=pulls&logo=docker)](https://hub.docker.com/r/pombeirp/pihole-dote)
Designed by: <https://github.com/chrisstaite/DoTe/>
Alternative to mine which uses DoTe
### AdguardHome
Run AdguardHome on your UDM with podman.
### Cloudflare DDNS
![Cloudflare](https://img.shields.io/badge/Cloudflare-F38020?style=for-the-badge&logo=Cloudflare&logoColor=white)
Update your cloudflare domains from your UDM with podman.
## Cool projects you can use with this
### multicast-relay
| Name | URL | Description |
|------ |----- |------------- |
|multicast-relay |<https://hub.docker.com/r/scyto/multicast-relay> | This is a docker container that implements <https://github.com/alsmith/multicast-relay> to provide mDNS and SSDP on a unifi dream machine. It will likely work on any multi homed host. |
| [mosquitto](./mosquitto/) | <https://hub.docker.com/_/eclipse-mosquitto> | Eclipse Mosquitto is an open source **MQTT message broker** |
| ntopng | <https://github.com/tusc/ntopng-udm> | Much better network stats for your UDM/P! Install this docker container and create an on_boot script to make sure it's always running. |
| LetsEncrypt | <https://github.com/kchristensen/udm-le> |Provision and renew LetsEncrypt SSL certs from your UDM/P. |
| ubios-cert | <https://github.com/alxwolf/ubios-cert> | Provision and renew SSL/TLS certificates from LetsEncrypt, ZeroSSL, BuyPass, Google and any other RFC8555-compliant CA. Runs `acme.sh` on your UDM, UDM Pro, UDM SE or UDR. No podman required, supports both V1.x and V2.x firmwares. Secure your HTTPS connections to device, WiFiman and Guest Portal. |
| Unifi API Browser | <https://hub.docker.com/r/scyto/unifibrowser> | This is a docker container that implements <https://github.com/Art-of-WiFi/UniFi-API-browser> to provide a graphical tool to inspect the data structures available via the unifi API.Great if you are using the REST API for your own purposes and want to explore.Works with multiple controller versions. |
|ubnt-auto-fan-speed |<https://github.com/renedis/ubnt-auto-fan-speed> | A shell script with the goal to make the UDM-Pro silenced while still having good thermal values. |
|rclone | <https://rclone.org/> |Run rclone container with Web GUI for offsite backups. |
|udm-proxy | <https://github.com/xpherism/udm-proxy> |Run a reverse proxy (using caddy in vlan) on the udm-pro. |
| Telegram-Notifications On WAN Failover | <https://github.com/fire1ce/UDM-Failover-Telegram-Notifications> | Use telegram bot to be notified of a wan failover with local account|
<https://hub.docker.com/r/scyto/multicast-relay>
[![!Protected by Cloudflare](https://github.com/unifi-utilities/unifios-utilities/assets/427295/5cda2367-fbda-438e-b942-2ebf4a105b82)](https://cloudflare.com)
This is a docker container that implements <https://github.com/alsmith/multicast-relay> to provide mDNS and SSDP on a unifi dream machine. It will likely work on any multi homed host.
### ntopng
## Unsupported / No longer maintained
<https://github.com/tusc/ntopng-udm>
Much better network stats for your UDM/P! Install this docker container and create an on_boot script to make sure it's always running.
| Name | URL | Description |
|------ |----- |------------- |
|suricata | | Updates suricata to a recent version. Now in firmware |
| Jumbo Frames | <https://github.com/kalenarndt/udmp-jumbo-frames> | native jumbo frame support for the UDM and UDM-Pro is added in the 1.12.13 EA firmware, support for the UDM-SE is not yet announced. |
| UDM Persistent SSH Keys Script | <https://github.com/fire1ce/UDM-Persistent-SSH-Keys> | Stores SSH Keys. This functionality is now in firmware
### LetsEncrypt SSL Certs
## Reimaging your UDM
<https://github.com/kchristensen/udm-le>
Working in the shell means that mistakes can happen. Deleted directories or packages may break the underlying software that makes your UDM-Pro SE function as designed. Thankfully, Unifi Support seems to have provided the following process to help bring your UDM back to the stock image.
Provision and renew LetsEncrypt SSL certs from your UDM/P
1. Remove the unit from your network and disconnect the cables from the unit.
2. Press down the reset button for 40+ seconds without power and cables.
3. Release the reset button and power the unit.
4. Again press the reset button for 15+ seconds.
Thanks to user [cfallwell](https://github.com/cfallwell) for describing this fix [here](https://github.com/unifi-utilities/unifios-utilities/issues/428#issuecomment-1386212026).

101
att-ipv6/10-att-ipv6.sh Executable file
View File

@ -0,0 +1,101 @@
#! /bin/bash
set -eo pipefail
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "$DATA_DIR/att-ipv6" ]; then
# If it does not exist, create the directory
mkdir -p "$DATA_DIR/att-ipv6"
echo "Directory '$DATA_DIR/att-ipv6' created."
else
# If it already exists, print a message
echo "Directory '$DATA_DIR/att-ipv6' already exists. Moving on."
fi
wan_iface="eth8" # "eth9" for UDM Pro WAN2
vlans="br0" # "br0 br100 br101..."
domain="example.invalid" # DNS domain
dns6="[2001:4860:4860::8888],[2001:4860:4860::8844]" # Google
CONTAINER=att-ipv6
confdir=${DATA_DIR}/att-ipv6
# main
mkdir -p "${confdir}/dhcpcd"
test -f "${confdir}/dhcpcd.conf" || {
: >"${confdir}/dhcpcd.conf.tmp"
cat >>"${confdir}/dhcpcd.conf.tmp" <<EOF
allowinterfaces ${wan_iface}
nodev
noup
ipv6only
nooption domain_name_servers
nooption domain_name
duid
persistent
option rapid_commit
option interface_mtu
require dhcp_server_identifier
slaac private
noipv6rs
interface ${wan_iface}
ipv6rs
ia_na 0
EOF
ix=0
for vv in $vlans; do
echo " ia_pd ${ix} ${vv}/0"
ix=$((ix + 1))
done >>"${confdir}/dhcpcd.conf.tmp"
mv "${confdir}/dhcpcd.conf.tmp" "${confdir}/dhcpcd.conf"
}
test -f "${confdir}/att-ipv6-dnsmasq.conf" || {
: >"${confdir}/att-ipv6-dnsmasq.conf.tmp"
cat >>"${confdir}/att-ipv6-dnsmasq.conf.tmp" <<EOF
#
# via att-ipv6
#
enable-ra
no-dhcp-interface=lo
no-ping
EOF
for vv in $vlans; do
cat <<EOF
interface=${vv}
dhcp-range=set:att-ipv6-${vv},::2,::7d1,constructor:${vv},slaac,ra-names,64,86400
dhcp-option=tag:att-ipv6-${vv},option6:dns-server,${dns6}
domain=${domain}|${vv}
ra-param=${vv},high,0
EOF
done >>"${confdir}/att-ipv6-dnsmasq.conf.tmp"
mv "${confdir}/att-ipv6-dnsmasq.conf.tmp" "${confdir}/att-ipv6-dnsmasq.conf"
}
if podman container exists "$CONTAINER"; then
podman start "$CONTAINER"
else
podman run -d --restart=always --name "$CONTAINER" -v "${confdir}/dhcpcd.conf:/etc/dhcpcd.conf" -v "${confdir}/dhcpcd:/var/lib/dhcpcd" --net=host --privileged ghcr.io/michaelw/dhcpcd
fi
# Fix DHCP, assumes DHCPv6 is turned off in UI
cp "${confdir}/att-ipv6-dnsmasq.conf" /run/dnsmasq.conf.d/
start-stop-daemon -K -q -x /usr/sbin/dnsmasq

130
att-ipv6/README.md Normal file
View File

@ -0,0 +1,130 @@
# AT&T IPv6
On ATT IPv6, the RG (residential gateway) receives a /60 prefix itself, but only hands out one /64 to routers in IP Passthrough mode, regardless how big of a prefix was requested. The RG keeps the lower 8 /64s for its own purposes (`2600:1700:X:yyy0::/63`), and Unifi normally only receives `2600:1700:X:yyyf::/64`.
This script enables UDM to receive up to 8 PDs on ATT IPv6 (tested with RG BGW320-500), usually starting at `2600:1700:X:yyyf::/64` down to `2600:1700:X:yyy8::/64`.
Note that these may not always be assigned contiguous or in order.
The price to pay is that almost none of the IPv6 support native to UDM remains enabled, hence options like DHCPv6 cannot be changed in the UI anymore.
Firewall and routing rules remain functional, however.
## Requirements
1. You have successfully setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
2. You must set up the ATT RG in ["IP Passthrough" mode](https://patrickdomingues.com/2022/09/03/udm-pro-vpn-on-att-fiber-bgw320/)
3. You must turn off IPv6 on the ATT WAN connection, AND on each network/VLAN (IPv6 Interface Type: None)
4. You must add Firewall rules equivalent to (this can be done in the UI, select `Internet v6 Local` chain)
```
-A UBIOS_WAN_LOCAL_USER -p udp -m udp --sport 547 --dport 546 -j RETURN # select IPv6 Protocol "UDP" and create port groups for source port 547 and dest port 546
-A UBIOS_WAN_LOCAL_USER -p ipv6-icmp -m icmp6 --icmpv6-type 134 -j RETURN # select IPv6 Protocol "ICMPv6" and IPv6ICMP Type Name "Router Advertisement"
```
5. You may want to add a "Traffic Management" route on your ATT WAN device to access 192.168.1.254/32, so that you can access the RG after it is in passthrough mode.
## Customization
Near the top of `10-att-ipv6.sh`:
```sh
wan_iface="eth8" # use "eth9" for UDM Pro WAN2
vlans="br0" # "br0 br100 br101..."
domain="example.invalid" # DNS domain
dns6="[2001:4860:4860::8888],[2001:4860:4860::8844]" # Google
```
This generates configuration files in directory `/data/att-ipv6`, if they don't exist.
The files can be edited, or regenerated by deleting them and re-running the script.
## Installation
```sh
cd /data/on_boot.d
curl -LO https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/HEAD/att-ipv6/10-att-ipv6.sh
chmod +x 10-att-ipv6.sh
./10-att-ipv6.sh
```
The dhcpcd container being used is built [here](https://github.com/michaelw/dhcpcd-container/pkgs/container/dhcpcd)
## Validation
Running the script starts dhcpcd within the `att-ipv6` container on `eth8` (WAN1) and only for the default network (`br0`). This can be customized, see above.
To check that everything is working as expected, and the ATT RG delegates multiple prefixes:
On UDM:
```sh
$ ip -6 r # should see a default route on the WAN interface, and a 2600:1700:X:Y::/64 prefix on each configured VLAN bridge interface
2600:1700:X:yyy0::/64 dev eth9 proto ra metric 203 mtu 1500 pref medium
2600:1700:X:yyyb::/64 dev br104 proto dhcp metric 235 pref medium
2600:1700:X:yyyc::/64 dev br103 proto dhcp metric 234 pref medium
2600:1700:X:yyyd::/64 dev br102 proto dhcp metric 233 pref medium
2600:1700:X:yyye::/64 dev br101 proto dhcp metric 232 pref medium
2600:1700:X:yyyf::/64 dev br0 proto dhcp metric 212 pref medium
[...]
```
```sh
$ podman logs att-ipv6 # should see dhcpcd successfully acquiring prefixes
[...]
eth9: writing lease `/var/lib/dhcpcd/eth9.lease6'
eth9: delegated prefix 2600:1700:X:yyyf::/64
eth9: delegated prefix 2600:1700:X:yyye::/64
eth9: delegated prefix 2600:1700:X:yyyd::/64
eth9: delegated prefix 2600:1700:X:yyyc::/64
eth9: delegated prefix 2600:1700:X:yyyb::/64
br0: adding address 2600:1700:X:yyyf::1/64
br0: pltime 3600 seconds, vltime 3600 seconds
br0: executing `/lib/dhcpcd/dhcpcd-run-hooks' DELEGATED6
br101: adding address 2600:1700:X:yyye::1/64
br101: pltime 3600 seconds, vltime 3600 seconds
br101: executing `/lib/dhcpcd/dhcpcd-run-hooks' DELEGATED6
br102: adding address 2600:1700:X:yyyd::1/64
br102: pltime 3600 seconds, vltime 3600 seconds
br102: executing `/lib/dhcpcd/dhcpcd-run-hooks' DELEGATED6
br103: adding address 2600:1700:X:yyyc::1/64
br103: pltime 3600 seconds, vltime 3600 seconds
br103: executing `/lib/dhcpcd/dhcpcd-run-hooks' DELEGATED6
br104: adding address 2600:1700:X:yyyb::1/64
br104: pltime 3600 seconds, vltime 3600 seconds
br104: executing `/lib/dhcpcd/dhcpcd-run-hooks' DELEGATED6
br0: adding route to 2600:1700:X:yyyf::/64
br101: adding route to 2600:1700:X:yyye::/64
br102: adding route to 2600:1700:X:yyyd::/64
br103: adding route to 2600:1700:X:yyyc::/64
br104: adding route to 2600:1700:X:yyyb::/64
lo: deleting reject route to 2600:1700:X:yyyf::/64
lo: deleting reject route to 2600:1700:X:yyye::/64
lo: deleting reject route to 2600:1700:X:yyyd::/64
lo: deleting reject route to 2600:1700:X:yyyc::/64
lo: deleting reject route to 2600:1700:X:yyyb::/64
[...]
```
```sh
$ ps auxw|grep dnsmasq # should see dnsmasq running
```
On BGW320-500, check https://192.168.1.254/cgi-bin/lanstatistics.ha for multiple PDs in `IPv6 Delegated Prefix Subnet (including length)`.
On clients:
```
ip -6 addr show # should see SLAAC and/or DHCPv6 addresses received (if not, check dnsmasq configuration in `/run/dnsmasq.conf.d`)
```
### Useful commands
```sh
# View dhcpcd logs to verify the container is running without error (ipv6 logs from dhcpcd are normal).
podman logs att-ipv6
# Restart dhcpcd (e.g., after configuration change)
podman exec -it dhcpcd -x
# Stop the container
podman stop att-ipv6
# Remove the container
podman rm att-ipv6
```

45
cloudflare-ddns/README.md Normal file
View File

@ -0,0 +1,45 @@
# Cloudflare Dynamic DNS
## Features
- Update Multiple Subdomains
- Proxy your traffic through cloudflare
- Set a ttl
Complete feature list and documentation can be found [here](https://github.com/timothymiller/cloudflare-ddns)
## Requirements
1. You have successfully setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
2. You must have a cloudflare profile with at least one domain.
3. You must have a valid cloudflare api token with correct permissions (see [complete documentation](https://github.com/timothymiller/cloudflare-ddns) for details)
## Customization
Update [config.json](configs/config.json) with the following options:
- your cloudflare api token
- your zone id
- each subdomain you'd like to point at your udm-pro
- Set the proxied flag if you'd like cloudflare to proxy the records
- Set the ttl value you'd like for your records
## Steps
1. Make a directory for your configuration, check if you have `/mnt/data/` or `/data/` and adjust accordingly.
```sh
mkdir -p /data/cloudflare-ddns
```
2. Create a [cloudflare-ddns configuration](configs/config.json) in `/data/cloudflare-ddns` and update the configuration to meet your needs.
3. Copy [30-cloudflare-ddns.sh](on_boot.d/30-cloudflare-ddns.sh) to `/data/on_boot.d`.
. Execute /data/on_boot.d/[30-cloudflare-ddns.sh](on_boot.d/30-cloudflare-ddns.sh)
5. Execute `podman logs cloudflare-ddns` to verify the continer is running without error (ipv6 warnings are normal).
### Useful commands
```sh
# view cloudflare-ddns logs to verify the continer is running without error (ipv6 warnings are normal).
podman logs cloudflare-ddns
```

View File

@ -0,0 +1,23 @@
{
"cloudflare": [
{
"authentication": {
"api_token": "cloudflare_api_token_here",
"api_key": {
"api_key": "api_key_if_you_don't_have_a_token",
"account_email": "your_email_here_if_you_don't_have_a_token"
}
},
"zone_id": "your_zone_id_here",
"subdomains": [
"each",
"subdomain"
],
"proxied": false
}
],
"ttl": 120,
"a": true,
"aaaa": false,
"purgeUnknownRecords": false
}

View File

@ -0,0 +1,38 @@
#!/bin/bash
CONTAINER=cloudflare-ddns
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "$DATA_DIR/cloudflare-ddns" ]; then
# If it does not exist, create the directory
mkdir -p "$DATA_DIR/cloudflare-ddns"
echo "Directory '$DATA_DIR/cloudflare-ddns' created."
else
# If it already exists, print a message
echo "Directory '$DATA_DIR/cloudflare-ddns' already exists. Moving on."
fi
# Starts a cloudflare ddns container that is deleted after it is stopped.
# All configs stored in /data/cloudflare-ddns
if podman container exists "$CONTAINER"; then
podman start "$CONTAINER"
else
podman run -i -d --rm \
--net=host \
--name "$CONTAINER" \
--security-opt=no-new-privileges \
-v $DATA_DIR/cloudflare-ddns/config.json:/config.json \
timothyjmiller/cloudflare-ddns:latest
fi

221
cloudflared/README.md Normal file
View File

@ -0,0 +1,221 @@
# cloudflared
## Features
1. cloudflared tunneling service, aka. Argo Tunnels / Zero Trust / etc
2. cloudflared proxy-dns service, provides DNS-over-HTTPS capability for all DNS traffic out from your UDM-SE
## Requirements
1. You have successfully setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
## Configuration
### cloudflared tunnel
Configuration is required here, otherwise nothing will work.
You need to modify `SERVICE_TOKEN` in `51-cloudflared-tunnel.sh` with the secret token you got when configuring the tunnel in Cloudflare Zero Trust
Run the script and ensure it doesn't error,
```bash
root@UDM-SE:/mnt/data/on_boot.d# ./51-cloudflared-tunnel
Hit:1 https://deb.debian.org/debian bullseye InRelease
Hit:2 https://download.docker.com/linux/debian bullseye InRelease
Hit:3 https://deb.debian.org/debian bullseye-updates InRelease
Hit:4 https://pkg.cloudflare.com/cloudflared bullseye InRelease
Hit:5 https://security.debian.org/debian-security bullseye-security InRelease
Hit:6 https://deb.debian.org/debian bullseye-backports InRelease
Hit:7 https://apt.artifacts.ui.com bullseye InRelease
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
cloudflared is already the newest version (2023.8.2).
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
libltdl7 libslirp0 slirp4netns
Use 'apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
root@UDM-SE:/mnt/data/on_boot.d#
```
Now check that the services are healthy,
```bash
root@UDM-SE:~# systemctl status cloudflared.service
● cloudflared.service - cloudflared
Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2023-10-04 15:59:16 AEST; 2h 51min ago
Main PID: 6060 (cloudflared)
Tasks: 9 (limit: 4724)
Memory: 19.8M
CPU: 21.886s
CGroup: /system.slice/cloudflared.service
└─6060 /usr/bin/cloudflared --no-autoupdate tunnel run --token REMOVED
Oct 04 15:59:16 UDM-SE cloudflared[6060]: 2023-10-04T05:59:16Z INF ICMP proxy will use fe80::d221:f9ff:fe89:c24b in zone eth8 as source for IPv6
Oct 04 15:59:16 UDM-SE cloudflared[6060]: 2023-10-04T05:59:16Z WRN The user running cloudflared process has a GID (group ID) that is not within ping_group_range. You might need to add that user to a group within that range, or instead update the range to encompass a group the user is already in by modifying /proc/sys/net/ipv4/ping_group_r>
Oct 04 15:59:16 UDM-SE cloudflared[6060]: 2023-10-04T05:59:16Z WRN ICMP proxy feature is disabled error="cannot create ICMPv4 proxy: Group ID 0 is not between ping group 1 to 0 nor ICMPv6 proxy: socket: permission denied"
Oct 04 15:59:16 UDM-SE cloudflared[6060]: 2023-10-04T05:59:16Z INF Starting metrics server on 127.0.0.1:38587/metrics
Oct 04 15:59:16 UDM-SE cloudflared[6060]: 2023-10-04T05:59:16Z INF Registered tunnel connection connIndex=0 connection=REMOVED event=0 ip=198.41.200.33 location=syd04 protocol=quic
Oct 04 15:59:16 UDM-SE systemd[1]: Started cloudflared.
Oct 04 15:59:17 UDM-SE cloudflared[6060]: 2023-10-04T05:59:17Z INF Registered tunnel connection connIndex=1 connection=REMOVED event=0 ip=198.41.192.167 location=bne01 protocol=quic
Oct 04 15:59:18 UDM-SE cloudflared[6060]: 2023-10-04T05:59:18Z INF Updated to new configuration config=null version=0
Oct 04 15:59:18 UDM-SE cloudflared[6060]: 2023-10-04T05:59:18Z INF Registered tunnel connection connIndex=2 connection=REMOVED event=0 ip=198.41.200.23 location=syd07 protocol=quic
Oct 04 15:59:19 UDM-SE cloudflared[6060]: 2023-10-04T05:59:19Z INF Registered tunnel connection connIndex=3 connection=REMOVED event=0 ip=198.41.192.67 location=bne01 protocol=quic
root@UDM-SE:~#
```
### cloudflared proxy-dns
Modify the variables in `50-cloudflared-proxy-dns.sh`, the defaults are:
```bash
BIND=127.0.0.53
PORT=53
UPSTREAM="https://1.1.1.1/dns-query https://1.0.0.1/dns-query"
BOOTSTRAP="https://162.159.36.1/dns-query https://162.159.46.1/dns-query https://[2606:4700:4700::1111]/dns-query https://[2606:4700:4700::1001]/dns-query"
ARGS="--metrics ${BIND}: --address ${BIND} --port ${PORT}"
```
No configuration is strictly necessary as the above will work and punch DNS requests out thru the default Cloudflare 1.1.1.1/1.0.0.1 resolvers, only over HTTPS.
You may want to change `UPSTREAM=` if you want to use a different DNS-over-HTTPS resolver.
For example if you are using Cloudflare Zero Trust Gateway services, there will be a location specific hostname for DNS-over-HTTPS, so you would:
Change the default variable value of `UPSTREAM="https://1.1.1.1/dns-query https://1.0.0.1/dns-query"`
To `UPSTREAM="https://UNIQUE_HOSTNAME_FOR_LOCATION.cloudflare-gateway.com/dns-query"`
Run the script,
```bash
root@UDM-SE:/mnt/data/on_boot.d# ./50-cloudflared-proxy-dns
Hit:1 https://deb.debian.org/debian bullseye InRelease
Hit:2 https://deb.debian.org/debian bullseye-updates InRelease
Hit:3 https://deb.debian.org/debian bullseye-backports InRelease
Hit:4 https://download.docker.com/linux/debian bullseye InRelease
Get:5 https://security.debian.org/debian-security bullseye-security InRelease [48.4 kB]
Hit:6 https://pkg.cloudflare.com/cloudflared bullseye InRelease
Hit:7 https://apt.artifacts.ui.com bullseye InRelease
Fetched 48.4 kB in 1s (35.4 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
cloudflared is already the newest version (2023.8.2).
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
libltdl7 libslirp0 slirp4netns
Use 'apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Removed /etc/systemd/system/multi-user.target.wants/cloudflared-proxy-dns.service.
removed '/etc/systemd/system/cloudflared-proxy-dns.service'
Created symlink /etc/systemd/system/multi-user.target.wants/cloudflared-proxy-dns.service → /etc/systemd/system/cloudflared-proxy-dns.service.
root@UDM-SE:/mnt/data/on_boot.d#
```
Now check the status,
```bash
root@UDM-SE:~# systemctl status cloudflared-proxy-dns.service
● cloudflared-proxy-dns.service - DNS over HTTPS (DoH) proxy client
Loaded: loaded (/etc/systemd/system/cloudflared-proxy-dns.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2023-10-04 15:59:07 AEST; 2h 52min ago
Main PID: 4894 (cloudflared)
Tasks: 9 (limit: 4724)
Memory: 20.0M
CPU: 5.701s
CGroup: /system.slice/cloudflared-proxy-dns.service
└─4894 /usr/bin/cloudflared proxy-dns --metrics 127.0.0.53: --address 127.0.0.53 --port 53 --upstream https://REMOVED.cloudflare-gateway.com/dns-query --bootstrap https://162.159.36.1/dns-query --bootstrap https://162.159.46.1/dns-query --bootstrap https://[2606:4700:4700::1111]/dns-query --bootstrap https://[2606:4700:470>
Oct 04 15:59:07 UDM-SE systemd[1]: Started DNS over HTTPS (DoH) proxy client.
Oct 04 15:59:11 UDM-SE cloudflared[4894]: 2023-10-04T05:59:11Z INF Adding DNS upstream url=https://REMOVED.cloudflare-gateway.com/dns-query
Oct 04 15:59:11 UDM-SE cloudflared[4894]: 2023-10-04T05:59:11Z INF Starting metrics server on 127.0.0.53:41219/metrics
Oct 04 15:59:11 UDM-SE cloudflared[4894]: 2023-10-04T05:59:11Z INF Starting DNS over HTTPS proxy server address=dns://127.0.0.53:53
root@UDM-SE:~#
```
You should also understand what's been done to capture all outbound DNS traffic from both your LAN and your UDM-SE
A dummy interface named "cloudflared" has been created with an IP of 127.0.0.53/32.
```bash
root@UDM-SE:~# ip addr show dev cloudflared
34: cloudflared: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether b6:0f:bb:8e:2e:53 brd ff:ff:ff:ff:ff:ff
inet 127.0.0.53/32 scope host cloudflared
valid_lft forever preferred_lft forever
root@UDM-SE:~#
root@UDM-SE:~# netstat -tuapn | grep :53 | grep cloudflared
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 4894/cloudflared
udp 0 0 127.0.0.53:53 0.0.0.0:* 4894/cloudflared
root@UDM-SE:~#
```
And that's it at a basic level. dnsmasq has not been modified in any way and the dnsmasq process is still listening on 127.0.0.1:53 (and various other interfaces) which the UDM-SE itself is using as a resolver.
e.g.
```bash
root@UDM-SE:~# cat /etc/resolv.conf
# Generated automatically by ubios-udapi-server
nameserver 127.0.0.1
root@UDM-SE:~#
```
So your final step, in order to ensure ALL of your local network DNS traffic flows through `cloudflared proxy-dns`, is to reconfigure your upstream Internet connectivity interfaces to use 127.0.0.53
e.g. in the Unifi UI reconfigure things similar to the below,
![Explicit Upstream DNS Configuration](./upstream_dns_explicit.png)
NOTE: If you have multiple WAN connections, update ALL of them to use 127.0.0.53 as the DNS server for the connection.
This will result in the following being configured in files on your UDM-SE,
```bash
root@UDM-SE:~# cat /etc/resolv.conf
# Generated automatically by ubios-udapi-server
nameserver 127.0.0.1
root@UDM-SE:~# cat /etc/resolv.dnsmasq
# Generated automatically by ubios-udapi-server
# static nameservers
# eth8
nameserver 127.0.0.53
root@UDM-SE:~# cat /run/dns.conf.d/resolv.
resolv.eth10 resolv.eth7 resolv.eth8 resolv.ppp1
root@UDM-SE:~# cat /run/dns.conf.d/resolv.*
# Generated automatically by ubios-udapi-server
# Generated automatically by ubios-udapi-server
# Generated automatically by ubios-udapi-server
# static nameservers
nameserver 127.0.0.53
# Generated automatically by ubios-udapi-server
root@UDM-SE:~#
```
What this means is that:
1. The UnifOS itself resolves via 127.0.0.1:53, which is dnsmasq
2. dnsmasq resolves via 127.0.0.53, which is cloudflared, any time the DNS request has to go out to the Internet, *regardless* of which WAN connection will be used, it will route through cloudflared.
3. Systems in your networks resolve via UDM-SE IP, which means the dnsmasq process, and then dnsmasq resolves their requests via 127.0.0.1:53, which is cloudflared
Because of #1 all of your internal DNS aliases/hostnames for your connected devices will continue to work.
cloudflared will use your active Internet connection to reach the configured resolvers. Note however, that the bootstrap resolvers, which are identified by IP, *MUST* be reachable first.
`BOOTSTRAP="https://162.159.36.1/dns-query https://162.159.46.1/dns-query https://[2606:4700:4700::1111]/dns-query https://[2606:4700:4700::1001]/dns-query"`
If all of the above bootstrap resolver IP's are NOT accessible, for example because you have created firewall rules or done anything else to stop connectivity to them working, DNS resolution will probably stop working too.

View File

@ -0,0 +1,75 @@
#!/bin/bash
BIND=127.0.0.53
PORT=53
UPSTREAM="https://1.1.1.1/dns-query https://1.0.0.1/dns-query"
BOOTSTRAP="https://162.159.36.1/dns-query https://162.159.46.1/dns-query https://[2606:4700:4700::1111]/dns-query https://[2606:4700:4700::1001]/dns-query"
# build argument set, modify this if you want additional customisation
ARGS="--metrics ${BIND}: --address ${BIND} --port ${PORT}"
for i in ${UPSTREAM} ; do
ARGS="${ARGS} --upstream $i"
done
for i in ${BOOTSTRAP} ; do
ARGS="${ARGS} --bootstrap $i"
done
# ensure this directory exists
mkdir -p --mode=0755 /usr/share/keyrings
if [ ! -f /usr/share/keyrings/cloudflare-main.gpg ] ; then
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
fi
if [ ! -f /etc/apt/sources.list.d/cloudflared.list ] ; then
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bullseye main' | tee /etc/apt/sources.list.d/cloudflared.list
fi
dpkg -l | grep cloudflared 1>/dev/null 2>&1
apt update
if [ ${?} != 0 ] ; then
# attempt to install
apt install -y cloudflared || exit 1
else
# attempt to upgrade
apt upgrade -y cloudflared
fi
systemctl stop cloudflared-proxy-dns.service
systemctl disable cloudflared-proxy-dns.service
rm -fv /etc/systemd/system/cloudflared-proxy-dns.service
systemctl daemon-reload
# create a dummy interface that cloudflared can listen on, but which will be independent of any Unifi OS related interfaces, including lo which we can't use
ifconfig cloudflared 1>/dev/null 2>&1 || ip link add name cloudflared type dummy
# add our bind IP to the cloudflared interface
ip addr show dev cloudflared | grep ${BIND}/32 1>/dev/null 2>&1 || ip addr add ${BIND}/32 dev cloudflared
tee /etc/systemd/system/cloudflared-proxy-dns.service >/dev/null <<EOF
[Unit]
Description=DNS over HTTPS (DoH) proxy client
Wants=network-online.target nss-lookup.target
Before=nss-lookup.target
[Service]
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
DynamicUser=yes
ExecStart=/usr/bin/cloudflared proxy-dns ${ARGS}
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable cloudflared-proxy-dns.service
systemctl restart cloudflared-proxy-dns.service
# start the updating service to auto-update the package periodically
test -f /etc/systemd/system/cloudflared-update.timer && systemctl enable cloudflared-update.timer
# EOF

View File

@ -0,0 +1,39 @@
#!/bin/bash
# this should be the secret tunnel token
SERVICE_TOKEN="YOUR SECRET TOKEN GOES HERE"
# ensure this directory exists
mkdir -p --mode=0755 /usr/share/keyrings
if [ ! -f /usr/share/keyrings/cloudflare-main.gpg ] ; then
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
fi
if [ ! -f /etc/apt/sources.list.d/cloudflared.list ] ; then
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bullseye main' | tee /etc/apt/sources.list.d/cloudflared.list
fi
dpkg -l | grep cloudflared 1>/dev/null 2>&1
apt update
if [ ${?} != 0 ] ; then
# attempt to install
apt install -y cloudflared || exit 1
else
# attempt to upgrade
apt upgrade -y cloudflared
fi
# only install/overwrite service automatically if the file does not yet exist
# this allows you to customise the service and how it operates if necessary
test -f /etc/systemd/system/cloudflared.service || cloudflared service install "${SERVICE_TOKEN}"
systemctl daemon-reload
systemctl enable cloudflared.service
systemctl restart cloudflared.service
# start the updating service to auto-update the package periodically
test -f /etc/systemd/system/cloudflared-update.timer && systemctl enable cloudflared-update.timer
# EOF

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -0,0 +1,157 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2*)
DATA_DIR="/data"
;;
3*)
DATA_DIR="/data"
;;
4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## Set the version of cni plugin to use. It will revert to latest if an invalid version is given, and the installer will use the last installed version if that fails.
# Examples of valid version code would be "latest", "v0.9.1" and "v0.9.0".
CNI_PLUGIN_VER=latest
# location of the CNI Plugin cached tar files
CNI_CACHE="${DATA_DIR}/.cache/cni-plugins"
# location of the conf files to go in the net.d folder of the cni-plugin directory
CNI_NETD="${DATA_DIR}/podman/cni"
# The checksum to use. For CNI Plugin sha1, sha256 and sha512 are available.
CNI_CHECKSUM="sha256"
# Maximum number of loops to attempt to download the plugin if required - setting a 0 or negative value will reinstalled the currently installed version (if in cache)
MAX_TRIES=3
mkdir -p "${CNI_CACHE}" "${CNI_NETD}" "/etc/cni/net.d"
# The script will attempt to use the nominated version first, and falls back to latest version if that fails
if [ "$#" -eq 0 ]; then
set ${CNI_PLUGIN_VER}
fi
# Insert conf files for podman networks into the net.d folder
populate_netd()
{
for file in "${CNI_NETD}"/*.conflist
do
if [ -f "$file" ]; then
ln -fs "$file" "/etc/cni/net.d/$(basename "$file")"
fi
done
}
# This function checks a valid checksum has been selected. It requires the checksum is given as the first argument
checksum_check()
{
if [ "$#" -eq 0 ]; then
echo "no arguement given"
return 2
fi
case $1 in
"sha1" | "sha256" | "sha512")
return 0;
;;
*)
echo "Incorrect checksum selection"
return 1;
;;
esac
}
# Test a file against it's checksum - 1 is the checksum type, 2 is the file to test and 3 is the checksum file
checksum_test()
{
if [ ! -f ${2} ] || [ ! -f ${3} ]; then
echo "file does not exist"
return 2
fi
if ! checksum_check ${1}; then
echo "An incorrect checksum has been used"
return 3
fi
value1=$(${1}sum ${2} | awk '{print $1}')
value2=$(cat ${3} | awk '{print $1}')
if [ "${value1}" = "${value2}" ]; then
return 0
else
return 1
fi
}
# Install function - it requires the first argument to be the version to install
install()
{
if [ "$#" -eq 0 ]; then
set "installed"
fi
if [ -f "${CNI_CACHE}/cni-plugins-linux-arm64-$1.tgz" ]; then
echo "Pouring ${CNI_CACHE}/cni-plugins-linux-arm64-$1.tgz"
rm -rf /opt/cni/bin
mkdir -p /opt/cni/bin
tar -xzC /opt/cni/bin -f "${CNI_CACHE}/cni-plugins-linux-arm64-$1.tgz"
# Create a link to installed version as fallback option
if [ "$1" != "installed" ]; then
ln -sf "${CNI_CACHE}/${CNI_TAR}" "${CNI_CACHE}/cni-plugins-linux-arm64-installed.tgz"
ln -sf "${CNI_CACHE}/${CNI_TAR}.${CNI_CHECKSUM}" "${CNI_CACHE}/cni-plugins-linux-arm64-installed.tgz.${CNI_CHECKSUM}"
fi
return 0
fi
echo "No CNI Plugin available to install"
return 1
}
# Download function - the first argument is the version to download. It will default to latest if a invalid option is given.
download()
{
# To stop infinite recursion
if [ ${MAX_TRIES} -lt 1 ]; then
# install the last installed version if latest and specified version have both failed.
install
return 1
fi
# This defaults to latest, in case the specified download doesn't work.
if [ "$#" -eq 0 ]; then
set latest
fi
# Find the corect parameters
set "$(basename "$(curl -fsSLo /dev/null -w "%{url_effective}" https://github.com/containernetworking/plugins/releases/$1)")" "$@"
CNI_TAR="cni-plugins-linux-arm64-$1.tgz"
URL="https://github.com/containernetworking/plugins/releases/download/$1/${CNI_TAR}"
# Cache a checksum for the file
if [ ! -f "${CNI_CACHE}/${CNI_TAR}.${CNI_CHECKSUM}" ]; then
echo "Downloading ${URL}.${CNI_CHECKSUM}"
curl -fsSLo "/tmp/${CNI_TAR}.${CNI_CHECKSUM}" "${URL}.${CNI_CHECKSUM}"
mv "/tmp/${CNI_TAR}.${CNI_CHECKSUM}" "${CNI_CACHE}/${CNI_TAR}.${CNI_CHECKSUM}"
fi
# Cache the tar file
if [ ! -f "${CNI_CACHE}/${CNI_TAR}" ]; then
echo "Downloading ${URL}"
curl -fsSLo "/tmp/${CNI_TAR}" "${URL}"
mv "/tmp/${CNI_TAR}" "${CNI_CACHE}/${CNI_TAR}"
fi
# Symbolic link to latest
if [ "$1" != "$2" ]; then
ln -sf "${CNI_CACHE}/${CNI_TAR}" "${CNI_CACHE}/cni-plugins-linux-arm64-$2.tgz"
ln -sf "${CNI_CACHE}/${CNI_TAR}.${CNI_CHECKSUM}" "${CNI_CACHE}/cni-plugins-linux-arm64-$2.tgz.${CNI_CHECKSUM}"
fi
# Test integrity of the files
if ! checksum_test ${CNI_CHECKSUM} ${CNI_CACHE}/${CNI_TAR} ${CNI_CACHE}/${CNI_TAR}.${CNI_CHECKSUM}; then
echo "Corrupt tar file, deleting tar and checksum"
rm -f "${CNI_CACHE}/${CNI_TAR}" "${CNI_CACHE}/${CNI_TAR}.${CNI_CHECKSUM}"
MAX_TRIES=${(MAX_TRIES - 1)}
# try again on fallback of latest until retries are exhausted
download
else
install $1 $2
return 0
fi
}
download
populate_netd

View File

@ -6,6 +6,7 @@
"type": "macvlan",
"mode": "bridge",
"master": "br5",
"mac": "add 3 fake hex portions, replacing x's here 00:1c:b4:xx:xx:xx",
"ipam": {
"type": "static",
"addresses": [

View File

@ -6,6 +6,7 @@
"type": "macvlan",
"mode": "bridge",
"master": "br5",
"mac": "PUT YOUR GENERATED OWN MAC HERE",
"ipam": {
"type": "static",
"addresses": [

View File

@ -1,6 +0,0 @@
#!/bin/sh
curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-arm64-v0.8.6.tgz -o /tmp/cni.tgz
mkdir -p /mnt/data/podman/cni/
tar xf /tmp/cni.tgz -C /mnt/data/podman/cni/
rm /tmp/cni.tgz

View File

@ -0,0 +1,41 @@
# Container common settings
## Features
1. **Stable disk usage footprint**: Sets a maximum log size any podman container log is allowed to grow up to (from unlimited size to 100Mb). Log "max size" is not a hard limit, but a point when Container Monitor attempts to truncate container log file. **NOTE:** application-specific logs that may be written outside container logs are not truncated by Container Monitor at set limits.
## Requirements
1. You have already setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
## Customization
While a 100Mb log limit per container should give plenty of log data for all featured in this repo projects, you can increase or decrease max_log_size value in /data/on_boot.d/05-container-common.sh file after installation.
## Steps
1. Run as root on UDM Pro to download and set permissions of on_boot.d script:
```sh
# Download 05-container-common.sh from GitHub
curl -L https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/container-common/on_boot.d/05-container-common.sh -o /data/on_boot.d/05-container-common.sh;
# Set execute permission
chmod a+x /data/on_boot.d/05-container-common.sh;
```
2. Review the script /data/on_boot.d/05-container-common.sh and when happy execute it.
```sh
# Review script
cat /data/on_boot.d/05-container-common.sh;
# Apply container-common settings
/data/on_boot.d/05-container-common.sh;
```
3. Already running containers will pick up new defaults after either container restart ("podman restart \<container-name\>") or after UDM Pro restart. New containers will pick up a change from first run.
4. To list containers that are running with log size limits:
```sh
# List container monitor processes with "--log-size-max" custom argument set
ps -ef | grep conmon | grep log-size-max
```

View File

@ -0,0 +1,5 @@
#!/bin/bash
# This script runs before any custom containers start to adjust container common defaults
# Set a limit for container logs. 104857600 Bytes = 100 Megabytes
sed -i 's/max_log_size = -1/max_log_size = 104857600/g' /etc/containers/libpod.conf;

View File

@ -1,9 +1,26 @@
#!/bin/sh
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## configuration variables:
VLAN=5
IPV4_IP="10.0.5.3"
# This is the IP address of the container. You may want to set it to match
# your own network structure such as 192.168.5.3 or similar.
IPV4_GW="10.0.5.1/24"
# As above, this should match the gateway of the VLAN for the container
# network as above which is usually the .1/24 range of the IPV4_IP
# if you want IPv6 support, generate a ULA, select an IP for the dns server
# and an appropriate gateway address on the same /64 network. Make sure that
@ -25,73 +42,65 @@ IPV6_GW=""
FORCED_INTFC=""
# container name; e.g. nextdns, pihole, adguardhome, etc.
CONTAINER=nextdns
CONTAINER=pihole
## network configuration and startup:
CNI_PATH=/mnt/data/podman/cni
if [ ! -f "$CNI_PATH"/macvlan ]; then
mkdir -p $CNI_PATH
curl -L https://github.com/containernetworking/plugins/releases/download/v0.8.6/cni-plugins-linux-arm64-v0.8.6.tgz | tar -xz -C $CNI_PATH
if ! test -f /opt/cni/bin/macvlan; then
echo "Error: CNI plugins not found. You can install it with the following command:" >&2
echo " curl -fsSLo ${DATA_DIR}/on_boot.d/05-install-cni-plugins.sh https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/cni-plugins/05-install-cni-plugins.sh && /bin/sh ${DATA_DIR}/on_boot.d/05-install-cni-plugins.sh" >&2
exit 1
fi
mkdir -p /opt/cni
rm -f /opt/cni/bin
ln -s $CNI_PATH /opt/cni/bin
for file in "$CNI_PATH"/*.conflist
do
if [ -f "$file" ]; then
ln -s "$file" "/etc/cni/net.d/$(basename "$file")"
fi
done
# set VLAN bridge promiscuous
ip link set br${VLAN} promisc on
ip link set "br${VLAN}" promisc on
# create macvlan bridge and add IPv4 IP
ip link add br${VLAN}.mac link br${VLAN} type macvlan mode bridge
ip addr add ${IPV4_GW} dev br${VLAN}.mac noprefixroute
ip link add "br${VLAN}.mac" link "br${VLAN}" type macvlan mode bridge
ip addr add "${IPV4_GW}" dev "br${VLAN}.mac" noprefixroute
# (optional) add IPv6 IP to VLAN bridge macvlan bridge
if [ -n "${IPV6_GW}" ]; then
ip -6 addr add ${IPV6_GW} dev br${VLAN}.mac noprefixroute
ip -6 addr add "${IPV6_GW}" dev "br${VLAN}.mac" noprefixroute
fi
# set macvlan bridge promiscuous and bring it up
ip link set br${VLAN}.mac promisc on
ip link set br${VLAN}.mac up
ip link set "br${VLAN}.mac" promisc on
ip link set "br${VLAN}.mac" up
# add IPv4 route to DNS container
ip route add ${IPV4_IP}/32 dev br${VLAN}.mac
ip route add "${IPV4_IP}/32" dev "br${VLAN}.mac"
# (optional) add IPv6 route to DNS container
if [ -n "${IPV6_IP}" ]; then
ip -6 route add ${IPV6_IP}/128 dev br${VLAN}.mac
ip -6 route add "${IPV6_IP}/128" dev "br${VLAN}.mac"
fi
# Make DNSMasq listen to the container network for split horizon or conditional forwarding
if ! grep -qxF interface=br$VLAN.mac /run/dnsmasq.conf.d/custom.conf; then
echo interface=br$VLAN.mac >> /run/dnsmasq.conf.d/custom.conf
kill -9 `cat /run/dnsmasq.pid`
if ! grep -qxF "interface=br${VLAN}.mac" /run/dnsmasq.conf.d/custom.conf; then
echo "interface=br${VLAN}.mac" >>/run/dnsmasq.conf.d/custom.conf
kill -9 "$(cat /run/dnsmasq.pid)"
fi
if podman container exists ${CONTAINER}; then
podman start ${CONTAINER}
if podman container exists "${CONTAINER}"; then
podman start "${CONTAINER}"
else
logger -s -t podman-dns -p ERROR Container $CONTAINER not found, make sure you set the proper name, you can ignore this error if it is your first time setting it up
logger -s -t podman-dns -p "ERROR Container ${CONTAINER} not found, make sure you set the proper name, you can ignore this error if it is your first time setting it up"
fi
# (optional) IPv4 force DNS (TCP/UDP 53) through DNS container
for intfc in ${FORCED_INTFC}; do
if [ -d "/sys/class/net/${intfc}" ]; then
for proto in udp tcp; do
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV4_IP} ! -d ${IPV4_IP} --dport 53 -j LOG --log-prefix [DNAT-${intfc}-${proto}]"
iptables -t nat -C ${prerouting_rule} 2>/dev/null || iptables -t nat -A ${prerouting_rule}
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV4_IP} ! -d ${IPV4_IP} --dport 53 -j DNAT --to ${IPV4_IP}"
iptables -t nat -C ${prerouting_rule} || iptables -t nat -A ${prerouting_rule}
iptables -t nat -C ${prerouting_rule} 2>/dev/null || iptables -t nat -A ${prerouting_rule}
# (optional) IPv6 force DNS (TCP/UDP 53) through DNS container
if [ -n "${IPV6_IP}" ]; then
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV6_IP} ! -d ${IPV6_IP} --dport 53 -j LOG --log-prefix [DNAT-${intfc}-${proto}]"
ip6tables -t nat -C ${prerouting_rule} 2>/dev/null || ip6tables -t nat -A ${prerouting_rule}
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV6_IP} ! -d ${IPV6_IP} --dport 53 -j DNAT --to ${IPV6_IP}"
ip6tables -t nat -C ${prerouting_rule} || ip6tables -t nat -A ${prerouting_rule}
ip6tables -t nat -C ${prerouting_rule} 2>/dev/null || ip6tables -t nat -A ${prerouting_rule}
fi
done
fi

View File

@ -0,0 +1,24 @@
{
"cniVersion": "0.4.0",
"name": "haproxy",
"plugins": [
{
"type": "macvlan",
"mode": "bridge",
"master": "br5",
"mac": "add 3 fake hex portions, replacing x's here 00:1c:b4:xx:xx:xx",
"ipam": {
"type": "static",
"addresses": [
{
"address": "10.0.5.3/24",
"gateway": "10.0.5.1"
}
],
"routes": [
{"dst": "0.0.0.0/0"}
]
}
}
]
}

37
haproxy/50-haproxy.sh Normal file
View File

@ -0,0 +1,37 @@
#!/bin/bash
CONTAINER=haproxy
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "${DATA_DIR}/haproxy" ]; then
# If it does not exist, create the directory
mkdir -p "${DATA_DIR}/haproxy"
echo "Directory '${DATA_DIR}/haproxy' created."
else
# If it already exists, print a message
echo "Directory '${DATA_DIR}/haproxy' already exists. Moving on."
fi
# Starts an haproxy container that is deleted after it is stopped.
# All configs stored in /data/haproxy
if podman container exists "$CONTAINER"; then
podman start "$CONTAINER"
else
podman run -d --net=host --restart always \
--name haproxy \
--hostname ha.proxy \
-v "${DATA_DIR}/haproxy/:/usr/local/etc/haproxy/" \
haproxy:latest
fi

40
haproxy/README.md Normal file
View File

@ -0,0 +1,40 @@
# Run haproxy on your UDM
## Features
1. Load balance services on your UDM, because why not?.
2. Persists through reboots and firmware updates.
## Requirements
1. You have successfully setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
2. You have to have services you want to load-balance, an example would be a multi-master k3s cluster.
## Steps
1. Check if you either have `/mnt/data` or `/data/` and adjust below accordingly
2. Pull your image with `podman pull docker.io/library/haproxy`.
3. Copy [50-haproxy.sh](./50-haproxy.sh) to `/data/on_boot.d/50-haproxy.sh`.
4. Choose network configuration - You can run either on the host network or on a seperate docker network. Running on the host network is easier but does mean you can't clash with the ports already in use on the UDM.
1. If you want to run on the host network
1. You don't have to do anything extra to run on the host network all the instructions / scripts assume this setup.
2. If you want to run on a custom docker network do the following:
1. Setup the network - there are some instructions in the Customizations setting of the pihole instructions: https://github.com/unifi-utilities/unifios-utilities/tree/main/run-pihole#customizations
2. Copy [21-haproxy.conflist](./21-haproxy.conflist) to `/data/podman/cni/` and update its values to reflect your environment.
3. Execute the `/data/on_boot.d/05-install-cni-plugins.sh` script to create the network.
4. Edit `/data/on_boot.d/50-haproxy.sh` and change `--net=host` to `--network haproxy`
5. Create a persistant directory and config for haproxy to use:
```sh
mkdir -p /data/haproxy
touch /data/haproxy/haproxy.cfg
```
6. Add your config to `/data/haproxy/haproxy.cfg`. Each configuration is unique, so check out some resouces like [haproxy.com](https://www.haproxy.com/documentation/hapee/latest/configuration/config-sections/) for basics.
7. Run `/data/on_boot.d/50-haproxy.sh`
## Upgrading Easily (if at all)
1. Edit [update-haproxy.sh](./update-haproxy.sh) to use the same command you used at installation (if changed). If you added your own network config ensure you change the `--net=host` to `--network haproxy`
2. Copy the [update-haproxy.sh](./update-haproxy.sh) to `/data/scripts`
3. Anytime you want to update your installation, simply run `/data/scripts/update-haproxy.sh`

23
haproxy/update-haproxy.sh Normal file
View File

@ -0,0 +1,23 @@
IMAGE=haproxy:latest
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
podman pull $IMAGE
podman stop haproxy
podman rm haproxy
podman run -d --net=host --restart always \
--name haproxy \
--hostname ha.proxy \
-v "${DATA_DIR}/haproxy/:/usr/local/etc/haproxy/" \
$IMAGE

BIN
hdhomerun/.DS_Store vendored Normal file

Binary file not shown.

62
hdhomerun/README.md Normal file
View File

@ -0,0 +1,62 @@
# HDHomeRun VLAN Traversal
## License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## Reference
From https://community.ui.com/questions/Howto-HDHomerun-discovery-on-different-LAN-segment/97db52c6-4add-4ba1-ab0d-27ee6f43db8f
## Purpose
The HDHomeRun software sends a UDP broadcast out to the HDHomeRun tuner as part
of the discovery process. If your HDHomeRun is on a separate VLAN, you need
some sort of proxy to push this UDP broadcast out to the target network.
Also `socat` is a useful tool and maybe you want to cross-compile it for your
UDMP(SE)
## Compiling `socat`
In the `build` directory, there is a Docker file to cross compile a socat
binary for the Dream Machine Pro.
```docker build -t build_socat .```
```docker run -v $PWD:/tmp/release build_socat```
The first command builds the container, and the second runs the container. The
container will copy the binary inside the container to `/tmp/release`. The -v
volume mapping will case the file to apper in the current working directory of
the host.
Precompiled binary is provided. Use at your own risk.
## Setting up the on.boot script
1. Update the `99-hdhomerun.sh` script with the IP address of your HDHomeRun
tuner.
2. Place it in your `on_boot.d` folder and make it executable.
3. Reboot your UDMP(SE) or restart the service with something like
`systemctl restart udm-boot`
4. You can verify the script is running with `ps aux | grep "socat"`
5. The HDHomeRun software should now be able to discover the tuner on the
other VLAN.
## Testing
This was tested with an HDHomeRun PRIME. I do not know if it works with other
hardware.

BIN
hdhomerun/bin/.DS_Store vendored Normal file

Binary file not shown.

BIN
hdhomerun/bin/socat Executable file

Binary file not shown.

BIN
hdhomerun/build/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,43 @@
# Note: map a volume to /tmp/release to accept the binary.
# ```
# docker build -t build_socat .
FROM aarch64/gcc
ARG SOCAT_VERSION=1.7.4.3
ARG READLINE_VERSION=7.0
ARG OPENSSL_VERSION=1.0.2k
# Make directories
RUN mkdir -p /build && mkdir -p /tmp/release
WORKDIR /build
# Build readline
RUN curl -k -LO ftp://ftp.cwru.edu/pub/bash/readline-${READLINE_VERSION}.tar.gz
RUN tar xzvf readline-${READLINE_VERSION}.tar.gz
WORKDIR /build/readline-${READLINE_VERSION}
RUN ./configure -disable-shared --enable-static -build=aarch64
RUN make -j4
RUN make install-static
# Build OpenSSL
WORKDIR /build
RUN curl -k -LO https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
RUN tar zxvf openssl-${OPENSSL_VERSION}.tar.gz
WORKDIR /build/openssl-${OPENSSL_VERSION}
ENV CFLAGS='-fPIC -static'
RUN ./Configure no-shared linux-aarch64
RUN make -j4
RUN make install
# Build socat
WORKDIR /build
RUN curl -k -LO http://www.dest-unreach.org/socat/download/socat-${SOCAT_VERSION}.tar.gz
RUN tar xzvf socat-${SOCAT_VERSION}.tar.gz
WORKDIR /build/socat-${SOCAT_VERSION}
ENV LDFLAGS='-static -ldl -ltinfo'
RUN ./configure -build=linux-aarch64
RUN make -j4
# Copy the file to the release directory
ENTRYPOINT cp socat /tmp/release

View File

@ -0,0 +1,29 @@
#!/bin/bash
# Place cross compiled version of `socat` in /data/hdhomerun
HDHOMERUN_IP=10.10.30.146
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "$DATA_DIR" ]; then
# If it does not exist, create the directory
mkdir -p "$DATA_DIR"
echo "Directory '$DATA_DIR' created."
else
# If it already exists, print a message
echo "Directory '$DATA_DIR' already exists. Moving on."
fi
${DATA_DIR}/hdhomerun/socat -d -d -v udp4-recvfrom:65001,broadcast,fork udp4-sendto:$HDHOMERUN_IP:65001 &

46
homebridge/README.md Normal file
View File

@ -0,0 +1,46 @@
# Run Homebridge on your UDM
### Features
1. Run [Homebridge](https://homebridge.io/) on your UDM(P).
2. Integrate Unifi Protect cameras in HomeKit via `homebridge-unifi-protect`.
3. Persists through reboots and firmware updates.
### Requirements
1. You have successfully setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script).
2. You have applied [container-common](https://github.com/unifi-utilities/unifios-utilities/tree/main/container-common) change to prevent UDM storage to fill up with Homebridge logs and addon error messages that can move fast.
3. You have applied [cni-plugins](https://github.com/unifi-utilities/unifios-utilities/tree/main/cni-plugins "cni-plugins") to setup for cni configeration. (You dont need the configeration files, just place the script in the on boot folder.)
### Steps
1. Type this command: `mkdir -p /data/homebridge/run`
2. Copy [25-homebridge.sh](on_boot.d/25-homebridge.sh) to `/data/on_boot.d`. To do this, cd into `/data/on_boot.d`, then type `vim 25-homebridge.sh` then go to [this page](https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/homebridge/on_boot.d/25-homebridge.sh "this page") and copy everything using CTRL + A and then CTRL + C and then paste it into vim then click ESC and then type `:x` then click the enter key.
3. Copy [90-homebridge.conflist](cni/90-homebridge.conflist) to `/data/podman/cni`. This will create the podman network that bridges the container to your VLAN. To do this, cd into `/data/podman/cni` and type `vim 90-homebridge.conflist` then go to [this page](https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/homebridge/cni/90-homebridge.conflist "this page") and the press CTRL + A and then CTRL + C and then paste it into vim and click ESC and then type `:x` then click the enter key.
4. Run the Homebridge docker container. Change the timezone (`-e TZ`) to match your timezone, and DNS (`--dns`) to match your VLAN gateway.
```shell script
podman run -d --restart always \
--privileged \
--name homebridge \
--net homebridge \
--dns 192.168.1.1 \
--dns-search lan \
-e TZ=America/Chicago \
-e PGID=0 -e PUID=0 \
-e HOMEBRIDGE_CONFIG_UI=1 \
-e HOMEBRIDGE_CONFIG_UI_PORT=80 \
-v "/data/homebridge/:/homebridge/" \
-v "/data/homebridge/run/:/run/" \
oznu/homebridge:latest
```
5. Access the Homebridge UI based on the IP you assigned, like [http://192.168.1.20/](http://192.168.1.20/).
6. If using the UDM Pro, the `homebridge-unifi-protect` plugin can be installed via the Homebridge UI to integrate Unifi Protect cameras.
### Customization
- Update [90-homebridge.conflist](cni/90-homebridge.conflist) to match your network:
- Change `"bridge": "br0"` to the appropriate VLAN for your network.
- Update `"subnet"` and `"gateway"` to match that VLAN.
- If you want a specific IP assigned, update `"rangeStart"` and `"rangeEnd"`. Otherwise those properties can be deleted.

View File

@ -0,0 +1,32 @@
{
"cniVersion": "0.4.0",
"name": "homebridge",
"plugins": [
{
"type": "bridge",
"bridge": "br0",
"ipam": {
"type": "host-local",
"ranges": [
[
{
"subnet": "192.168.1.0/24",
"rangeStart": "192.168.1.20",
"rangeEnd": "192.168.1.20",
"gateway": "192.168.1.1"
}
]
],
"routes": [
{"dst": "0.0.0.0/0"}
]
}
},
{
"type": "tuning",
"capabilities": {
"mac": true
}
}
]
}

View File

@ -0,0 +1,52 @@
#!/bin/bash
CONTAINER=homebridge
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## network configuration and startup:
CNI_PATH=${DATA_DIR}/podman/cni
# Check if the directory exists
if [ ! -d "$CNI_PATH" ]; then
# If it does not exist, create the directory
mkdir -p "$CNI_PATH"
echo "Directory '$CNI_PATH' created."
else
# If it already exists, print a message
echo "Directory '$CNI_PATH' already exists. Moving on."
fi
if [ ! -f "$CNI_PATH"/tuning ]; then
mkdir -p $CNI_PATH
curl -L https://github.com/containernetworking/plugins/releases/download/v0.9.1/cni-plugins-linux-arm64-v0.9.1.tgz | tar -xz -C $CNI_PATH
fi
mkdir -p /opt/cni
rm -f /opt/cni/bin
ln -s $CNI_PATH /opt/cni/bin
for file in "$CNI_PATH"/*.conflist; do
if [ -f "$file" ]; then
ln -s "$file" "/etc/cni/net.d/$(basename "$file")"
fi
done
# Starts the homebridge container on boot.
# All configs stored in /data/homebridge
if podman container exists ${CONTAINER}; then
podman start ${CONTAINER}
else
logger -s -t homebridge -p ERROR Container $CONTAINER not found, make sure you set the proper name, you can ignore this error if it is your first time setting it up
fi

69
ipt-enable-logs/README.md Normal file
View File

@ -0,0 +1,69 @@
# Enable log tags on your UDM
## Features
If you're used to the Unifi Security Gateway, you may miss the USG log prefixes that allow you to know which rule blocked certain traffic.
This mod adds logging prefixes to messages from `/var/log/messages` allowing you to trace a particular log message to the respective iptable rule (which is generated from the firewall rules you configure on the Network application, among other things)
## Requirements
1. You have successfully setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
## General idea
This mod builds a small Go program that modifies the existing iptables to add `--log-prefix` to entries that are defined as loggable through the `-j LOG` directive. The Go program is built in a Docker container local to the UDM.
Here's an example snippet of an iptable modified by this program:
```
-A UBIOS_WAN_IN_USER -d 192.168.16.10/32 -p udp -m udp --dport 51820 -m conntrack --ctstate NEW -j LOG --log-prefix "[FW-A-WAN_IN_U-3010] "
-A UBIOS_WAN_IN_USER -d 192.168.16.10/32 -p udp -m udp --dport 51820 -m conntrack --ctstate NEW -m comment --comment 00000000008589937602 -j RETURN
-A UBIOS_WAN_IN_USER -d 192.168.16.10/32 -p udp -m udp --dport 51821 -m conntrack --ctstate NEW -j LOG --log-prefix "[FW-A-WAN_IN_U-3011] "
-A UBIOS_WAN_IN_USER -d 192.168.16.10/32 -p udp -m udp --dport 51821 -m conntrack --ctstate NEW -m comment --comment 00000000008589937603 -j RETURN
```
## Steps
1. Copy [on_boot.d/30-ipt-enable-logs-launch.sh](./on_boot.d/30-ipt-enable-logs-launch.sh) to /data/on_boot.d
1. Copy the [scripts/ipt-enable-logs](./scripts/ipt-enable-logs) folder to /data/scripts
1. Copy [scripts/ipt-enable-logs.sh](./scripts/ipt-enable-logs.sh) to /data/scripts
1. Execute /data/on_boot.d/30-ipt-enable-logs-launch.sh
1. Copy [scripts/refresh-iptables.sh](./scripts/refresh-iptables.sh) to /data/scripts
## Refreshing iptables
Whenever you update the firewall rules on the Network application, the iptables will be reprovisioned and will need to be reprocessed
by calling /data/scripts/refresh-iptables.sh.
## Looking at logs
Logs can be followed easily from another machine through SSH by using the following bash functions:
```shell
function logunifijson() {
ssh unifi "tail -f /var/log/messages" | \
rg "kernel:" | \
sed "s/]IN/] IN/" | \
jq --unbuffered -R '. | rtrimstr(" ") | split(": ") | {date: (.[0] | split(" ") | .[0:3] | join(" "))} + (.[1] | capture("\\[.+\\] \\[(?<rule>.*)\\].*")) + ((.[1] | capture("\\[.+\\] (?<rest>.*)") | .rest | split(" ") | map(select(startswith("[") == false) | split("=") | {(.[0]): .[1]})) | (reduce .[] as $item ({}; . + $item)))'
}
function logunifi() {
logunifijson | jq --unbuffered -r '"\(.date) - \(.rule)\tIN=\(.IN) \t\(.PROTO)\tSRC=\(.SRC)@\(.SPT)\tDST=\(.DST)@\(.DPT)\tLEN=\(.LEN)\t"'
}
```
Here's what the output of `logunifi` looks like:
```
Nov 14 10:58:31 - A-LAN_LOCAL_U-2000 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-2000 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-2000 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-2000 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-2000 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-2000 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
```
## Acknowledgements
Thanks a lot to [@opustecnica](https://github.com/opustecnica) for the [initial implementation](https://github.com/opustecnica/public/wiki/UDM-&-UDM-PRO-NOTES) and idea (based on a bash script)!

View File

@ -0,0 +1,33 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "${DATA_DIR}/scripts" ]; then
# If it does not exist, create the directory
mkdir -p "${DATA_DIR}/scripts"
echo "Directory '${DATA_DIR}/scripts' created."
else
# If it already exists, print a message
echo "Directory '${DATA_DIR}/scripts' already exists. Moving on."
fi
set -e
if ! iptables-save | grep -e '\-A UBIOS_.* \--log-prefix "\[' >/dev/null; then
${DATA_DIR}/scripts/ipt-enable-logs.sh | iptables-restore -c
else
echo "iptables already contains USER log prefixes, ignoring."
fi

View File

@ -0,0 +1,31 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "${DATA_DIR}/scripts" ]; then
# If it does not exist, create the directory
mkdir -p "${DATA_DIR}/scripts"
echo "Directory '${DATA_DIR}/scripts' created."
else
# If it already exists, print a message
echo "Directory '${DATA_DIR}/scripts' already exists. Moving on."
fi
set -e
docker run -it --rm -v ${DATA_DIR}/scripts/ipt-enable-logs:/src -w /src --network=none golang:1.17.3 go build -v -o /src/ipt-enable-logs /src >&2
${DATA_DIR}/scripts/ipt-enable-logs/ipt-enable-logs

View File

@ -0,0 +1,3 @@
module pedropombeiro.com/ipt-enable-logs
go 1.17

View File

@ -0,0 +1,62 @@
package main
import (
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
)
func main() {
cmd := exec.Command("iptables-save")
outputBytes, err := cmd.Output()
if err != nil {
_ = fmt.Errorf("Failed to run iptables-save: %v", err)
os.Exit(1)
}
str := string(outputBytes)
lines := strings.Split(str, "\n")
re := regexp.MustCompile(`-A UBIOS_([A-Z_]+) .* --comment (\d+) -j ([A-Z]+)`)
for i, line := range lines {
if i != 0 {
fmt.Println()
}
if !strings.HasSuffix(line, "-j LOG") {
fmt.Print(line)
continue
}
matches := re.FindSubmatch([]byte(lines[i+1]))
commentNr, err := strconv.Atoi(string(matches[2]))
if err != nil {
commentNr = 0
}
actionName := getActionName(string(matches[3]))
ruleName := getRuleName(string(matches[1]), commentNr)
fmt.Printf(`%s --log-prefix "[FW-%s-%s] "`, line, actionName, ruleName)
}
}
func getActionName(action string) string {
action = strings.Replace(action, "RETURN", "A", 1)
action = strings.Replace(action, "REJECT", "R", 1)
action = strings.Replace(action, "DROP", "D", 1)
action = strings.Replace(action, "MASQUERADE", "M", 1)
return action
}
func getRuleName(rule string, commentNr int) string {
ruleName := strings.Replace(rule, "PREROUTING", "PRER", 1)
ruleName = strings.Replace(ruleName, "POSTROUTING", "POSTR", 1)
ruleName = strings.Replace(ruleName, "HOOK", "HK", 1)
ruleName = strings.Replace(ruleName, "USER", "U", 1)
if commentNr != 0 {
ruleName = fmt.Sprintf("%s-%d", ruleName, commentNr & 0xFFFFFFFF)
}
return ruleName
}

View File

@ -0,0 +1,36 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "${DATA_DIR}/on_boot.d" ]; then
# If it does not exist, create the directory
mkdir -p "${DATA_DIR}/on_boot.d"
echo "Directory '${DATA_DIR}/on_boot.d' created."
else
# If it already exists, print a message
echo "Directory '${DATA_DIR}/on_boot.d' already exists. Moving on."
fi
set -e
if [ -f ${DATA_DIR}/on_boot.d/10-dns.sh ]; then
if ! iptables-save | grep -e '\-A PREROUTING.* \--log-prefix "\[' >/dev/null; then
${DATA_DIR}/on_boot.d/10-dns.sh
else
echo "iptables already contains DNAT log prefixes, ignoring."
fi
fi
${DATA_DIR}/on_boot.d/30-ipt-enable-logs-launch.sh

16
modern-unix/Makefile Normal file
View File

@ -0,0 +1,16 @@
RSYNC_FLAGS ?= -Ravuzh --no-o
SCP_FLAGS ?= -O -o LogLevel=Error
SSH_FLAGS ?= -o RemoteCommand=none -o LogLevel=error
SSH_HOST ?= root@192.168.16.1 # IP address of the UDM in the local network
.PHONY: push-config
push-config:
ssh $(SSH_FLAGS) $(SSH_HOST) 'mkdir -p /data/on_boot.d /data/scripts; rm -rf /data/scripts/*.sh'
chmod +x ./on_boot.d/*.sh
rsync $(RSYNC_FLAGS) ./on_boot.d/ ./scripts/ ./settings/ $(SSH_HOST):/data/
.PHONY: install-tools
install-tools:
ssh $(SSH_FLAGS) $(SSH_HOST) /data/scripts/download-tools.sh
.PHONY: all clean test

34
modern-unix/README.md Normal file
View File

@ -0,0 +1,34 @@
# Modern Unix tools for the UDM
## Features
[Modern Unix tools](https://github.com/ibraheemdev/modern-unix) to make the UDM shell more pleasant
and modern:
- [bat](https://github.com/sharkdp/bat): A `cat` clone with syntax highlighting and Git integration.
- [bottom](https://github.com/ClementTsang/bottom): Yet another cross-platform graphical
process/system monitor.
- [croc](https://github.com/schollz/croc): Easily and securely send things from one computer to another 🐊 📦
- [duf](https://github.com/muesli/duf): A better `df` alternative.
- [gping](https://github.com/orf/gping): `ping`, but with a graph.
- [ncdu](https://dev.yorhel.nl/ncdu): Ncdu is a disk usage analyzer with an ncurses interface.
- [lsd](https://github.com/Peltoche/lsd): The next gen file listing command. Backwards compatible with `ls`.
- [xh](https://github.com/ducaale/xh): A friendly and fast tool for sending HTTP requests.
It reimplements as much as possible of HTTPie's excellent design, with a focus on improved performance.
## Demo
[![asciicast](https://asciinema.org/a/e2E1x0QilIvOgSy2N4dKSWwJ8.svg)](https://asciinema.org/a/e2E1x0QilIvOgSy2N4dKSWwJ8)
## Requirements
1. You have successfully setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
## Steps
1. You may copy the files in `on_boot.d/`, `scripts/`, and `settings/` to `/data/` in the UDM, or you can
use the Makefile targets to copy and install the tools from a remote machine:
```sh
make push-config install-tools
```

View File

@ -0,0 +1,31 @@
#!/bin/bssh
## Configure shell profile
PROFILE_SOURCE=/data/settings/profile/global.profile.d
PROFILE_TARGET=/etc/profile.d
device_info() {
/usr/bin/ubnt-device-info "$1"
}
# Modify login banner (motd)
cat > /etc/motd <<EOF
Welcome to $(device_info model)!
(c) 2010-$(date +%Y) Ubiquiti Inc. | http://www.ui.com
Model: $(device_info model)
Version: $(device_info firmware)
MAC Address: $(device_info mac)
EOF
# Extend UbiOS prompt to include useful information
cat > /etc/profile.d/prompt.sh <<'EOF'
UDM_NAME="$(grep -m 1 '^name:' /data/unifi-core/config/settings.yaml | awk -F: '{ gsub(/^[ \t]+|[ \t]+$/, "", $2); print tolower($2) }')"
PROMPT_MAIN="\u@${UDM_NAME}:\w"
export PS1="[UDM] ${PROMPT_MAIN}${PS1}"
EOF
# Copy all global profile scripts (for all users) from `/data/settings/profile/global.profile.d/` directory
mkdir -p ${PROFILE_SOURCE}
cp -rf ${PROFILE_SOURCE}/* ${PROFILE_TARGET}

6
modern-unix/scripts/colors.sh Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color

View File

@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -e
SCRIPTS=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
source "${SCRIPTS}/colors.sh"
printf "${YELLOW}%s${NC}\n" "Installing tools..."
target_dir="/data/opt"
temp_dir="$(mktemp -d)"
bat_version=0.22.1
croc_version=9.6.3
duf_version=0.8.1
ncdu_version=2.2.1
lsd_version=0.23.1
xh_version=0.18.0
function download_and_extract() {
printf "${GREEN}%s${NC}\n" "Downloading $1..."
filename="$(basename "$1")"
wget -q "$1" -O "${temp_dir}/package.${filename##*.}"
printf "${GREEN}%s${NC}" "Extracting... "
if [[ ${filename##*.} == 'zip' ]]; then
extract_zip "$2"
else
extract_tar "$2"
fi
}
function extract_zip() {
unzip -o -j "${temp_dir}/package.zip" -d "${target_dir}" "$1"
rm -f "${temp_dir}/package.zip"
}
function extract_tar() {
if [[ $1 == *"/"* ]]; then
tar xzvf "${temp_dir}/package.gz" --directory="${target_dir}" --strip-components=1 "$1" --no-same-owner
else
tar xzvf "${temp_dir}/package.gz" --directory="${target_dir}" "$1" --no-same-owner
fi
rm -f "${temp_dir}/package.*"
}
mkdir -p "${target_dir}"
archive_name="bat-v${bat_version}-aarch64-unknown-linux-gnu"
download_and_extract "https://github.com/sharkdp/bat/releases/download/v${bat_version}/bat-v${bat_version}-aarch64-unknown-linux-gnu.tar.gz" "${archive_name}/bat"
download_and_extract "https://github.com/ClementTsang/bottom/releases/latest/download/bottom_aarch64-unknown-linux-musl.tar.gz" btm
download_and_extract "https://github.com/schollz/croc/releases/download/v${croc_version}/croc_${croc_version}_Linux-ARM64.tar.gz" croc
download_and_extract "https://github.com/muesli/duf/releases/download/v${duf_version}/duf_${duf_version}_linux_arm64.tar.gz" duf
download_and_extract "https://github.com/orf/gping/releases/latest/download/gping-aarch64-unknown-linux-musl.tar.gz" gping
download_and_extract "https://dev.yorhel.nl/download/ncdu-${ncdu_version}-linux-aarch64.tar.gz" ncdu
archive_name="lsd-${lsd_version}-aarch64-unknown-linux-musl"
download_and_extract "https://github.com/Peltoche/lsd/releases/download/${lsd_version}/${archive_name}.tar.gz" "${archive_name}/lsd"
archive_name="xh-v${xh_version}-aarch64-unknown-linux-musl"
download_and_extract "https://github.com/ducaale/xh/releases/download/v${xh_version}/xh-v${xh_version}-aarch64-unknown-linux-musl.tar.gz" "${archive_name}/xh"
rm -rf "${temp_dir}"

View File

@ -0,0 +1,17 @@
#!/bin/bash
alias ...=../..
alias ....=../../..
alias .....=../../../..
alias ......=../../../../..
alias cp='cp -i'
alias la='ls -lAFh'
alias ll='ls -l'
alias md='mkdir -p'
alias mkcd='foo(){ mkdir -p "$1"; cd "$1" }; foo'
alias mv='mv -i'
alias rd=rmdir
alias rm='rm -i'
alias docker='podman'
alias ls='lsd'
alias vim='vi'

View File

@ -0,0 +1,4 @@
#!/bin/bash
PATH="/data/opt:$PATH"
export PATH

84
mosquitto/README.md Normal file
View File

@ -0,0 +1,84 @@
# [Eclipse Mosquitto™](https://mosquitto.org) on Ubiquiti Unifi Dream Machine (Pro)
> Run the MQTT message broker Eclipse Mosquitto™ on your Unifi Dream Machine (Pro).
## Prerequisities
- Working **`on_boot.d`** setup (check [unifi-utilities/unifios-utilities#on-boot-script](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script) for instructions)
- A VLAN network (you can use one you are already using)
**Recommended**
- Use [container-common](../container-common/README.md) to prevent growing disk usage from accumulating logs
**Optional**
- Port forwarding, ie. WAN -> [MOSQUITTO_IP] (TCP/1883) if needed
**Note**
Throughout this guide I'm using `VLAN 20` with gateway `10.0.20.1/24` as an example; Mosquitto's IP will be `10.0.20.4`.
_Adjust according to your setup._
## Setup
1. First, lets create the folder structure we'll be working with.
`$ mkdir -p /data/mosquitto/config /data/mosquitto/data`
This is where Mosquitto's configuration file and data ("persistence database"; if enabled) will live.
If you're unsure on how to configure mosquitto, use the provided barebone config [`config/mosquitto.conf`](config/mosquitto.conf) to get it initially running.
2. **Optional:** Customize [`on_boot.d/45-mosquitto.sh`](on_boot.d/45-mosquitto.sh) to your setup and copy to `/data/on_boot.d/`.
Most likely you'll need to mark the script as executable, this will do the trick:
`$ chmod a+x /data/on_boot.d/45-mosquitto.sh`
3. Then take a loot at [`cni/45-mosquitto.conflist`](cni/45-mosquitto.conflist) and make sure it matches your previously defined configuration; then place it in `/data/podman/cni/`
4. Run boot script (to create the mosquitto network set it's ip routes)
`$ sh /data/on_boot.d/45-mosquitto.sh`
It fail when trying to run the container, but thats okay, its just for setting op needed configuration before initial image run.
The script will also create a [minimal configuration](config/mosquitto.conf) for Mosquitto in `/data/mosquitto/config/`, _**only if it doesn't already exist**_.
> **Note:** You can use this config to get everything started, but I highly recommend securing your instance with authentication (links to the offical documentation & other resources are at the bottom)
5. Register the container with podman:
```shell
$ podman run -d --network mosquitto \
--restart always \
--security-opt=no-new-privileges \
--name mosquitto \
--hostname mosquitto.local \
-e "TZ=Europe/Berlin" \
-v /data/mosquitto/config/:/mosquitto/config \
-v /data/mosquitto/data/:/mosquitto/data \
eclipse-mosquitto:latest
```
6. Run boot script again and we are done!
`$ sh /data/on_boot.d/45-mosquitto.sh`
> You should now be able to connect with any MQTT client to Mosquitto, in my case `mqtt://10.0.20.4:1883`
## Commands
**Updates**
To update container image to its latest version, first delete the current container (`$ podman stop mosquitto && podman rm mosquitto`) and follow through setup steps 5. & 6.
**Logs**
If you want to know what mosquitto is doing, run `$ podman logs -f mosquitto` to follow the logs.
## Relevant Links
- [Eclipse Mosquitto Homepage](https://mosquitto.org)
- [mosquitto.conf man page](https://mosquitto.org/man/mosquitto-conf-5.html)
- [Setting up Authentication in Mosquitto MQTT Broker](https://medium.com/@eranda/setting-up-authentication-on-mosquitto-mqtt-broker-de5df2e29afc)
- [eclipse-mosquitto on Docker-Hub](https://hub.docker.com/_/eclipse-mosquitto/)
## Credits
Huge thanks to @boostchicken for his incredible work on [unifios-utilities](https://github.com/unifi-utilities/unifios-utilities) and all contributors of this repo!

View File

@ -0,0 +1,32 @@
{
"cniVersion": "0.4.0",
"name": "mosquitto",
"plugins": [
{
"type": "bridge",
"bridge": "br20",
"ipam": {
"type": "host-local",
"ranges": [
[
{
"subnet": "10.0.20.0/24",
"rangeStart": "10.0.20.4",
"rangeEnd": "10.0.20.4",
"gateway": "10.0.20.1"
}
]
],
"routes": [
{"dst": "0.0.0.0/0"}
]
}
},
{
"type": "tuning",
"capabilities": {
"mac": true
}
}
]
}

View File

@ -0,0 +1,11 @@
listener 1883
allow_anonymous true
connection_messages true
persistence true
persistence_location /mosquitto/data/
log_dest stdout
log_type debug
log_timestamp true

View File

@ -0,0 +1,85 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
# Check if the directory exists
if [ ! -d "${DATA_DIR}/podman/cni" ]; then
# If it does not exist, create the directory
mkdir -p "${DATA_DIR}/podman/cni"
echo "Directory '${DATA_DIR}/podman/cni' created."
else
# If it already exists, print a message
echo "Directory '${DATA_DIR}/podman/cni' already exists. Moving on."
fi
## network configuration
VLAN_ID=20
IPV4_IP_CONTAINER="10.0.20.4"
IPV4_IP_GATEWAY="10.0.20.1"
CONTAINER_NAME="mosquitto"
CONTAINER_CNI_PATH="${DATA_DIR}/podman/cni/45-mosquitto.conflist"
# make sure cni plugs are installed
if ! test -f /opt/cni/bin/macvlan; then
echo "Error: CNI plugins not found. You can install it with the following command:" >&2
echo " curl -fsSLo ${DATA_DIR}/on_boot.d/05-install-cni-plugins.sh https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/cni-plugins/05-install-cni-plugins.sh && /bin/bash ${DATA_DIR}/on_boot.d/05-install-cni-plugins.sh" >&2
exit 1
fi
## network configuration and startup
if ! test -f $CONTAINER_CNI_PATH; then
logger -s -t podman-mosquitto -p ERROR Container network configuration for $CONTAINER_NAME not found, make sure $CONTAINER_CNI_PATH exists
exit 1
fi
# link the conflist into live directory
ln -fs "$CONTAINER_CNI_PATH" "/etc/cni/net.d/$(basename "$CONTAINER_CNI_PATH")"
# set VLAN_ID bridge promiscuous
ip link set br${VLAN_ID} promisc on
# create macvlan bridge and add IPv4 IP
ip link add br${VLAN_ID}.mac link br${VLAN_ID} type macvlan mode bridge
ip addr add ${IPV4_IP_GATEWAY}/24 dev br${VLAN_ID}.mac noprefixroute
# set macvlan bridge promiscuous and bring it up
ip link set br${VLAN_ID}.mac promisc on
ip link set br${VLAN_ID}.mac up
# add IPv4 route to container
ip route add ${IPV4_IP_CONTAINER}/32 dev br${VLAN_ID}.mac
# create basic config if not exist
if ! test -f "$DATA_DIR"/mosquitto/config/mosquitto.conf; then
mkdir -p "$DATA_DIR"/mosquitto"$DATA_DIR" "$DATA_DIR"/mosquitto/config
cat >"$DATA_DIR"/mosquitto/config/mosquitto.conf <<EOF
listener 1883
allow_anonymous true
connection_messages true
persistence true
persistence_location /mosquitto/data/
log_dest stdout
log_type debug
log_timestamp true
EOF
fi
if podman container exists ${CONTAINER_NAME}; then
podman start ${CONTAINER_NAME}
else
logger -s -t podman-mosquitto -p ERROR Container $CONTAINER_NAME not found, make sure you set the proper name, you can ignore this error if it is your first time setting it up
fi

View File

@ -1,60 +1,64 @@
# Run NextDNS on your UDM
# THIS IS NO LONGER MAINTAINED. VENDOR PROVIDES DIRECT SUPPORT
## Features
1. Run NextDNS on your UDM with a completely isolated network stack. This will not port conflict or be influenced by any changes on by Ubiquiti.
1. Run NextDNS on your UDM with a completely isolated network stack. This will not port conflict or be influenced by any changes on by Ubiquiti.
2. Resolves IP addresses handed out by DHCP on the UDM!
3. Persists through reboots and firmware updates.
4. If you are already using PiHole and want to test NextDNS out, you can just stop your PiHole container and start this one in its place using the same IP/CNI config.
## Requirements
1. You have already setup the on boot script described [here](https://github.com/boostchicken/udm-utilities/tree/master/on-boot-script)
1. You have already setup the on boot script described [here](https://github.com/unifi-utilities/unifios-utilities/tree/main/on-boot-script)
## Customization
* Feel free to change [20-dns.conflist](../cni-plugins/20-dns.conflist) to change the IP address of the container.
* The NextDNS docker image is not supported by NextDNS. It is built out of this repo. If you make any enhancements please contribute back via a Pull Request.
* If you want to inject custom DNS names into NextDNS use --add-host docker commands. The /etc/resolv.conf and /etc/hosts is generated from that and --dns.
* Edit [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) and update its values to reflect your environment (specifically the container name)
* If you want IPv6 support use [20-dnsipv6.conflist](../cni-plugins/20-dnsipv6.conflist) and update [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) with the IPv6 addresses. Also, please provide IPv6 servers to podman using --dns arguments.
- Feel free to change [20-dns.conflist](../cni-plugins/20-dns.conflist) to change the IP and MAC address of the container.
- The NextDNS docker image is not supported by NextDNS. It is built out of this repo. If you make any enhancements please contribute back via a Pull Request.
- If you want to inject custom DNS names into NextDNS use --add-host docker commands. The /etc/resolv.conf and /etc/hosts is generated from that and --dns.
- Edit [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) and update its values to reflect your environment (specifically the container name)
- If you want IPv6 support use [20-dnsipv6.conflist](../cni-plugins/20-dnsipv6.conflist) and update [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) with the IPv6 addresses. Also, please provide IPv6 servers to podman using --dns arguments.
## Docker
The official repo is boostchicken/nextdns-udm. Latest will always refer to the latest builds, there are also tags for each NextDNS release (e.g. 1.6.4).
The official repo is boostchicken/nextdns. Latest will always refer to the latest builds, there are also tags for each NextDNS release (e.g. 1.6.4).
The Dockerfile is included, you can build it locally on your UDM if you don't want to pull from Docker Hub or make customizations
```shell script
podman build . -t nextdns-udm:latest
```sh
podman build . -t nextdns:latest
```
Building from another device is possible. You must have [buildx](https://github.com/docker/buildx/) installed to do cross platform builds. This is useful if you want to mirror to a private repo
Building from another device is possible. You must have [buildx](https://github.com/docker/buildx/) installed to do cross platform builds. This is useful if you want to mirror to a private repo
```shell script
docker buildx build --platform linux/arm64/v8 -t nextdns-udm:latest .
```sh
docker buildx build --platform linux/arm64/v8 -t nextdns:latest .
```
## Steps
If you have already installed PiHole, skip right to step 6.
If you have already installed PiHole, skip right to step 5.
1. Copy [05-install-cni-plugins.sh](../cni-plugins/05-install-cni-plugins.sh) to /data/on_boot.d
1. Execute /data/on_boot.d/05-install-cni-plugins.sh
1. On your controller, make a Corporate network with no DHCP server and give it a VLAN. For this example we are using VLAN 5.
2. Copy [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) to /mnt/data/on_boot.d and update its values to reflect your environment
3. Execute /mnt/data/on_boot.d/10-dns.sh
4. Copy [20-dns.conflist](../cni-plugins/20-dns.conflist) to /mnt/data/podman/cni. This will create your podman macvlan network
5. Create /mnt/data/nextdns and copy [nextdns.conf](udm-files/nextdns.conf) to it.
6. Run the NextDNS docker container. Mounting dbus and running in privileged is only required for mDNS. Also, please change the --dns arguments to whatever was provided by NextDNS.
1. Copy [10-dns.sh](../dns-common/on_boot.d/10-dns.sh) to /data/on_boot.d and update its values to reflect your environment
1. Copy [20-dns.conflist](../cni-plugins/20-dns.conflist) to /data/podman/cni. This will create your podman macvlan network
1. Execute /data/on_boot.d/[10-dns.sh](../dns-common/on_boot.d/10-dns.sh)
1. Create /data/nextdns and copy [nextdns.conf](udm-files/nextdns.conf) to it.
1. Run the NextDNS docker container. Mounting dbus and running in privileged is only required for mDNS. Also, please change the --dns arguments to whatever was provided by NextDNS.
```shell script
podman run -d -it --privileged --network dns --restart always \
--name nextdns \
-v "/mnt/data/nextdns/:/etc/nextdns/" \
-v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket \
--mount type=bind,source=/config/dnsmasq.lease,target=/tmp/dnsmasq.leases \
--dns=45.90.28.163 --dns=45.90.30.163 \
--hostname nextdns \
boostchicken/nextdns-udm:latest
```
```sh
podman run -d -it --privileged --network dns --restart always \
--name nextdns \
-v "/data/nextdns/:/etc/nextdns/" \
-v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket \
--mount type=bind,source=/config/dnsmasq.lease,target=/tmp/dnsmasq.leases \
--dns=45.90.28.163 --dns=45.90.30.163 \
--hostname nextdns \
boostchicken/nextdns:latest
```
7. Update your DNS Servers to 10.0.5.3 (or your custom ip) in all your DHCP configs.
1. Update your DNS Servers to 10.0.5.3 (or your custom ip) in all your DHCP configs.

View File

@ -1,5 +1,5 @@
FROM alpine as builder
ENV VERSION=1.7.1
ENV VERSION=1.37.11
LABEL maintainer="John Dorman <dorman@ataxia.cloud>"
RUN wget -O /tmp/nextdns.tar.gz https://github.com/nextdns/nextdns/releases/download/v${VERSION}/nextdns_${VERSION}_linux_arm64.tar.gz \
&& mkdir /tmp/nextdns && tar zxf /tmp/nextdns.tar.gz -C /tmp/nextdns

239
nspawn-container/README.md Normal file
View File

@ -0,0 +1,239 @@
# How to Create a Custom Container on UnifiOS 3.x+
This is a guide that shows you how to create your own container on UnifiOS 3.0+, and how to install custom services in your container (such as pihole or adguard home).
Starting with UnifiOS 3.0, podman/docker support has been removed due to a kernel change. However, you can still create a container with systemd-nspawn, which is what this guide will focus on.
## Table of Contents
1. [Instructions](#instructions)
* [Step 1. Create the Container](#step-1-create-the-container)
* [Step 2. Configure the Container](#step-2-configure-the-container)
* [Step 2A. Configure the Container To Use An Isolated MacVLAN Network](#step-2a-configure-the-container-to-use-an-isolated-macvlan-network)
* [Step 3. Configure Persistence Across Firmware Updates](#step-3-configure-persistence-across-firmware-updates)
* [Step 4. Install Custom Services](#step-4-install-custom-services)
2. [FAQ](#faq)
## Instructions
### Step 1. Create the Container
The following commands are all perfomed on the Unifi router in SSH.
1. We first need to install systemd-container and debootstrap. We will use debootstrap to create a directory with a base debian system, and then use systemd-nspawn to boot the container.
```sh
apt -y install systemd-container debootstrap
```
2. Next, we use debootstrap to create a directory called `debian-custom` with a base debian system in `/data/custom/machines`.
```sh
mkdir -p /data/custom/machines
cd /data/custom/machines
debootstrap --include=systemd,dbus unstable debian-custom
```
* This process can take up to 10 minutes to download and install all the packages.
* The container folder will be 390MB after installation, but can increase to 1GB+ after installing many services (storage management is up to you).
* Note: Instead of debootstrap, you can also use pacstrap or other distributions' tools to create an Arch Linux, Fedora, or other container instead of a debian container (see [examples here](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#Examples)).
3. Finally, let's bring up a shell on this container, set the root password, and enable the networking service. Run each command one-by-one.
```sh
systemd-nspawn -M debian-custom -D /data/custom/machines/debian-custom
passwd root
systemctl enable systemd-networkd
echo "nameserver 1.1.1.1" > /etc/resolv.conf
echo "debian-custom" > /etc/hostname
exit
```
* The first command should put you in a shell in the container. If it doesn't work, something went wrong.
* Note the password will be hidden when you are typing it out in the `passwd root` command, and you will be asked to type it twice.
* We also set the default nameserver to 1.1.1.1 in resolv.conf. You can change this to your own DNS or omit this command if you plan to configure the DNS later.
* The hostname can be set to whatever you want, here debian-custom is used as an example.
### Step 2. Configure the Container
Now that the container is created, let's configure it. Make sure you are back on the host OS and not in the container.
1. First, we will link the container to `/var/lib/machines` so we can control it with `machinectl`.
```sh
mkdir -p /var/lib/machines
ln -s /data/custom/machines/debian-custom /var/lib/machines/
```
2. Next, we will create a `debian-custom.nspawn` file in `/etc/systemd/nspawn` to configure parameters for the container (such as network, bind mounts, etc). Here I use vim to create the file as a personal preference.
```sh
mkdir -p /etc/systemd/nspawn
vim /etc/systemd/nspawn/debian-custom.nspawn
```
* For a container that has access to all the host network interfaces and full capabilities to do anything to the system, here is an example nspawn configuration file. Note it is important to set `Boot=on` so systemd boots up inside the container.
```ini
[Exec]
Boot=on
Capability=all
ResolvConf=off
[Network]
Private=off
VirtualEthernet=off
```
* For a more isolated container configured with a macvlan bridge, follow [Step 2A](#step-2a-configure-the-container-to-use-an-isolated-macvlan-network) below instead before running the container.
* For other options, see the nspawn manpage [here](https://www.freedesktop.org/software/systemd/man/systemd.nspawn.html).
3. After you've configured your nspawn file, let's boot up the container and see if it works.
```sh
machinectl start debian-custom
machinectl enable debian-custom
```
* If the container booted up, you can check `machinectl status debian-custom` for information (hint: press 'q' to exit the status log).
* The second enable command will enable the container to start on boot.
4. Now that the container is running, we should be able to open a shell or login to it.
* Typing `machinectl shell debian-custom` should open a shell to the machine and bypass login. Typing `exit` in this shell will exit back to the host Unifi OS.
* Typing `machinectl login debian-custom` will give you a login prompt like a normal Linux system. In most cases, you can just use `machinectl shell` to bypass the login for easier access. If you do use the login instead of the shell, you can exit the container by holding the `Ctrl` key and pressing the `]` key 3 times.
5. Now that you have access to your own container, you can install whatever services you want within it like a normal Linux system ([see examples below](#step-4-install-custom-services)). Make sure you ran `machinectl enable debian-custom` so the container starts on boot.
### Step 2A: Configure the Container to use an Isolated MacVLAN Network
This configuration is only needed if you want to isolate the container's network with a macvlan bridge. The following steps are all performed on the host OS.
1. Download the [10-setup-network.sh](scripts/10-setup-network.sh) script to `/data/on_boot.d` and configure it with your VLAN and IPs for your container and gateway. This script will create a brX.mac interface as a gateway bridge for containers to communicate with.
```sh
mkdir -p /data/on_boot.d && cd /data/on_boot.d
curl -LO https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/nspawn/nspawn-container/scripts/10-setup-network.sh
vim 10-setup-network.sh
```
* Modify `VLAN` to an existing VLAN network that you want your container to be on. The default is VLAN 5. Make sure this VLAN network is created in Unifi first with a unique subnet and IP (do not use the same IP as you will use for IPV4_IP or IPV4_GW in this script).
* Modify `IPV4_GW` to set the gateway interface's IP. The default is 10.0.5.1/24, but you can use whatever subnet you want as long as it's different than any Unifi subnet.
* Modify `IPV4_IP` to your preferred container IP. The default is 10.0.5.3, but you can use whatever you want as long as its on the same subnet as the gateway subnet `IPV4_GW`.
* Also modify `IPV6_GW` and `IPV6_IP` if you need IPV6 support. Leave them empty for no IPV6 support.
2. Create or modify your `/etc/systemd/nspawn/debian-custom.nspawn` file with the following parameters. This will tell nspawn to isolate the network and create a macvlan interface in the container from our VLAN bridge. This interface will be called mv-br5.
```ini
[Exec]
Boot=on
ResolvConf=off
[Network]
MACVLAN=br5
```
* Change br5 to brX where X = VLAN number you used in `10-setup-network.sh`.
3. Configure your container to set the IP and gateway you defined in `10-setup-network.sh` by creating a network file in the folder `/etc/systemd/network` under your container's directory. Name this file `mv-brX.network` where X = VLAN number you used (e.g. `mv-br5.network`).
```sh
cd /data/custom/machines/debian-custom/etc/systemd/network
vim mv-br5.network
```
* The following is an example configuration based on the default settings in `10-setup-network.sh`.
```ini
[Match]
Name=mv-br5
[Network]
IPForward=yes
Address=10.0.5.3/24
Gateway=10.0.5.1
Address=fd62:89a2:fda9:e23::3/64
Gateway=fd62:89a2:fda9:e23::1
```
* Make sure to change `Name` to the correct VLAN.
* Change `Address` and `Gateway` accordingly if you changed the settings in `10-setup-network.sh`.
* You can remove the last 2 lines with IPv6 addresses if you don't need IPv6.
4. Run the `10-setup-network.sh` script, start the container, open a shell on the container, and check the network.
```sh
chmod +x /data/on_boot.d/10-setup-network.sh
/data/on_boot.d/10-setup-network.sh
machinectl reboot debian-custom
machinectl shell debian-custom
ip addr show
ping -c4 1.1.1.1
```
* You should see the correct IP defined on mv-br5. If no IP has been assigned, make sure you enabled and started the systemd-networkd service and check again: `systemctl enable --now systemd-networkd`
* If you still don't see any IP on mv-br5, then double-check you're using the correct VLAN and put the configuration in the correct location. You can also check `journalctl -eu systemd-networkd` for any errors.
* If pinging 1.1.1.1 doesn't work from within the container, double-check you set the correct container IP in your 10-setup-network.sh.
5. The script `10-setup-network.sh` in `/data/on_boot.d` needs to be started on boot.
* If you've installed the udm-boot service, it should automatically run any scripts in `/data/on_boot.d` and no further setup is needed.
* If you prefer not to use udm-boot and instead use your own systemd boot service, [here is an example systemd service](scripts/setup-network.service) to run this script at boot. Save it to `/etc/systemd/system/setup-network.service` in the host OS (not container) and then enable it with `systemctl enable setup-network`.
### Step 3: Configure Persistence Across Firmware Updates
When the firmware is updated, `/data` (which contains our container storage) and `/etc/systemd` (which contains our boot scripts) are preserved, but `/var` and `/usr` is deleted by the firmware update script. Any additional debian packages that are installed in the host OS like systemd-container are also deleted. This means we need to reinstall the systemd-container package and re-link our container to /var/lib/machines (for machinectl access) when the firmware is upgraded. This can be accomplished with a simple boot script that checks to see if this package is installed on boot.
1. Download the [0-setup-system.sh](scripts/0-setup-system.sh) script into /data/on_boot.d.
```sh
mkdir -p /data/on_boot.d && cd /data/on_boot.d
curl -LO https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/nspawn/nspawn-container/scripts/0-setup-system.sh
chmod +x /data/on_boot.d/0-setup-system.sh
```
2. Download the backup dpkg package files for systemd-container and dependencies into `/data/custom/dpkg`. These packages will only be used as a backup install in case the Internet is down after the first boot after an update.
```sh
mkdir -p /data/custom/dpkg && cd /data/custom/dpkg
apt download systemd-container libnss-mymachines debootstrap arch-test
```
3. The script `0-setup-system.sh` in `/data/on_boot.d` needs to be started on boot.
* If you've installed the udm-boot service, it should automatically run any scripts in `/data/on_boot.d` and no further setup is needed.
* If you prefer not to use udm-boot and instead use your own systemd boot service, [here is an example systemd service](scripts/setup-system.service) to run this script at boot. Save it to `/etc/systemd/system/setup-system.service` in the host OS (not container) and then enable it with `systemctl enable setup-system`.
### Step 4: Install Custom Services
Services can be installed in the container like any linux system. For debian containers, you can use apt or other manual methods. Follow the Debian/Linux guide for your particular software that you want to install.
* Common examples
* [Pi-Hole](examples/pihole/README.md)
* [AdGuard Home](examples/adguardhome/README.md)
## FAQ
1. How do I access a folder from the host OS in the container (e.g. the /data directory)?
* Edit your `.nspawn` config file and add the following `[Files]` section. You can specify multiple `Bind=` or `BindReadOnly=` lines to bind mount multiple directories. See [nspawn manpage](https://www.freedesktop.org/software/systemd/man/systemd.nspawn.html#Bind=) for more details.
```ini
[Files]
Bind=/data:/data
```
2. I am getting security errors trying to run certain privileged commands in the container.
* Edit your `.nspawn` config file and add `Capability=all` under the `[Exec]` section to unlock all security capablitlites. You can also permit or restrict capabilities for enhanced security (see the [nspawn manpage](https://www.freedesktop.org/software/systemd/man/systemd.nspawn.html#Capability=) for more information).
3. Some programs complain of a missing /lib/modules folder and can't access kernel modules.
* Edit your `.nspawn` config file and add `BindReadOnly=/lib/modules` to the `[Files]` section. This will bind mount the /lib/modules folder from the host OS. You might also want to try unlocking all capabilitites or specific ones (as in the above question) if you're still having issues with permissions using certain modules.
4. iptables doesn't work in the container after I installed it.
* You need to use iptables-legacy and not iptables-nft because the host OS is still using the legacy iptables. If using a Debian container, you can switch to the legacy iptables with the following commands executed from within the container. Also, you won't be able to see or modify the host's iptables entries if you're using a private/macvlan network for the container.
```sh
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/bin/ip6tables-legacy
```

View File

@ -0,0 +1,22 @@
## How to Install AdGuard Home in Container
This guide assumes you have already created and started an nspawn container as instructed in the [main README](../../README.md), and have configured an isolated macvlan network for your container.
To install AdGuard Home, we simply run the automated install as instructed in the [AdGuard Home documentation](https://github.com/AdguardTeam/AdGuardHome#automated-install-unix).
1. Spawn a shell to your container.
```sh
machinectl shell debian-custom
```
2. Run the automated install command from the adguard documentation and follow the prompts. Refer to the pihole documentation for more details.
```sh
apt -y install curl
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
```
3. Go to http://10.0.5.3:3000 to configure AdGuard Home (or whatever IP you configured for your container).
4. After configuration, you can access Ad Guard Home web gui at http://10.0.5.3.
5. Now you can set your LAN clients to use the AdGuard Home IP 10.0.5.3 as the DNS, or use dig to test DNS resolution from a client (e.g.: `dig @10.0.5.3 google.com A`).

View File

@ -0,0 +1,149 @@
## Create the filesystem overlay
If you're going to create several nspawn containers, you can save some disk
space by using overlayfs to use a common base. Follow the instructions in the
unifi-utilities [documentation](https://github.com/unifi-utilities/unifios-utilities/blob/main/nspawn-container/README.md)
for UnifiOS 3.0+ containers. I called my container `debian-base`.
Next, we need an `upperdir` where the file changes are saved and a `workdir`
where temporary file changes are saved. I'm going to create a container for
multicast-relay, replacing the [podman container](https://github.com/scyto/multicast-relay)
that I used prior to 3.x. An important note is that upperdir and workdir
must not be on the overlayfs that UnifiOS uses. I opted to store this data
on the hard drive that I use for video storage at `/volume1`.
So, we have the following directories, which you need to create:
- `/var/lib/machines/multicast-relay`: This will be the root directory of
our new container.
- `/volume1/machines/multicast-relay/upper`: This stores the differences from
the base container.
- `/volume1/machines/multicast-relay/work`: This is a temporary directory for
changes before they're saved to `upper`. This could possibly be on a `tmpfs`
mount, but I didn't want to mess with available memory.
- `/data/custom/machines/debian-base`: This is the base container directory
created by following the README linked above.
Do it:
```shell
mkdir -p /var/lib/machines/multicast-relay /volume1/machines/multicast-relay/{upper,work}
```
Now add the matching entry to your fstab. I'm not 100% sure how permanent this is,
but I'll find out when I either reboot or do a firmware upgrade.
Append this to `/etc/fstab`
```
overlay /var/lib/machines/multicast-relay overlay noauto,x-systemd.automount,lowerdir=/data/custom/machines/debian-base,upperdir=/volume1/machines/multicast-relay/upper,workdir=/volume1/machines/multicast-relay/work 0 0
```
If everything is good, you can `mount /var/lib/machines/multicast-relay`. If
there's any error from that, you have some homework to do. This _should_ automount
on reboot, but I haven't tested by rebooting my UDM Pro yet. We'll see 🤞.
## Configure the container
With your overlay in place, you can start the container and install your stuff.
```
systemd-nspawn -M multicast-relay -D /var/lib/machines/multicast-relay
```
You should now be at a root shell inside the container. I configured this all
manually, but you can use the [script](./configure-container.sh) I created during
my trial and error to save yourself some time. Minimal Debian doesn't have
`curl` or `wget`, so you can install one of those and download the script,
or copy-paste into `vi` or something. This is left as an exercise to the reader.
To escape this container, you'll have to press the cheat code given at the start
of your session. (HINT: Press <kbd>Ctrl</kbd> + <kbd>]</kbd> 3 times.)
NOTE: I didn't set the root password, which you will see in many tutorials. It
isn't needed. The host can bypass any login prompt using `machinectl shell <container>`.
You might want to set a root password and/or other user if you are using the
container as a lightweight VM.
## Run the container
If this is your first systemd-nspawn service, you'll need to create the config
directory.
```
mkdir -p /etc/systemd/nspawn
```
Now create the container launch configuration in the file indicated. `multicast-relay`
requires the ability to open raw sockets, so we grant that capability and strip the rest. Be sure you specify the interfaces you wish to use in the `Environment=` line.
Optionally, you can specify additional `multicast-relay` options in `OPTS`
```
# /etc/systemd/nspawn/multicast-relay.nspawn
[Exec]
Boot=on
Capability=CAP_NET_RAW
ResolvConf=off
Environment=INTERFACES="br0 br50"
Environment=OPTS=
[Network]
Private=off
VirtualEthernet=off
```
Once that file is in place, you're ready to enable the container on boot and run it.
```
machinectl enable multicast-relay
machinectl start multicast-relay
```
## Troubleshooting
You can view the stdout of the container in the host journal.
```
journalctl -xe
```
Output from multicast-relay itself won't be found here though. You _should_ be
able to view a containers journal from the host, but I got an error when I tried
suggesting the Debian container has a newer journal format than the UnifiOS host.
No matter, you can just enter the container and get a root shell (no login required).
```
machinectl shell multicast-relay
```
Now, we're setting the interface and options via environment variables set on the
host. If you want to double check that's working correctly, check the environment
of systemd from within the container.
```
cat /proc/1/environ | tr '\0' '\n'
```
output:
```
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
container=systemd-nspawn
HOME=/root
USER=root
LOGNAME=root
container_uuid=c05b41ce-0995-412d-bd2d-338759b24e54
NOTIFY_SOCKET=/run/host/notify
container_host_version_id=11
container_host_id=debian
INTERFACES=br0 br50
```
You could use the same command to view the environment of our service. In this case,
we can use the PID of `dash`, the shell script interpreter from `start.sh`.
```
root@DreamMachinePro:~# cat /proc/$(pidof dash)/environ | tr '\0' '\n'
LANG=C.UTF-8
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
INVOCATION_ID=d1cfaf43a00b4e79bcddca6a1595837c
JOURNAL_STREAM=8:51317778
SYSTEMD_EXEC_PID=47
INTERFACES=br0 br50
```

View File

@ -0,0 +1,40 @@
#!/bin/bash
set -eux -o pipefail
# Install dependencies
apt install -y --no-install-recommends python3 python3-netifaces git ca-certificates
# Checkout latest commit of default branch of multicast-relay
cd /opt
git clone --depth=1 https://github.com/alsmith/multicast-relay.git
# Drop a startup script
cat <<'EOF' | tee /opt/multicast-relay/start.sh
#!/bin/dash
# This script adapted from scyto
# https://github.com/scyto/multicast-relay/blob/master/start.sh
SCRIPT_DIR=$(dirname $(readlink -f $0))
echo "starting multicast-relay"
echo "Using Interfaces: ${INTERFACES}"
echo "Using Options --foreground " $OPTS
python3 "${SCRIPT_DIR}/multicast-relay.py" --interfaces ${INTERFACES} --foreground $OPTS
EOF
chmod +x /opt/multicast-relay/start.sh
# Install and enable a systemd service
cat <<'EOF' | tee /etc/systemd/system/multicast-relay.service
[Unit]
Description=multicast relay service
[Service]
PassEnvironment=INTERFACES OPTS
ExecStart=/opt/multicast-relay/start.sh
[Install]
WantedBy=multi-user.target
EOF
systemctl enable multicast-relay.service

View File

@ -0,0 +1,48 @@
## How to Install Pi-Hole in Container
This guide assumes you have already created and started an nspawn container as instructed in the [main README](../../README.md), and have configured an isolated macvlan network for your container.
To install pihole, we simply run the automated install as instructed in the [pihole documentation](https://docs.pi-hole.net/main/basic-install/) and follow the prompts.
1. Spawn a shell to your container.
```sh
machinectl shell debian-custom
```
2. Run the automated install command from the pihole documentation and follow the prompts. Refer to the pihole documentation for more details.
```sh
apt -y install curl
curl -sSL https://install.pi-hole.net | PIHOLE_SKIP_OS_CHECK=true bash
```
* You must use `PIHOLE_SKIP_OS_CHECK=true` so pihole can be installed on Debian unstable.
* After installation, the debian-custom container has a size of 611 MB after running `apt clean` to delete the package cache.
3. When the install says a static IP is needed, press Continue.
4. Select an upstream DNS provider on the next page, or add your custom DNS provider. Note all these options can be changed later in the admin panel, so you don't need to be perfect here.
5. On the next page, choose "Yes" to include the default list or "No" to not include any block lists at install (you will have to install your own later in that case).
6. On the next page, choose "Yes" to install the Admin web interface, then "Yes" on the next page to install the default web server that pihole uses (lighthttpd). It's also possible to use nginx instead of lighthttpd, but this isn't covered in this tutorial.
7. On the next two pages, click Yes to enable Query Logging, and enable "Show everything". You can disable query logging or hide information from the log if you prefer.
8. Once the install is finished, it will tell you what your pihole IP and admin password is.
9. You can either use the current admin password the installation gave you, or run `pihole -a -p` to update the password.
10. You should now be able to access the pihole admin page at https://10.0.5.3/admin if you used the default container IP.
11. As a final step, you need to set "Permit all origins" in the Pi-Hole Admin to allow requests from more than one hop away (i.e. your LAN clients). Go to Pi-Hole Admin -> Settings -> DNS -> Permit all origins -> Save.
12. Now you can set your LAN clients to use the pihole IP 10.0.5.3 as the DNS, or use dig to test DNS resolution from a client (e.g.: `dig @10.0.5.3 google.com A`).
## How to Update or Reconfigure Pi-Hole.
To update pihole, simply run the following from within the container.
```sh
PIHOLE_SKIP_OS_CHECK=true pihole -up
```
In case there is a configuration error and pihole is having trouble, you can reconfigure it from scratch by running:
```sh
PIHOLE_SKIP_OS_CHECK=true pihole -r
```

View File

@ -0,0 +1,280 @@
#!/bin/bash
###################################################################
#Script Name : interactive_setup
#Description : This script guides you through creating a custom container on UnifiOS 3.0+ using systemd-nspawn.
# It includes steps for configuring the container, ensuring persistence across firmware updates,
# and installing custom services such as pihole (Not Yet) or adguard home.
# The process involves installing systemd-container and debootstrap and using them to create
# a base debian system in /data/custom/machines directory.
#Author : Apo-mak
#Last Date Edited : 09-06-2023
###################################################################
set -e
container_name="debian-custom"
container_root_pasword="12345678"
vlan_id="5"
vlan_address="10.0.5.3/24"
vlan_gateway="10.0.5.1"
##
# Color Variables
##
green='\e[32m'
blue='\e[34m'
clear='\e[0m'
##
# Color Functions
##
ColorGreen(){
echo -ne $green$1$clear
}
ColorBlue(){
echo -ne $blue$1$clear
}
##############################################
function set_variables(){
read -p "Enter the container name [$container_name]: " container_name
container_name=${container_name:-"debian-custom"}
read -p "Enter the container root password [$container_root_pasword]: " container_root_pasword
container_root_pasword=${container_root_pasword:-"12345678"}
}
function set_container_network_variables(){
read -p "Enter the container vlan_id [$vlan_id]: " vlan_id
vlan_id=${vlan_id:-"5"}
read -p "Enter the container vlan_address [$vlan_address]: " vlan_address
vlan_address=${vlan_address:-"10.0.5.3/24"}
read -p "Enter the container vlan_gateway [$vlan_gateway]: " vlan_gateway
vlan_gateway=${vlan_gateway:-"10.0.5.1"}
}
function echo_variables(){
echo "#### Printing set Variables: ###"
echo "Container Name: $container_name "
echo "Container Root Password: $container_root_pasword "
echo "Network Vlan ID: $vlan_id "
echo "Container $vlan_address "
echo "Network Getway: $vlan_gateway "
}
function create_custom_container_simple(){
echo "You have selected to setup a container that has access to all the host network
interfaces and full capabilities to do anything to the system"
read -p "Press enter to continue OR ctrl + c to cancel."
create_custom_container ;
setup_networking_simple ;
setup_persistence ;
setup_backup_dpkg_files
}
function create_custom_container_macvlan(){
echo "You have selected to setup a container to use an Isolated MacVLAN Network AKA Vlan."
read -p "Press enter to continue OR ctrl + c to cancel."
create_custom_container ;
setup_networking_MACVLAN ;
setup_persistence ;
setup_backup_dpkg_files
}
function create_custom_container() {
echo ""
echo " Creating a Custom Container on UnifiOS 3.x"
echo ""
#### check if directory exists and abort
if [ -d "/data/custom/machines/$container_name" ]
then
echo "Directory /data/custom/machines/$container_name already exists... aborting the setup ...
try manual setup or setup with new container name."
exit 1
fi
### Step 1. Create the Container
echo " Installing the systemd-container and debootstrap"
apt -y install systemd-container debootstrap
### create a directory called "$container_name" with a base debian system in /data/custom/machines
echo "Creating container required directories"
mkdir -p /data/custom/machines
cd /data/custom/machines
debootstrap --include=systemd,dbus unstable "$container_name"
### Finally, let's bring up a shell on this container
echo "Set container Root password, Network setting and enable systemd-networkd"
#systemd-nspawn -M "$container_name" -D /data/custom/machines/"$container_name"
#systemd-nspawn -M "$container_name" -D /data/custom/machines/"$container_name" echo "This Echo is from inside the new Container ..."
systemd-nspawn -M "$container_name" -D /data/custom/machines/"$container_name" /bin/bash -c "echo 'root:${container_root_pasword}' | chpasswd"
echo "In container start network"
systemd-nspawn -M "$container_name" -D /data/custom/machines/"$container_name" /bin/bash -c systemctl enable systemd-networkd
echo "in container set default DNS 1.1.1.1"
systemd-nspawn -M "$container_name" -D /data/custom/machines/"$container_name" /bin/bash -c echo "nameserver 1.1.1.1" > /etc/resolv.conf \
echo ""$container_name"" > /etc/hostname
#### we will link the container to /var/lib/machines so we can control it with machinectl
echo "Linking the container to /var/lib/machines"
mkdir -p /var/lib/machines
ln -s /data/custom/machines/"$container_name" /var/lib/machines/
}
function setup_networking_simple() {
echo ""
echo " Setting up networking Simple"
echo ""
##### we will create a "$container_name".nspawn file in /etc/systemd/nspawn to configure parameters for the container
######(such as network, bind mounts, etc)
echo "configuring parameters for the container "
mkdir -p /etc/systemd/nspawn
cat <<EOF > /etc/systemd/nspawn/"$container_name".nspawn
[Exec]
Boot=on
Capability=all
[Network]
Private=off
VirtualEthernet=off
ResolvConf=off
EOF
}
function setup_networking_MACVLAN() {
echo ""
echo " Setting up networking MACVLAN"
echo ""
#####we will create a "$container_name".nspawn file in /etc/systemd/nspawn to configure parameters for the container
######(such as network, bind mounts, etc)
echo "configuring parameters for the container "
mkdir -p /etc/systemd/nspawn
cat <<EOF > /etc/systemd/nspawn/"$container_name".nspawn
[Exec]
Boot=on
[Network]
MACVLAN=br$vlan_id
ResolvConf=off
EOF
##### Configure the Container to use an Isolated MacVLAN Network
echo " Configuring the Container to use an Isolated MacVLAN Network"
cd /data/on_boot.d
if [ -f "$file" ] ; then
rm "$file"
fi
curl -LO https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/nspawn/nspawn-container/scripts/10-setup-network.sh
chmod +x 10-setup-network.sh
cat <<EOF > /etc/systemd/nspawn/"$container_name".nspawn
[Exec]
Boot=on
[Network]
MACVLAN=br$vlan_id
ResolvConf=off
EOF
#####Configure your container to set the IP and gateway you defined in 10-setup-network.sh
cd /data/custom/machines/"$container_name"/etc/systemd/network
cat <<EOF > mv-br${vlan_id}.network
[Match]
Name=mv-br$vlan_id
[Network]
IPForward=yes
Address=$vlan_address
Gateway=$vlan_gateway
EOF
#### Run the 10-setup-network.sh script to setup the network interface
/data/on_boot.d/10-setup-network.sh
machinectl stop "$container_name"
machinectl start "$container_name"
}
function setup_adguard() {
echo "You have selected to setup a AdGuardHome in container $container_name"
read -p "Press enter to continue OR ctrl + c to cancel."
echo ""
echo " Setting up adguard"
echo ""
############ install addguard #######
systemd-nspawn -M "$container_name" -D /data/custom/machines/"$container_name" /bin/bash -c "apt -y install curl &&
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v"
echo "Go to http://${vlan_address}:3000 to configure AdGuard Home (or whatever IP your container has if you had select simple install)."
read -p "Press enter to continue"
}
function setup_persistence() {
echo ""
echo " Configuring Persistence Across Firmware Updates"
echo ""
#### Configure Persistence Across Firmware Updates
echo "Configuring Persistence Across Firmware Updates"
cd /data/on_boot.d
curl -LO https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/nspawn/nspawn-container/scripts/0-setup-system.sh
chmod +x 0-setup-system.sh
mv 0-setup-system.sh 02-setup-system.sh
}
function setup_backup_dpkg_files() {
echo ""
echo " Downloading the backup dpkg package files"
echo ""
#### Download the backup dpkg package files for systemd-container and dependencies into /data/custom/dpkg.
#####These packages will only be used as a backup install in case the Internet is down after the first boot after an update.
echo "Configuring backup install"
mkdir -p /data/custom/dpkg && cd /data/custom/dpkg
apt download systemd-container libnss-mymachines debootstrap arch-test
echo " Container setup has ended .. :) "
}
menu(){
echo -ne "
Create a container with systemd-nspawn
Select your option from below:
$(ColorGreen '1)') Create a Custom Container Simple
$(ColorGreen '2)') Create a Custom Container Mac Vlan
$(ColorGreen '3)') Install Adguard in existing container.
$(ColorGreen '4)') Print set Variables.
$(ColorGreen '5)') Set Container Variables (name & Root Password).
$(ColorGreen '6)') Set Container Network Variables. (Vlan ID & IP address).
$(ColorGreen '0)') Exit
$(ColorBlue 'Choose an option:') "
read a
case $a in
1) create_custom_container_simple ; menu ;;
2) create_custom_container_macvlan ; menu ;;
3) setup_adguard ; menu ;;
4) echo_variables ; menu ;;
5) set_variables ; menu ;;
6) set_container_network_variables ; menu ;;
0) exit 0 ;;
*) echo -e $red"Wrong option."$clear; WrongCommand;;
esac
}
# Call the menu function
menu

View File

@ -0,0 +1,20 @@
#!/bin/bash
# This script installs systemd-container if it's not installed.
# Also links any containers from /data/custom/machines to /var/lib/machines.
set -e
if ! dpkg -l systemd-container | grep ii >/dev/null; then
if ! apt -y install systemd-container debootstrap; then
yes | dpkg -i /data/custom/dpkg/*.deb
fi
fi
mkdir -p /var/lib/machines
for machine in $(ls /data/custom/machines/); do
if [ ! -e "/var/lib/machines/$machine" ]; then
ln -s "/data/custom/machines/$machine" "/var/lib/machines/"
machinectl enable $machine
machinectl start $machine
fi
done

View File

@ -0,0 +1,84 @@
#!/bin/bash
# This script will create a macvlan bridge interface to allow communication
# between container networks and host networks.
# An interface called brX.mac will be created, where X = $VLAN configured below.
# The interface will be assigned an IP of $IPV4_GW, and $IPV6_GW configured below.
# Routes will be added for the container IP $IPV4 and $IPV6.
# Script is based on 10-dns.sh from unifios-utilities.
## CONFIGURATION VARIABLES
# VLAN ID network container will be on. This VLAN has to first be configured as a
# network in Unifi Network settings with a unique IP/subnet. Do not use the same
# IP in the unifi network settings as you will use below for IPV4_IP or IPV4_GW.
VLAN=5
# IP addresses of container.
IPV4_IP="10.0.5.3"
# Gateway IP address of macvlan interface. IP above should be in this subnet.
IPV4_GW="10.0.5.1/24"
# IPv6 container and gateway addresses. These can be empty if not using IPv6.
# Preferably generate your own ULA instead of using the default one below.
# A public IPv6 prefix based on your ISP's prefix can be used too, but any
# prefix changes for dynamic IPv6 prefixes have to be modified manually.
IPV6_IP="fd62:89a2:fda9:e23::3"
IPV6_GW="fd62:89a2:fda9:e23::1/64"
# Set this to the interface(s) on which you want DNS TCP/UDP port 53 traffic
# re-routed through this container. Separate interfaces with spaces.
# This is useful when runinng a DNS service, like Adguard Home
# e.g. "br0" or "br0 br1" etc.
FORCED_INTFC=""
## END OF CONFIGURATION
# set VLAN bridge promiscuous
ip link set "br${VLAN}" promisc on
# create macvlan bridge and add IPv4 IP
ip link add "br${VLAN}.mac" link "br${VLAN}" type macvlan mode bridge
ip addr add "${IPV4_GW}" dev "br${VLAN}.mac" noprefixroute
# (optional) add IPv6 IP to VLAN bridge macvlan bridge
if [ -n "${IPV6_GW}" ]; then
ip -6 addr add "${IPV6_GW}" dev "br${VLAN}.mac" noprefixroute
fi
# set macvlan bridge promiscuous and bring it up
ip link set "br${VLAN}.mac" promisc on
ip link set "br${VLAN}.mac" up
# add IPv4 route to container
ip route add "${IPV4_IP}/32" dev "br${VLAN}.mac"
# (optional) add IPv6 route to container
if [ -n "${IPV6_IP}" ]; then
ip -6 route add "${IPV6_IP}/128" dev "br${VLAN}.mac"
fi
# Make DNSMasq listen to the container network for split horizon or conditional forwarding
if ! grep -qxF "interface=br${VLAN}.mac" /run/dnsmasq.conf.d/custom.conf; then
echo "interface=br${VLAN}.mac" >>/run/dnsmasq.conf.d/custom.conf
kill -9 "$(cat /run/dnsmasq.pid)"
fi
# (optional) IPv4 force DNS (TCP/UDP 53) through DNS container
for intfc in ${FORCED_INTFC}; do
if [ -d "/sys/class/net/${intfc}" ]; then
for proto in udp tcp; do
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV4_IP} ! -d ${IPV4_IP} --dport 53 -j LOG --log-prefix [DNAT-${intfc}-${proto}]"
iptables -t nat -C ${prerouting_rule} 2>/dev/null || iptables -t nat -A ${prerouting_rule}
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV4_IP} ! -d ${IPV4_IP} --dport 53 -j DNAT --to ${IPV4_IP}"
iptables -t nat -C ${prerouting_rule} 2>/dev/null || iptables -t nat -A ${prerouting_rule}
# (optional) IPv6 force DNS (TCP/UDP 53) through DNS container
if [ -n "${IPV6_IP}" ]; then
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV6_IP} ! -d ${IPV6_IP} --dport 53 -j LOG --log-prefix [DNAT-${intfc}-${proto}]"
ip6tables -t nat -C ${prerouting_rule} 2>/dev/null || ip6tables -t nat -A ${prerouting_rule}
prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV6_IP} ! -d ${IPV6_IP} --dport 53 -j DNAT --to ${IPV6_IP}"
ip6tables -t nat -C ${prerouting_rule} 2>/dev/null || ip6tables -t nat -A ${prerouting_rule}
fi
done
fi
done

View File

@ -0,0 +1,13 @@
[Unit]
Description=Setup custom container network service
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/data/on_boot.d/10-setup-network.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
[Unit]
Description=Setup custom container service
Wants=network-online.target
After=network-online.target
StartLimitBurst=5
[Service]
Type=oneshot
ExecStart=/data/on_boot.d/0-setup-system.sh
RemainAfterExit=yes
RestartSec=30
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,18 @@
FROM debian:bookworm-slim
RUN set -ex \
&& echo 'deb http://deb.debian.org/debian bookworm-backports main' > /etc/apt/sources.list.d/backports.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
devscripts \
fakeroot \
debhelper=12.\* dh-autoreconf=17\* \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -rf /tmp/* /var/tmp/* /var/log/* /var/lib/apt/lists/* /var/log/alternatives.log
RUN chmod a+rwx,u+t /tmp
ENTRYPOINT []
CMD ["/bin/sh"]

View File

@ -0,0 +1,61 @@
# UDM / UDMPro Boot Script
## Features
1. Allows you to run a shell script at S95 anytime your UDM starts / reboots
## Compatibility
1. Should work on any UDM/UDMPro after 2.4.x
- [build_deb.sh](build_deb.sh) can be used to build the package by yourself.
- [dpkg-build-files](dpkg-build-files) contains the sources that debuild uses to build the package if you want to build it yourself / change it
- by default it uses docker or podman to build the debian package
- use `./build_deb.sh build` to not use a container
- the resulting package will be in [packages/](packages/)
- Built on Ubuntu-20.04 on Windows 10/WSL2
## Install
You can execute in UDM/Pro/SE and UDR with:
```bash
curl -fsL "https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/HEAD/on-boot-script-2.x/remote_install.sh" | /bin/bash
```
This is a force to install script so will uninstall any previous version and install on_boot keeping your on boot files.
This will also install CNI Plugins & CNI Bridge scripts. If you are using UDMSE/UDR remember that you must install podman manually because there is no podman.
## Manually Install Steps
1. Get into the unifios shell on your udm
```bash
unifi-os shell
```
2. Download [udm-boot-2x_1.0.1_all.deb](packages/udm-boot-2x_1.0.1_all.deb) and install it and go back to the UDM.
```bash
curl -L [[https://unifi.boostchicken.io/udm-boot-v2+/udm-boot-2x_1.0.1_all.deb](https://unifi.boostchicken.io/udm-boot-v2+/udm-boot-2x_1.0.1_all.deb)](https://unifi.boostchicken.io/udm-boot-v2+/udm-boot-2x_1.0.1_all.deb) -o udm-boot-2x_1.0.1_all.deb
dpkg -i udm-boot-2x_1.0.1_all.deb
systemctl enable udm-boot
exit
```
3. Copy any shell scripts you want to run to /data/on_boot.d on your UDM (not the unifi-os shell) and make sure they are executable and have the correct shebang (#!/bin/bash). Additionally, scripts need to have a `.sh` extention in their filename.
Examples:
- Start a DNS Container [10-dns.sh](../dns-common/on_boot.d/10-dns.sh)
- Start wpa_supplicant [on_boot.d/10-wpa_supplicant.sh](examples/udm-files/on_boot.d/10-wpa_supplicant.sh)
- Add a persistent ssh key for the root user [on_boot.d/15-add-root-ssh-keys.sh](examples/udm-files/on_boot.d/15-add-root-ssh-keys.sh)
## Version History
### 1.0.0
- First release that persists through firmware

101
on-boot-script-2.x/build_deb.sh Executable file
View File

@ -0,0 +1,101 @@
#!/bin/bash
set -e
WORK_DIR="$(cd "$(dirname "$0")" && echo "${PWD}")"
TARGET_DIR="${WORK_DIR}/packages"
SOURCE_DIR="${WORK_DIR}/dpkg-build-files"
CONTAINER_FILE="${WORK_DIR}/Dockerfile"
CONTAINER_CONTEXT="${WORK_DIR}"
fatal() {
echo "ERROR: ${1}" 1>&2
exit ${2-1}
}
build_in_container=false
build=false
build_container=false
if [ $# -eq 0 ]; then
build_in_container=true
fi
if [ "${1}" = "build" ]; then
build=true
fi
if [ "${1}" = "build_container" ]; then
build_container=true
fi
build_in_container() {
docker_exec="$(command -v docker || true)"
podman_exec="$(command -v podman || true)"
container_exec="${docker_exec:-"${podman_exec}"}"
container_args=""
if [ ! -f "${container_exec}" ]; then
fatal "docker or podman not found"
fi
if [ ! -f "${CONTAINER_FILE}" ]; then
fatal "container file ${CONTAINER_FILE} not found"
fi
if [ "${container_exec}" = "${docker_exec}" ]; then
# docker does not map user, so we run it as user
container_args="--user "$(id -u):$(id -g)""
fi
"${container_exec}" build --file "${CONTAINER_FILE}" --tag udm-boot-deb-builder "${CONTAINER_CONTEXT}"
"${container_exec}" run -it \
${container_args} \
-v "${SOURCE_DIR}:/source:ro" \
-v "${TARGET_DIR}:/target:rw" \
-v "${WORK_DIR}/build_deb.sh:/build_deb.sh:ro" \
--rm \
udm-boot-deb-builder \
/build_deb.sh build_container
}
build() {
source_dir=$1
target_dir=$2
version="$(dpkg-parsechangelog --show-field version -l "${source_dir}/debian/changelog")"
name="$(dpkg-parsechangelog --show-field source -l "${source_dir}/debian/changelog")"
package_name="${name}-${version}"
build_dir="$(mktemp --tmpdir="/tmp" --directory "${name}.XXXXXXXXXX")"
build_package_dir="${build_dir}/${package_name}"
if [ ! -d "${source_dir}" ]; then
fatal "source dir ${source_dir} not found"
fi
if [ ! -d "${target_dir}" ]; then
fatal "target dir ${target_dir} not found"
fi
mkdir -p "${build_package_dir}"
cp -r "${source_dir}"/* "${build_package_dir}"
(
cd "${build_package_dir}"
# we could exclude "source" here to skip building the source,
# but lintian warns only in the source build about some stuff
debuild -us -uc --build=source,all --lintian-opts --profile debian
)
find "${build_dir}" -maxdepth 1 -type f -exec mv {} "${target_dir}" \;
rm -rf "${build_dir}"
}
build_container() {
build "/source" "/target"
}
if [ $build_in_container = true ]; then
build_in_container
fi
if [ $build = true ]; then
build "${SOURCE_DIR}" "${TARGET_DIR}"
fi
if [ $build_container = true ]; then
build_container
fi

View File

@ -0,0 +1,12 @@
udm-boot-2x (1.0.1) stable; urgency=medium
* Using bash to invoke
-- Boostchicken <john@boostchicken.dev> Sat, 21 Feb 2023 18:46:14 -0700
udm-boot-2x (1.0.0) stable; urgency=medium
* Initial release, happy firmware persisting!
-- Boostchicken <john@boostchicken.dev> Sat, 18 Feb 2023 18:46:14 -0700

View File

@ -0,0 +1,15 @@
Source: udm-boot-2x
Section: contrib/utils
Priority: optional
Maintainer: Boostchicken <john@boostchicken.dev>
Build-Depends: debhelper-compat (= 12)
Standards-Version: 4.4.1
Homepage: https://github.com/unifi-utilities/unifios-utilities
#Vcs-Browser: https://salsa.debian.org/debian/udmboot
#Vcs-Git: https://salsa.debian.org/debian/udmboot.git
Package: udm-boot-2x
Architecture: all
Depends: ${misc:Depends}
Description: Run things on boot on UDM 2.x
Run things on boot!

View File

@ -0,0 +1,9 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: udm-boot-2x
Upstream-Contact: John Dorman / Boostchicken
Source: https://github.com/unifi-utilities/unifi-utilities
Files: *
Copyright: 2023 john@boostchicken.dev
License: GPL-3
https://github.com/unifi-utilities/unifi-utilities/blob/main/LICENSE

View File

@ -0,0 +1 @@
udm-boot.service lib/systemd/system/

View File

@ -0,0 +1,40 @@
#!/bin/sh
# postinst script for udm-boot
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
alias deb-systemd-invoke='systemctl --no-block --'
case "$1" in
configure)
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@ -0,0 +1,38 @@
#!/bin/sh
# postrm script for udm-boot
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
true
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@ -0,0 +1,37 @@
#!/bin/sh
# preinst script for udm-boot
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
install|upgrade)
true
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@ -0,0 +1,40 @@
#!/bin/bash
# prerm script for udm-boot
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
# reserved for future use
true
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@ -0,0 +1,8 @@
#!/usr/bin/make -f
%:
dh $@
override_dh_builddeb:
dh_builddeb -- -Zgzip

View File

@ -0,0 +1 @@
3.0 (native)

View File

@ -0,0 +1,3 @@
udm-boot-2x source: changelog-should-mention-nmu
udm-boot-2x source: source-nmu-has-incorrect-version-number
udm-boot-2x source: odd-historical-debian-changelog-version

View File

@ -0,0 +1,16 @@
[Unit]
Description=Run On Startup UDM 2.x
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=500
StartLimitBurst=5
[Service]
Restart=on-failure
RestartSec=5s
ExecStart=bash -c 'mkdir -p /data/on_boot.d && find -L /data/on_boot.d -mindepth 1 -maxdepth 1 -type f -print0 | sort -z | xargs -0 -r -n 1 -- sh -c '\''if test -x "$0"; then echo "%n: running $0"; "$0"; else case "$0" in *.sh) echo "%n: sourcing $0"; . "$0";; *) echo "%n: ignoring $0";; esac; fi'\'
RemainAfterExit=true
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,42 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## Configure shell profile
device_info() {
echo $(/usr/bin/ubnt-device-info "$1")
}
# Modify login banner (motd)
cat >/etc/motd <<EOF
Welcome to UniFi Dream Machine!
(c) 2010-$(date +%Y) Ubiquiti Inc. | http://www.ui.com
Model: $(device_info model)
Version: $(device_info firmware)
MAC Address: $(device_info mac)
EOF
# Extend UbiOS prompt to include useful information
cat >/etc/profile.d/prompt.sh <<'EOF'
UDM_NAME="$(grep -m 1 '^name:' ${DATA_DIR}/unifi-core/config/settings.yaml | awk -F: '{ gsub(/^[ \t]+|[ \t]+$/, "", $2); print tolower($2) }')"
PROMPT_MAIN="\u@${UDM_NAME}:\w"
export PS1="[UDM] ${PROMPT_MAIN}${PS1}"
EOF
# Copy all global profile scripts (for all users) from `${DATA_DIR}/on_boot.d/settings/profile/global.profile.d/` directory
mkdir -p ${DATA_DIR}/on_boot.d/settings/profile/global.profile.d
cp -rf ${DATA_DIR}/on_boot.d/settings/profile/global.profile.d/* /etc/profile.d/

View File

@ -0,0 +1,7 @@
#!/bin/bash
## create files like this with different numbers for execution order
## ala /etc/profile.d
## example command to run, please replace with your own.
podman start wpa_supplicant-udmpro

View File

@ -0,0 +1,19 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2*)
DATA_DIR="/data"
;;
3*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
cp -f ${DATA_DIR}/on_boot.d/files/.profile /root/

View File

@ -0,0 +1,76 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## Config Variables - please edit these
# Set to true to download public keys from a github user account
USE_GITHUB_KEYS=true
# Enter your username on github to get the public keys for
GITHUB_USER="<YOUR_USERNAME>"
# File location for the output of the git download
GITHUB_KEY_PATH="${DATA_DIR}/podman/ssh"
GITHUB_KEY_FILE="${GITHUB_KEY_PATH}/github.keys"
# Set to true to use a file containing a key per line in the format ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAA...\n
USE_KEY_FILE=true
# IF using an input file, list it here
INPUT_KEY_PATH="${DATA_DIR}/podman/ssh"
INPUT_KEY_FILE="${INPUT_KEY_PATH}/ssh.keys"
# The target key file for the script
OUTPUT_KEY_PATH="/root/.ssh"
OUTPUT_KEY_FILE="${OUTPUT_KEY_PATH}/authorized_keys"
## Functions
# This function downloads the keys from the selected github user
download_from_github() {
if curl --output /dev/null --silent --head --fail https://github.com/${GITHUB_USER}.keys; then
curl https://github.com/${GITHUB_USER}.keys -o ${GITHUB_KEY_FILE}
echo "Downloaded keys from Github"
else
echo "Could not download ${GITHUB_USER}'s key file from github"
fi
}
# Write line to the output line. Add the input line as an arguement.
write_to_output() {
# Check the file exits
if ! test -f ${OUTPUT_KEY_FILE}; then
echo "File at ${OUTPUT_KEY_FILE} does not exist, creating it"
touch ${OUTPUT_KEY_FILE}
fi
echo "${1}" >>${OUTPUT_KEY_FILE}
}
# This function reads keys from a file into the requested file. The arguement is the input file.
use_key_from_file() {
if ! test -f $1; then
echo "File $1 does not exist"
return
fi
counter=0
while IFS= read -r line; do
write_to_output "${line}"
let "counter++"
done <$1
echo "${counter} number of entries read from "
}
## Script
# Makes paths if they don't exit
mkdir -p ${GITHUB_KEY_PATH} ${INPUT_KEY_PATH} ${OUTPUT_KEY_PATH}
#Check flags to see which files to use
if [ ${USE_GITHUB_KEYS} = true ]; then
download_from_github
use_key_from_file ${GITHUB_KEY_FILE}
fi
if [ ${USE_KEY_FILE} = true ]; then
use_key_from_file ${INPUT_KEY_FILE}
fi

View File

@ -0,0 +1,41 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## Places public keys in ~/.ssh/authorized_keys
KEYS_SOURCE_FILE="${DATA_DIR}/on_boot.d/settings/ssh/authorized_keys"
KEYS_TARGET_FILE="/root/.ssh/authorized_keys"
count_added=0
count_skipped=0
while read -r key; do
# Places public key in ~/.ssh/authorized_keys if not present
if ! grep -Fxq "$key" "$KEYS_TARGET_FILE"; then
let count_added++
echo "$key" >>"$KEYS_TARGET_FILE"
else
let count_skipped++
fi
done <"$KEYS_SOURCE_FILE"
echo "${count_added} keys added to ${KEYS_TARGET_FILE}"
if [ $count_skipped -gt 0 ]; then
echo "${count_skipped} already added keys skipped"
fi
# Convert ssh key to dropbear for shell interaction
echo "Converting SSH private key to dropbear format"
dropbearconvert openssh dropbear ${DATA_DIR}/ssh/id_rsa /root/.ssh/id_dropbear
exit 0

View File

@ -0,0 +1,38 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
#####################################################
# ADD KNOWN HOSTS AS BELOW - CHANGE BEFORE RUNNING #
#####################################################
# set -- "known host text on a line with quotes " \ #
# "second known host on another line " \ #
# "one per line, last line has no backslash" #
#####################################################
set -- "hostname ecdsa-sha2-nistp256 AAAABIGHOSTIDENTIFIERWITHMAGICSTUFF=" \
"otherhost ecdsa-sha2-nistp256 AAAADIFFERENTHOSTMAGICSTUFF!@HJKSL="
KNOWN_HOSTS_FILE="/root/.ssh/known_hosts"
counter=0
for host in "$@"; do
## Places known host in ~/.ssh/known_hosts if not present
if ! grep -Fxq "$host" "$KNOWN_HOSTS_FILE"; then
let counter++
echo "$host" >>"$KNOWN_HOSTS_FILE"
fi
done
echo $counter hosts added to $KNOWN_HOSTS_FILE
exit 0

View File

@ -0,0 +1,26 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
mkdir -p ${DATA_DIR}/.home
for file in .ash_history .bash_history; do
if [ ! -f ${DATA_DIR}/.home/$file ]; then
touch /root/$file
cp /root/$file ${DATA_DIR}/.home/$file
chown root:root ${DATA_DIR}/.home/$file
chmod 0600 ${DATA_DIR}/.home/$file
fi
ln -sf ${DATA_DIR}/.home/$file /root/$file
done

View File

@ -0,0 +1,7 @@
#!/bin/bash
## create files like this with different numbers for execution order
## ala /etc/profile.d
## Start the ntopng-udm container, from https://github.com/tusc/ntopng-udm
podman start ntopng

View File

@ -0,0 +1,22 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2* | 3* | 4*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## Store crontab files in ${DATA_DIR}/cronjobs/ (you will need to create this folder).
## This script will re-add them on startup.
cp ${DATA_DIR}/cronjobs/* /etc/cron.d/
/etc/init.d/crond restart
exit 0

View File

@ -0,0 +1,10 @@
#!/bin/bash
CONTAINER=node-exporter
# Starts a Prometheus node-exporter container that is deleted after it is stopped.
if podman container exists "${CONTAINER}"; then
podman start "${CONTAINER}"
else
podman run -d --rm --name "${CONTAINER}" --net="host" --pid="host" -v "/:/host:ro,rslave" quay.io/prometheus/node-exporter:latest --path.rootfs=/host
fi

View File

@ -0,0 +1,15 @@
#!/bin/bash
alias -='cd -'
alias ...=../..
alias ....=../../..
alias .....=../../../..
alias ......=../../../../..
alias cp='cp -i'
alias la='ls -lAFh'
alias ll='ls -l'
alias md='mkdir -p'
alias mkcd='foo(){ mkdir -p "$1"; cd "$1" }; foo'
alias mv='mv -i'
alias rd=rmdir
alias rm='rm -i'

View File

@ -0,0 +1,100 @@
#!/bin/bash
# Get DataDir location
DATA_DIR="/data"
case "$(ubnt-device-info firmware || true)" in
1*)
DATA_DIR="/mnt/data"
;;
2*)
DATA_DIR="/data"
;;
3*)
DATA_DIR="/data"
;;
*)
echo "ERROR: No persistent storage found." 1>&2
exit 1
;;
esac
## ----------------------------------------------------------------------
## Script to add/remove time-of-day restrictions on internet access for selected clients.
##
## Use DHCP reservations to encourage the selected clients to always obtain the same IP address.
##
## To install:
## * Copy this script into ${DATA_DIR}/on_boot.d/, using something like WinSCP or SSH + vi.
## * Grant Execute permission: chmod +x ${DATA_DIR}/on_boot.d/iptables_timerestrict.sh
## * Run it once, to activate it (crontab entries will keep it active forever after):
## Via SSH into UDM shell: ${DATA_DIR}/on_boot.d/iptables_timerestrict.sh
##
## Notes:
## * Changes to firewall rules in the Unifi Network Application will remove your restriction;
## re-run this script to re-apply the restriction rule, or wait for the next activation/deactivation hour.
## * To apply changes to this script (i.e. new client addresses, or changes to the time of day),
## re-run this script manually to apply the updates, or wait for the next activation/deactivation hour.
## * When this script activates or deactivates the blocking, it will log to /var/log/messages.
## * While the blocking is active, you'll see one "TIMERESTRICT BLOCK: " log message per hour
## in /var/log/messages if any blocked clients are attempting to use the internet.
##
## Caveats:
## * No support for wake_minute/sleep_minute - currently this only turns on/off at the top of an hour.
## * Assumption exists that sleep_hour is always greater-than wake_hour; i.e., you can't currently
## have a blocked time in the middle of the day.
## ----------------------------------------------------------------------
## List all client addresses you'd like to restrict. Separate multiple with spaces.
timerestricted_addresses='192.168.1.101 192.168.1.102'
## Hour of day to remove the restriction.
wake_hour=06
## Hour of day to activate the restriction.
sleep_hour=23
## ----------------------------------------------------------------------
## ----------------------------------------------------------------------
## ----------------------------------------------------------------------
myrule="FORWARD -i br0 -j TIMERESTRICT"
## report on blocks if rule exists
iptables -C $myrule 2>/dev/null && iptables -vL TIMERESTRICT | logger
echo "Setting up timerestrict firewall rules between $sleep_hour:00 and $wake_hour:00"
## initial setup
iptables -N TIMERESTRICT_LOGNDROP 2>/dev/null
iptables -F TIMERESTRICT_LOGNDROP 2>/dev/null
iptables -A TIMERESTRICT_LOGNDROP -m limit --limit 1/hour --limit-burst 1 -j LOG --log-prefix "TIMERESTRICT BLOCK: "
iptables -A TIMERESTRICT_LOGNDROP -j REJECT --reject-with icmp-net-prohibited
iptables -N TIMERESTRICT 2>/dev/null
iptables -F TIMERESTRICT 2>/dev/null
for ip in $timerestricted_addresses; do
iptables -A TIMERESTRICT -s $ip -j TIMERESTRICT_LOGNDROP
done
myrule="FORWARD -i br0 -j TIMERESTRICT"
## install or remove rule based on current time and whether the rule already exists
if [ $(date +%H) -ge $sleep_hour ]; then
logger "TIMERESTRICT: Activating sleep time"
iptables -C $myrule 2>/dev/null || iptables -I $myrule
elif [ $(date +%H) -ge $wake_hour ]; then
logger "TIMERESTRICT: Activating awake time"
iptables -C $myrule 2>/dev/null && iptables -D $myrule
fi
## setup cron job to activate/deactivate on time of day
echo "00 $sleep_hour * * * $(readlink -f $0)" >/etc/cron.d/iptables_timerestrict
echo "00 $wake_hour * * * $(readlink -f $0)" >>/etc/cron.d/iptables_timerestrict
## Format: <minute> <hour> <day> <month> <dow> <tags and command>
/etc/init.d/crond restart
echo "Done with firewall rule setup:"
echo "-------------------------------------------------------------------"
iptables -vL FORWARD | egrep '(Chain|pkts|TIMERESTRICT)'
echo ...
iptables -vL TIMERESTRICT
iptables -vL TIMERESTRICT_LOGNDROP
echo

View File

@ -0,0 +1,8 @@
#!/bin/bash
## Create network bridge for CNI
ip link show cni0 > /dev/null 2>&1
if [ $? -ne 0 ]; then
ip link add cni0 type bridge
fi

Some files were not shown because too many files have changed in this diff Show More