Compare commits

...

82 commits

Author SHA1 Message Date
10f6aa8455
Release 1.1.9 Ammend
All checks were successful
Build and release binary file and packages / test (push) Successful in 21s
Run Tests on Code / run-tests (push) Successful in 23s
Build and release binary file and packages / build (push) Successful in 2m1s
Build and release binary file and packages / upload-generic-package (push) Successful in 1s
Build and release binary file and packages / upload-debian-package (push) Successful in 2s
Build and release binary file and packages / create-release (push) Successful in 9s
2024-09-30 11:41:20 +02:00
af6dcad5df
Release 1.1.9
All checks were successful
Run Tests on Code / run-tests (push) Successful in 23s
2024-09-30 11:40:07 +02:00
afb4dd8ff3
Include interface name when malformed IP is detected 2024-09-30 11:39:43 +02:00
3f41b8958e
Update Release Debian Ref Collecting
All checks were successful
Run Tests on Code / run-tests (push) Successful in 13s
2024-08-07 20:50:25 +02:00
7e7646a4eb Merge pull request 'Bump forgejo-release to v2' (#36) from actions-update into main
All checks were successful
Run Tests on Code / run-tests (push) Successful in 42s
Reviewed-on: https://forgejo.neshweb.net///Neshura/cloudflare-dns-updater/pulls/36
2024-08-06 12:23:21 +00:00
40f617a2d6 Bump forgejo-release to v2
All checks were successful
Build binary file and bundle packages / test (pull_request) Successful in 35s
Run Tests on Code / run-tests (push) Successful in 37s
Build binary file and bundle packages / build (pull_request) Successful in 49s
2024-08-06 12:20:15 +00:00
65519933be
Release 1.1.8
All checks were successful
Run Tests on Code / run-tests (push) Successful in 24s
Build and release binary file and packages / test (push) Successful in 7s
Build and release binary file and packages / build (push) Successful in 23s
Build and release binary file and packages / upload-generic-package (push) Successful in 1s
Build and release binary file and packages / upload-debian-package (push) Successful in 1s
Build and release binary file and packages / create-release (push) Successful in 7s
2024-06-10 12:46:00 +02:00
2c83671c8e Migrate away from Mullvad API
All checks were successful
Run Tests on Code / run-tests (push) Successful in 20s
2024-06-10 11:51:27 +02:00
3626237d90
Release 1.1.7
All checks were successful
Run Tests on Code / run-tests (push) Successful in 20s
Build and release binary file and packages / test (push) Successful in 22s
Build and release binary file and packages / build (push) Successful in 28s
Build and release binary file and packages / upload-generic-package (push) Successful in 1s
Build and release binary file and packages / upload-debian-package (push) Successful in 1s
Build and release binary file and packages / create-release (push) Successful in 7s
2024-03-04 16:44:11 +01:00
6a31ae0f9a
Elevated Mullvad Error Returns to Error Level from Warning
All checks were successful
Run Tests on Code / run-tests (push) Successful in 10s
2024-03-04 16:43:56 +01:00
04a1be9bcb
Improved Error Message Syntax 2024-03-04 16:43:06 +01:00
49b8d8cc05
Release 1.1.6
All checks were successful
Run Tests on Code / run-tests (push) Successful in 21s
Build and release binary file and packages / test (push) Successful in 20s
Build and release binary file and packages / build (push) Successful in 27s
Build and release binary file and packages / upload-generic-package (push) Successful in 1s
Build and release binary file and packages / upload-debian-package (push) Successful in 2s
Build and release binary file and packages / create-release (push) Successful in 7s
2024-03-04 16:35:06 +01:00
ffe1fbc7a4
DNS Update Log was logged with level 'WARN' instead of 'INFO'
All checks were successful
Run Tests on Code / run-tests (push) Successful in 10s
2024-03-04 16:34:40 +01:00
3c4e55d126
Release 1.1.5
All checks were successful
Run Tests on Code / run-tests (push) Successful in 27s
Build and release binary file and packages / test (push) Successful in 10s
Build and release binary file and packages / build (push) Successful in 27s
Build and release binary file and packages / upload-generic-package (push) Successful in 2s
Build and release binary file and packages / upload-debian-package (push) Successful in 1s
Build and release binary file and packages / create-release (push) Successful in 8s
2024-03-04 16:23:54 +01:00
8a1c52cd90
Bugfix: IP could be set to '::' or '0.0.0.0' 2024-03-04 16:23:54 +01:00
7b6bdc37c7 Correct zone.d naming in README to zones.d
All checks were successful
Run Tests on Code / run-tests (push) Successful in 27s
2024-01-19 08:55:50 +00:00
bff7057c45
Release 1.1.4
All checks were successful
Build and release binary file and packages / build (push) Successful in 28s
Build and release binary file and packages / upload-generic-package (push) Successful in 1s
Build and release binary file and packages / upload-debian-package (push) Successful in 1s
Run Tests on Code / run-tests (push) Successful in 22s
Build and release binary file and packages / test (push) Successful in 21s
Build and release binary file and packages / create-release (push) Successful in 7s
2024-01-08 09:47:31 +01:00
9dfd21ce8d Merge pull request 'Closes #34' (#35) from systemd-fix into main
All checks were successful
Run Tests on Code / run-tests (push) Successful in 8s
Reviewed-on: #35
2024-01-08 08:46:26 +00:00
dec6834920 Remove User Service file from cargo deb config
All checks were successful
Run Tests on Code / run-tests (push) Successful in 9s
Build binary file and bundle packages / test (pull_request) Successful in 8s
Build binary file and bundle packages / build (pull_request) Successful in 28s
2024-01-08 08:43:43 +00:00
9d5c3fcc23 Remove deprecated scripts for User Service File
All checks were successful
Run Tests on Code / run-tests (push) Successful in 9s
2024-01-08 08:43:14 +00:00
bbee00c9f9 Remove deprecated scripts for User Service File
Some checks failed
Run Tests on Code / run-tests (push) Has been cancelled
2024-01-08 08:43:08 +00:00
46bf5dc50d Remove deprecated scripts for User Service File
Some checks failed
Run Tests on Code / run-tests (push) Has been cancelled
2024-01-08 08:43:04 +00:00
ba34228cbd Remove User Service File
All checks were successful
Run Tests on Code / run-tests (push) Successful in 8s
2024-01-08 08:42:44 +00:00
74cb65a658 Add User Variable to Service File
All checks were successful
Run Tests on Code / run-tests (push) Successful in 21s
2024-01-08 08:42:17 +00:00
973741f7bb
Release 1.1.3
All checks were successful
Run Tests on Code / run-tests (push) Successful in 26s
Build and release binary file and packages / test (push) Successful in 23s
Build and release binary file and packages / build (push) Successful in 28s
Build and release binary file and packages / upload-generic-package (push) Successful in 2s
Build and release binary file and packages / upload-debian-package (push) Successful in 2s
Build and release binary file and packages / create-release (push) Successful in 9s
2023-12-29 14:28:22 +01:00
1e578d1a6b
Filter out build.env file for releases
All checks were successful
Run Tests on Code / run-tests (push) Successful in 15s
2023-12-29 14:28:04 +01:00
fda3c6bab6
Fix package name in generic package registry 2023-12-29 14:27:52 +01:00
7b7b55de0d
Split upload phase
All checks were successful
Run Tests on Code / run-tests (push) Successful in 9s
2023-12-29 03:43:59 +01:00
561bcbba26
1.1.2
All checks were successful
Run Tests on Code / run-tests (push) Successful in 13s
Build and release binary file and packages / test (push) Successful in 16s
Build and release binary file and packages / build (push) Successful in 24s
Build and release binary file and packages / upload-release (push) Successful in 9s
2023-12-29 03:38:55 +01:00
6d0c792f52
rc.3 v2
Some checks failed
Run Tests on Code / run-tests (push) Successful in 10s
Build and release binary file and packages / test (push) Successful in 10s
Build and release binary file and packages / build (push) Successful in 34s
Build and release binary file and packages / upload-release (push) Failing after 8s
2023-12-29 03:38:20 +01:00
3da5ac2a0c
Add missing () to tag rc check
All checks were successful
Run Tests on Code / run-tests (push) Successful in 12s
2023-12-29 03:37:26 +01:00
89192016fd
Release 1.1.2
All checks were successful
Run Tests on Code / run-tests (push) Successful in 25s
Build and release binary file and packages / test (push) Successful in 24s
Build and release binary file and packages / build (push) Successful in 26s
Build and release binary file and packages / upload-release (push) Successful in 10s
2023-12-29 03:36:07 +01:00
6a4a2b6445
Release Candidate 1.1.2-rc.3
All checks were successful
Run Tests on Code / run-tests (push) Successful in 24s
Build and release binary file and packages / test (push) Successful in 22s
Build and release binary file and packages / build (push) Successful in 30s
Build and release binary file and packages / upload-release (push) Successful in 23s
2023-12-29 03:35:37 +01:00
bccfc3d1f1
Always upload to staging, only upload to main on non-rc tags
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
2023-12-29 03:35:18 +01:00
b6aade0ad3
Release Candidate 1.1.2-rc.2
All checks were successful
Run Tests on Code / run-tests (push) Successful in 12s
Build and release binary file and packages / test (push) Successful in 13s
Build and release binary file and packages / build (push) Successful in 26s
Build and release binary file and packages / upload-release (push) Successful in 10s
2023-12-29 03:31:17 +01:00
83a0b37c4e
Inline debian component switch instead of using if 2023-12-29 03:31:03 +01:00
61e45713e3
Fix Actions
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
Build and release binary file and packages / test (push) Successful in 10s
Build and release binary file and packages / build (push) Successful in 25s
Build and release binary file and packages / upload-release (push) Successful in 10s
2023-12-29 03:26:50 +01:00
9ccd290ebc
Release Candidate 1.1.2-rc.1
Some checks failed
Run Tests on Code / run-tests (push) Successful in 11s
Build and release binary file and packages / upload-release (push) Blocked by required conditions
Build and release binary file and packages / test (push) Successful in 11s
Build and release binary file and packages / build (push) Has been cancelled
2023-12-29 03:19:37 +01:00
0c8414f0d0
Fix workflow if
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
2023-12-29 03:18:40 +01:00
50c9677b82
Revert env changes
All checks were successful
Run Tests on Code / run-tests (push) Successful in 12s
Build and release binary file and packages / test (push) Successful in 10s
Build and release binary file and packages / build (push) Successful in 26s
Build and release binary file and packages / upload-release (push) Successful in 10s
2023-12-29 03:14:53 +01:00
f8f6737ae6
Add whitespace
Some checks failed
Run Tests on Code / run-tests (push) Successful in 11s
Build and release binary file and packages / test (push) Successful in 11s
Build and release binary file and packages / build (push) Failing after 24s
Build and release binary file and packages / upload-release (push) Has been skipped
2023-12-29 02:54:33 +01:00
9b47a6dbac
More syntax fix
All checks were successful
Run Tests on Code / run-tests (push) Successful in 12s
2023-12-29 02:54:02 +01:00
cbab7703ef
Syntax fix
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
2023-12-29 02:52:44 +01:00
7b6cc44e17
Release Candidate 1.1.2-rc.2
All checks were successful
Run Tests on Code / run-tests (push) Successful in 19s
2023-12-29 02:50:19 +01:00
30cf1afba8
Switch variable referencing style + change if condition check
All checks were successful
Run Tests on Code / run-tests (push) Successful in 13s
2023-12-29 02:49:38 +01:00
c62dd2ff39
Fix pre-release check
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
Build and release binary file and packages / test (push) Successful in 10s
Build and release binary file and packages / build (push) Successful in 27s
Build and release binary file and packages / upload-release (push) Successful in 12s
2023-12-29 02:36:29 +01:00
86dcdea7c6
Release Candidate 1.1.1-rc.1
All checks were successful
Run Tests on Code / run-tests (push) Successful in 21s
Build and release binary file and packages / test (push) Successful in 9s
Build and release binary file and packages / build (push) Successful in 28s
Build and release binary file and packages / upload-release (push) Successful in 10s
2023-12-29 02:31:01 +01:00
d28bbd45d7
Add staging debian component for pre-releases
All checks were successful
Run Tests on Code / run-tests (push) Successful in 13s
2023-12-29 02:30:30 +01:00
3fc17bcd4a
Specify config directory in Readme
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
2023-12-29 02:21:12 +01:00
3dec954747
Update README
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
2023-12-29 02:19:31 +01:00
45a7ab58d7
Add manual depends to cargo deb config. Should be complete
All checks were successful
Run Tests on Code / run-tests (push) Successful in 12s
2023-12-29 02:16:53 +01:00
ceddb5454d
Release 1.1.1
All checks were successful
Build and release binary file and packages / test (push) Successful in 23s
Run Tests on Code / run-tests (push) Successful in 27s
Build and release binary file and packages / build (push) Successful in 25s
Build and release binary file and packages / upload-release (push) Successful in 10s
2023-12-29 02:08:57 +01:00
812f93d2be Merge pull request 'Add Debian packaging to the App' (#32) from debian into main
All checks were successful
Run Tests on Code / run-tests (push) Successful in 10s
Reviewed-on: #32
2023-12-29 01:08:29 +00:00
b9419a5446
Different install target for user systemd service unit
All checks were successful
Run Tests on Code / run-tests (push) Successful in 13s
2023-12-29 02:08:07 +01:00
ffcaeb9d4b
Release Candidate 1.1.1-rc.7
All checks were successful
Run Tests on Code / run-tests (push) Successful in 24s
Build and Release Binary File / test (push) Successful in 23s
Build and Release Binary File / build (push) Successful in 26s
Build and Release Binary File / upload-release (push) Successful in 12s
2023-12-29 02:02:02 +01:00
6ec4b1b48c
Add binary to debian package. It went missing after adding the user systemd unit
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
2023-12-29 02:01:36 +01:00
a1092be60c
Release Candidate 1.1.1-rc.6
All checks were successful
Run Tests on Code / run-tests (push) Successful in 22s
Build and Release Binary File / test (push) Successful in 25s
Build and Release Binary File / build (push) Successful in 27s
Build and Release Binary File / upload-release (push) Successful in 14s
2023-12-29 01:57:45 +01:00
2412ad1666
Dependecy Version bump
All checks were successful
Run Tests on Code / run-tests (push) Successful in 19s
2023-12-29 01:57:10 +01:00
3657754fd7
Update .gitignore 2023-12-29 01:56:57 +01:00
0a9eba9732
Potential Bugfix whereby the code threw an otherwise unexplained error 2023-12-29 01:56:48 +01:00
6588bf20a5
Release Candidate 1.1.1-rc.5
All checks were successful
Run Tests on Code / run-tests (push) Successful in 25s
Build and Release Binary File / test (push) Successful in 27s
Build and Release Binary File / build (push) Successful in 31s
Build and Release Binary File / upload-release (push) Successful in 14s
2023-12-29 01:43:06 +01:00
00ea82e12c
Add systemd user unit
All checks were successful
Run Tests on Code / run-tests (push) Successful in 13s
2023-12-29 01:41:41 +01:00
6936fa87d4 Merge pull request 'Run check on pull-requests' (#33) from pull_request_checking into main
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
Reviewed-on: #33
2023-12-29 00:27:45 +00:00
b727a3714e
Fix cargo deb missing #DEBHELPER# variable
All checks were successful
Run Tests on Code / run-tests (push) Successful in 11s
Build and Release Binary File / test (push) Successful in 12s
Build and Release Binary File / build (push) Successful in 26s
Build and Release Binary File / upload-release (push) Successful in 11s
2023-12-29 01:26:09 +01:00
db0df8f0f0
Remove Version checking from test step
Some checks failed
Run Tests on Code / run-tests (push) Successful in 11s
Build binary file and bundle packages / test (pull_request) Successful in 11s
Build binary file and bundle packages / build (pull_request) Failing after 28s
2023-12-29 01:20:32 +01:00
7738c8b366
Release Candidate 1.1.1-rc.4
Some checks failed
Run Tests on Code / run-tests (push) Successful in 25s
Build and Release Binary File / test (push) Successful in 23s
Build and Release Binary File / build (push) Failing after 27s
Build and Release Binary File / upload-release (push) Has been skipped
2023-12-29 01:18:59 +01:00
6b847ba34e
Convert systemd unit to user script via custom install scripts
All checks were successful
Run Tests on Code / run-tests (push) Successful in 14s
2023-12-29 01:18:36 +01:00
95268b5020
Run check on pull-requests
Some checks failed
Run Tests on Code / run-tests (push) Successful in 13s
Build binary file and bundle packages / test (pull_request) Failing after 13s
Build binary file and bundle packages / build (pull_request) Has been skipped
2023-12-29 01:13:19 +01:00
e1dd7c0046
Release Candidate 1.1.1-rc.3
All checks were successful
Run Tests on Code / run-tests (push) Successful in 12s
Build and Release Binary File / test (push) Successful in 12s
Build and Release Binary File / build (push) Successful in 27s
Build and Release Binary File / upload-release (push) Successful in 9s
2023-12-29 00:55:39 +01:00
dba934ab41
Move systemd unit to correct directory 2023-12-29 00:55:21 +01:00
03453a3327
Fix cargo deb config
All checks were successful
Run Tests on Code / run-tests (push) Successful in 10s
Build and Release Binary File / test (push) Successful in 15s
Build and Release Binary File / build (push) Successful in 28s
Build and Release Binary File / upload-release (push) Successful in 11s
2023-12-29 00:46:51 +01:00
f74a37ac24
Release Candidate 1.1.1-rc.2
Some checks failed
Run Tests on Code / run-tests (push) Successful in 10s
Build and Release Binary File / test (push) Successful in 12s
Build and Release Binary File / build (push) Failing after 26s
Build and Release Binary File / upload-release (push) Has been skipped
2023-12-29 00:44:14 +01:00
c7a4e68e8f
Fix debian revision extraction 2023-12-29 00:43:59 +01:00
62945286fd
Remove no longer needed dependency install for cargo deb 2023-12-29 00:43:04 +01:00
6e385d7f87
Release Candidate 1.1.1-rc.3
Some checks failed
Run Tests on Code / run-tests (push) Successful in 21s
Build and Release Binary File / test (push) Successful in 12s
Build and Release Binary File / build (push) Failing after 32s
Build and Release Binary File / upload-release (push) Has been skipped
2023-12-29 00:39:26 +01:00
5aa2f62c66
Add systemd unit to debian package
All checks were successful
Run Tests on Code / run-tests (push) Successful in 21s
2023-12-29 00:38:52 +01:00
ee2b492851
Updated Readme 2023-12-29 00:38:27 +01:00
1c0bb64572
Remove outdated .json files 2023-12-29 00:36:12 +01:00
f78f735b2c
Move .env configuration to config.toml 2023-12-29 00:36:01 +01:00
4ba04706b5
Release Candidate 1.1.1-rc.2
Some checks failed
Run Tests on Code / run-tests (push) Successful in 13s
Build and Release Binary File / test (push) Successful in 12s
Build and Release Binary File / upload-release (push) Has been skipped
Build and Release Binary File / build (push) Failing after 27s
2023-12-29 00:04:36 +01:00
9e3415f890
Swap out hardcoded revision for Cargo.toml variable
All checks were successful
Run Tests on Code / run-tests (push) Successful in 12s
2023-12-29 00:04:01 +01:00
846e07b56c
Remove cargo-deb dependency due to inclusion in docker image 2023-12-28 23:48:39 +01:00
12 changed files with 348 additions and 254 deletions

View file

@ -1,4 +1,4 @@
name: 'Build and Release Binary File' name: 'Build and release binary file and packages'
author: 'Neshura' author: 'Neshura'
on: on:
@ -51,13 +51,6 @@ jobs:
- -
name: Checking Out Repository Code name: Checking Out Repository Code
uses: https://code.forgejo.org/actions/checkout@v3 uses: https://code.forgejo.org/actions/checkout@v3
-
name: Installing cargo-deb dependencies
run: apt install -y liblzma-dev
-
name: Installing cargo-deb
run: |
cargo install cargo-deb
- -
name: Prepare build environment name: Prepare build environment
run: mkdir dist run: mkdir dist
@ -70,8 +63,11 @@ jobs:
name: Bundle .deb package name: Bundle .deb package
run: | run: |
cargo deb cargo deb
DEBIAN_REF=$(echo ${{ github.ref_name }} | tr - \~) DEBIAN_REF=$(cat Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " " | tr - \~)
mv target/debian/${{ github.event.repository.name }}_$DEBIAN_REF-1_amd64.deb dist/${{ github.event.repository.name }}_$DEBIAN_REF-1_amd64.deb echo "DEBIAN_REF=$DEBIAN_REF" >> dist/build.env
DEBIAN_REV=-$(cat Cargo.toml | grep -E "(^|\|)revision =" | cut -f2- -d= | tr -d \" | tr -d " ")
echo "DEBIAN_REV=$DEBIAN_REV" >> dist/build.env
mv target/debian/${{ github.event.repository.name }}_"$DEBIAN_REF""$DEBIAN_REV"_amd64.deb dist/${{ github.event.repository.name }}_"$DEBIAN_REF""$DEBIAN_REV"_amd64.deb
- -
name: Uploading Build Artifact name: Uploading Build Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@ -80,7 +76,7 @@ jobs:
path: dist path: dist
if-no-files-found: error if-no-files-found: error
upload-release: upload-generic-package:
needs: build needs: build
if: success() if: success()
runs-on: docker runs-on: docker
@ -93,23 +89,55 @@ jobs:
run: | run: |
echo 'curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \ echo 'curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
--upload-file release_blobs/${{ github.event.repository.name }}-linux-amd64 \ --upload-file release_blobs/${{ github.event.repository.name }}-linux-amd64 \
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{ github.ref_name }}/chellaris-rust-api-linux-amd64' https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{ github.ref_name }}/${{ github.event.repository.name }}-linux-amd64'
curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \ curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
--upload-file release_blobs/${{ github.event.repository.name }}-linux-amd64 \ --upload-file release_blobs/${{ github.event.repository.name }}-linux-amd64 \
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{ github.ref_name }}/chellaris-rust-api-linux-amd64 https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{ github.ref_name }}/${{ github.event.repository.name }}-linux-amd64
upload-debian-package:
needs: build
if: success()
runs-on: docker
steps:
- -
name: Upload Debian Package name: Downloading All Build Artifacts
uses: actions/download-artifact@v3
-
name: Upload Debian Package to staging
run: | run: |
DEBIAN_REF=$(echo ${{ github.ref_name }} | tr - \~) source release_blobs/build.env
echo 'curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \ echo 'curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
--upload-file release_blobs/${{ github.event.repository.name }}_$DEBIAN_REF-1_amd64.deb \ --upload-file release_blobs/${{ github.event.repository.name }}_'"$DEBIAN_REF""$DEBIAN_REV"'_amd64.deb \
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/debian/pool/bookworm/staging/upload'
curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
--upload-file release_blobs/${{ github.event.repository.name }}_"$DEBIAN_REF""$DEBIAN_REV"_amd64.deb \
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/debian/pool/bookworm/staging/upload
-
name: Upload Debian Package to main
if: (! contains(github.ref_name, '-rc'))
run: |
source release_blobs/build.env
echo 'curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
--upload-file release_blobs/${{ github.event.repository.name }}_'"$DEBIAN_REF""$DEBIAN_REV"'_amd64.deb \
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/debian/pool/bookworm/main/upload' https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/debian/pool/bookworm/main/upload'
curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \ curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
--upload-file release_blobs/${{ github.event.repository.name }}_$DEBIAN_REF-1_amd64.deb \ --upload-file release_blobs/${{ github.event.repository.name }}_"$DEBIAN_REF""$DEBIAN_REV"_amd64.deb \
https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/debian/pool/bookworm/main/upload https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/debian/pool/bookworm/main/upload
create-release:
needs: build
if: success()
runs-on: docker
steps:
-
name: Downloading All Build Artifacts
uses: actions/download-artifact@v3
-
name: Filter out env files
run: rm release_blobs/build.env
- -
name: Release New Version name: Release New Version
uses: actions/forgejo-release@v1 uses: actions/forgejo-release@v2
with: with:
direction: upload direction: upload
url: https://forgejo.neshweb.net url: https://forgejo.neshweb.net

View file

@ -0,0 +1,67 @@
name: 'Build binary file and bundle packages'
author: 'Neshura'
on:
pull_request:
branches:
- main
jobs:
test:
runs-on: docker
container: forgejo.neshweb.net/ci-docker-images/rust-node:latest
steps:
-
name: Add Clippy
run: rustup component add clippy
-
name: Checking Out Repository Code
uses: https://code.forgejo.org/actions/checkout@v3
-
name: Set Up Cargo Cache
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-
name: Run Clippy
run: cargo clippy
build:
needs: test
if: success()
runs-on: docker
container: forgejo.neshweb.net/ci-docker-images/rust-node:latest
steps:
-
name: Checking Out Repository Code
uses: https://code.forgejo.org/actions/checkout@v3
-
name: Prepare build environment
run: mkdir dist
-
name: Compiling To Linux Target
run: |
cargo build -r
mv target/release/${{ github.event.repository.name }} dist/${{ github.event.repository.name }}-linux-amd64
-
name: Bundle .deb package
run: |
cargo deb
DEBIAN_REF=$(cat Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " " | tr - \~)
echo "DEBIAN_REF=$DEBIAN_REF" >> dist/build.env
DEBIAN_REV=-$(cat Cargo.toml | grep -E "(^|\|)revision =" | cut -f2- -d= | tr -d \" | tr -d " ")
echo "DEBIAN_REV=$DEBIAN_REV" >> dist/build.env
mv target/debian/${{ github.event.repository.name }}_"$DEBIAN_REF""$DEBIAN_REV"_amd64.deb dist/${{ github.event.repository.name }}_"$DEBIAN_REF""$DEBIAN_REV"_amd64.deb
-
name: Uploading Build Artifact
uses: actions/upload-artifact@v3
with:
name: release_blobs
path: dist
if-no-files-found: error

1
.gitignore vendored
View file

@ -4,6 +4,5 @@ venv/
.idea/ .idea/
.vscode/ .vscode/
/.env
/interfaces.toml /interfaces.toml
/zones.d /zones.d

36
Cargo.lock generated
View file

@ -114,11 +114,10 @@ dependencies = [
[[package]] [[package]]
name = "cloudflare-dns-updater" name = "cloudflare-dns-updater"
version = "1.1.1-rc.1" version = "1.1.9"
dependencies = [ dependencies = [
"chrono", "chrono",
"confy", "confy",
"dotenv",
"ipnet", "ipnet",
"log", "log",
"reqwest", "reqwest",
@ -178,12 +177,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.33" version = "0.8.33"
@ -627,7 +620,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.43", "syn",
] ]
[[package]] [[package]]
@ -828,7 +821,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.43", "syn",
] ]
[[package]] [[package]]
@ -875,26 +868,15 @@ dependencies = [
[[package]] [[package]]
name = "strum_macros" name = "strum_macros"
version = "0.24.3" version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
"syn 1.0.109", "syn",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
] ]
[[package]] [[package]]
@ -969,7 +951,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.43", "syn",
] ]
[[package]] [[package]]
@ -1147,7 +1129,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.43", "syn",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -1181,7 +1163,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.43", "syn",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]

View file

@ -1,11 +1,25 @@
[package] [package]
authors = ["Neshura"] authors = ["Neshura"]
name = "cloudflare-dns-updater" name = "cloudflare-dns-updater"
version = "1.1.1-rc.1" version = "1.1.9"
edition = "2021" edition = "2021"
description = "Application for automatically updating Cloudflare DNS records" description = "Application for automatically updating Cloudflare DNS records"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
[package.metadata.deb]
extended-description = "Application for automatically updating Cloudflare DNS records"
maintainer-scripts = "debian/"
revision = "1"
depends = ["libc6", "libssl3", "systemd"]
assets = [
[
"target/release/cloudflare-dns-updater",
"/usr/local/bin/cloudflare-dns-updater",
"755",
]
]
systemd-units = { enable = false }
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
@ -14,10 +28,9 @@ reqwest = { version = "^0.11.14", features = ["blocking", "json"] }
serde = "^1.0.152" serde = "^1.0.152"
serde_derive = "^1.0.152" serde_derive = "^1.0.152"
serde_json = "^1.0.93" serde_json = "^1.0.93"
strum_macros = "^0.24.3" strum_macros = "^0.25.3"
log = "^0.4.20" log = "^0.4.20"
systemd-journal-logger = "^2.1.1" systemd-journal-logger = "^2.1.1"
confy = "^0.5.1" confy = "^0.5.1"
dotenv = "^0.15.0"
ipnet = "^2.9.0" ipnet = "^2.9.0"
url = "2.5.0" url = "2.5.0"

View file

@ -7,23 +7,18 @@
The application necessarily requires a valid Cloudflare API Token. The application necessarily requires a valid Cloudflare API Token.
Further the application must be located in the same network as the configured zones. Further the application must be located in the same network as the configured zones.
| Environment Variable | Required | Usage | The actual configuration happens in three or more files located in `~/.config/cloudflare-dns-updater/`:
|:--------------------:|:--------:|:----------------------------------:| `config.toml` contains general configuration parameters for the application
| CF_API_TOKEN | x | Cloudflare API Token |
| STATUS_POST_URL | | Post Endpoint for a Uptime Monitor |
*Note: Variables can be stored in a .env file*
The actual configuration happens in two or more files:
`interfaces.toml` contains all IPv6 interfaces available/used by the zone config files. `interfaces.toml` contains all IPv6 interfaces available/used by the zone config files.
`.toml` files in `zone.d` contain settings for individual zones. `.toml` files in `zones.d` contain settings for individual zones.
Example: Example:
*.env* *config.toml*
```text ```toml
CF_API_TOKEN=0123456789abcdef0123456789abcdef01234 cf_api_token = "0123456789abcdef0123456789abcdef01234" # Cloudflare API Token
CHECK_INTERVAL_SECONDS=30 // Defaults to 60 if missing check_interval_seconds = 30 # Defaults to 60 if missing
UPTIME_URL=https://example.org/uptime/id12 // Entirely optional uptime_url = "https://example.org/uptime/id12" # Post Endpoint for a Uptime Monitor
``` ```
*interfaces.toml* *interfaces.toml*
@ -34,7 +29,7 @@ host_address = "::edcb:a098:7654:3210"
example-interface = "::0123:4567:890a:bcde" # static part of the IP, the rest will be dynamically generated using the host example-interface = "::0123:4567:890a:bcde" # static part of the IP, the rest will be dynamically generated using the host
``` ```
*zone.d/example.org.toml* *zones.d/example.org.toml*
```toml ```toml
email = "owner@example.org" # Email of User owning the Zone email = "owner@example.org" # Email of User owning the Zone
zone = "example.org" # Zone Name zone = "example.org" # Zone Name
@ -47,4 +42,10 @@ interface = "example-interface" # Only required on type values 6 and 10
``` ```
## Debian Repository ## Debian Repository
TODO!
Currently supported:
- Debian 12 'Bookworm'
Includes systemd system and user unit files
For more details see [the package registry](https://forgejo.neshweb.net/Neshura/-/packages/debian/cloudflare-dns-updater)

View file

@ -1,74 +0,0 @@
{
"AAAA": [
"books",
"calibre",
"docs.gitlab",
"element",
"files",
"gitlab",
"*.gitpages",
"gitpages",
"hentai",
"ipv6",
"jellyfin",
"komga",
"manga",
"mastodon",
"matrix",
"minecraft",
"monitoring",
"mstreaming",
"music",
"navidrome",
"neshura-server.net",
"nextcloud",
"nginx",
"picard",
"porn",
"portainer",
"readyornot",
"registry.gitlab",
"temp1",
"temp2",
"tube",
"video",
"www",
"zomboid"
],
"A": [
"books",
"calibre",
"docs.gitlab",
"element",
"files",
"gitlab",
"*.gitpages",
"gitpages",
"hentai",
"ipv4",
"jellyfin",
"komga",
"manga",
"mastodon",
"matrix",
"minecraft",
"monitoring",
"mstreaming",
"music",
"navidrome",
"neshura-server.net",
"nextcloud",
"nginx",
"picard",
"porn",
"portainer",
"readyornot",
"registry.gitlab",
"temp1",
"temp2",
"tube",
"video",
"www",
"zomboid"
]
}

View file

@ -1,38 +0,0 @@
{
"ipv6_interface": ":da5e:d3ff:feeb:4346",
"zones": [
{
"email": "neshura@proton.me",
"name": "neshura.net",
"id": "0183f167a051f1e432c0d931478638b5",
"dns_entries": [
{
"name": "*.neshura.net",
"type4": false,
"type6": true,
"interface": ":da5e:d3ff:feeb:4346"
},
{
"name": "neshura.net",
"type4": false,
"type6": true,
"interface": ":da5e:d3ff:feeb:4346"
}
]
},
{
"email": "neshura@proton.me",
"name": "neshura-server.net",
"id": "146d4cd6a1777376b423aaedc6824818",
"dns_entries": [
]
},
{
"email": "neshura@proton.me",
"name": "neshweb.net",
"id": "75b0d52229357478b734ae0f6d075c15",
"dns_entries": [
]
}
]
}

14
debian/cloudflare-dns-updater@.service vendored Normal file
View file

@ -0,0 +1,14 @@
[Unit]
Description="Application for automatically updating Cloudflare DNS records"
After=syslog.target
After=network-online.target
[Service]
Type=simple
User=%i
ExecStart=/usr/local/bin/cloudflare-dns-updater
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

View file

@ -1,6 +1,4 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::env;
use std::env::VarError;
use std::error::Error; use std::error::Error;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use log::{error, warn}; use log::{error, warn};
@ -11,7 +9,7 @@ use serde_derive::{Deserialize, Serialize};
use strum_macros::{Display, IntoStaticStr}; use strum_macros::{Display, IntoStaticStr};
use systemd_journal_logger::connected_to_journal; use systemd_journal_logger::connected_to_journal;
use url::ParseError; use url::ParseError;
use crate::config::{ZoneConfig, ZoneEntry}; use crate::config::{AppConfig, ZoneConfig, ZoneEntry};
const API_BASE: &str = "https://api.cloudflare.com/client/v4"; const API_BASE: &str = "https://api.cloudflare.com/client/v4";
@ -34,14 +32,14 @@ pub(crate) struct CloudflareZone {
} }
impl CloudflareZone { impl CloudflareZone {
pub(crate) fn new(zone: &ZoneConfig) -> Result<Self, VarError> { pub(crate) fn new(zone: &ZoneConfig, config: &AppConfig) -> Self {
let key = env::var("CF_API_TOKEN")?; let key = config.cloudflare_api_token.clone();
Ok(Self { Self {
name: zone.name.clone(), name: zone.name.clone(),
email: zone.email.clone(), email: zone.email.clone(),
key, key,
id: zone.id.clone(), id: zone.id.clone(),
}) }
} }
fn generate_auth_headers(&self) -> HeaderMap { fn generate_auth_headers(&self) -> HeaderMap {
@ -66,7 +64,7 @@ impl CloudflareZone {
let entries = match response.json::<CloudflareApiResults>() { let entries = match response.json::<CloudflareApiResults>() {
Ok(data) => data, Ok(data) => data,
Err(e) => { Err(e) => {
let err_msg = format!("Unable to parse API response. Error: {e}"); let err_msg = format!("Unable to parse API response: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -77,7 +75,7 @@ impl CloudflareZone {
Ok(entries.result) Ok(entries.result)
} else { } else {
let err_msg = format!("Unable to fetch Cloudflare Zone Entries for {}. Error: {}",self.name ,response.status()); let err_msg = format!("Unable to fetch Cloudflare Zone Entries for {}: {}",self.name ,response.status());
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -86,7 +84,7 @@ impl CloudflareZone {
} }
} }
Err(e) => { Err(e) => {
let err_msg = format!("Unable to access Cloudflare API. Error: {e}"); let err_msg = format!("Unable to access Cloudflare API: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -109,7 +107,7 @@ impl CloudflareZone {
self.validate_response(response) self.validate_response(response)
}, },
Err(e) => { Err(e) => {
let err_msg = format!("Unable to access Cloudflare API. Error: {e}"); let err_msg = format!("Unable to access Cloudflare API: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -135,7 +133,7 @@ impl CloudflareZone {
self.validate_response(response) self.validate_response(response)
}, },
Err(e) => { Err(e) => {
let err_msg = format!("Unable to access Cloudflare API. Error: {e}"); let err_msg = format!("Unable to access Cloudflare API: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -176,7 +174,7 @@ impl CloudflareZone {
self.validate_response(response) self.validate_response(response)
}, },
Err(e) => { Err(e) => {
let err_msg = format!("Unable to access Cloudflare API. Error: {e}"); let err_msg = format!("Unable to access Cloudflare API: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -202,7 +200,7 @@ impl CloudflareZone {
self.validate_response(response) self.validate_response(response)
}, },
Err(e) => { Err(e) => {
let err_msg = format!("Unable to access Cloudflare API. Error: {e}"); let err_msg = format!("Unable to access Cloudflare API: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -272,7 +270,7 @@ impl CloudflareZone {
match Url::parse(input) { match Url::parse(input) {
Ok(url) => Ok(url), Ok(url) => Ok(url),
Err(e) => { Err(e) => {
let err_msg = format!("Unable to parse URL. Error: {}", e); let err_msg = format!("Unable to parse URL: {}", e);
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -295,7 +293,7 @@ impl CloudflareZone {
let data = match response.json::<CloudflareApiResult>() { let data = match response.json::<CloudflareApiResult>() {
Ok(data) => data, Ok(data) => data,
Err(e) => { Err(e) => {
let err_msg = format!("Unable to parse API response. Error: {e}"); let err_msg = format!("Unable to parse API response: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -307,7 +305,7 @@ impl CloudflareZone {
match data.success { match data.success {
true => Ok(()), true => Ok(()),
false => { false => {
let err_msg = format!("Unexpected error while updating DNS record. Info: {:?}", data); let err_msg = format!("Unexpected error while updating DNS record: {:?}", data);
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -316,7 +314,7 @@ impl CloudflareZone {
} }
} }
} else { } else {
let err_msg = format!("Unable to post/put Cloudflare DNS entry. Error: {}", response.status()); let err_msg = format!("Unable to post/put Cloudflare DNS entry: {}", response.status());
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),

View file

@ -37,7 +37,7 @@ impl InterfaceConfig {
let interface_address = match self.interfaces.get(interface_name) { let interface_address = match self.interfaces.get(interface_name) {
Some(address) => *address, Some(address) => *address,
None => { None => {
let err_msg = "Malformed IP in interfaces.toml"; let err_msg = format!("Malformed or missing IP in interfaces.toml for interface {}", interface_name);
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -140,3 +140,46 @@ impl Default for ZoneConfig {
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub(crate) struct AppConfig {
pub(crate) cloudflare_api_token: String,
pub(crate) check_interval_seconds: Option<u16>,
pub(crate) uptime_url: Option<String>,
}
impl AppConfig {
pub(crate) fn load() -> Result<Self, Box<dyn Error>> {
let cfg: Self = match confy::load(env!("CARGO_PKG_NAME"),"config") {
Ok(data) => data,
Err(e) => {
match connected_to_journal() {
true => error!("[ERROR] {e}"),
false => eprintln!("[ERROR] {e}")
}
return Err(Box::new(e));
}
};
if cfg.cloudflare_api_token.is_empty() {
let err_msg = "Cloudflare api token not specified. The app cannot work without this";
match connected_to_journal() {
true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}")
}
panic!("{err_msg}");
}
Ok(cfg)
}
}
impl Default for AppConfig {
fn default() -> Self {
Self {
cloudflare_api_token: "".to_owned(),
check_interval_seconds: None,
uptime_url: None
}
}
}

View file

@ -1,16 +1,15 @@
/*use cloudflare_old::{Instance, CloudflareDnsType};*/ /*use cloudflare_old::{Instance, CloudflareDnsType};*/
use reqwest::blocking::get; use reqwest::blocking::get;
use std::{env, thread::{sleep}}; use std::{thread::{sleep}};
use std::error::Error; use std::error::Error;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr; use std::str::FromStr;
use chrono::{Utc, Duration}; use chrono::{Utc, Duration};
use dotenv::dotenv;
use log::{info, warn, error, LevelFilter}; use log::{info, warn, error, LevelFilter};
use reqwest::StatusCode; use reqwest::StatusCode;
use systemd_journal_logger::{connected_to_journal, JournalLog}; use systemd_journal_logger::{connected_to_journal, JournalLog};
use crate::cloudflare::{CloudflareZone, DnsRecordType}; use crate::cloudflare::{CloudflareZone, DnsRecordType};
use crate::config::{InterfaceConfig, ZoneConfig, ZoneEntry}; use crate::config::{AppConfig, InterfaceConfig, ZoneConfig, ZoneEntry};
mod config; mod config;
mod cloudflare; mod cloudflare;
@ -25,8 +24,8 @@ struct Addresses {
impl Addresses { impl Addresses {
fn new() -> Result<Self, Box<dyn Error>> { fn new() -> Result<Self, Box<dyn Error>> {
let mut ret = Self { let mut ret = Self {
ipv4_uri: "https://am.i.mullvad.net/ip".to_owned(), ipv4_uri: "http://ip4only.me/api/".to_owned(),
ipv6_uri: "https://ipv6.am.i.mullvad.net/ip".to_owned(), ipv6_uri: "http://ip6only.me/api/".to_owned(),
ipv4: Ipv4Addr::new(0, 0, 0, 0), ipv4: Ipv4Addr::new(0, 0, 0, 0),
ipv6: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0) ipv6: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)
}; };
@ -62,6 +61,14 @@ impl Addresses {
match self.get_v4() { match self.get_v4() {
Ok(ip) => { Ok(ip) => {
if ip != self.ipv4 { if ip != self.ipv4 {
if ip == Ipv4Addr::new(0,0,0,0) {
let warn_msg = "'0.0.0.0' detected as new IPv4, skipping changes".to_owned();
match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"),
false => println!("[WARN] {warn_msg}"),
}
}
else {
let info_msg = format!("IPv4 changed from '{}' to '{}'", self.ipv4, ip); let info_msg = format!("IPv4 changed from '{}' to '{}'", self.ipv4, ip);
match connected_to_journal() { match connected_to_journal() {
true => info!("[INFO] {info_msg}"), true => info!("[INFO] {info_msg}"),
@ -70,11 +77,12 @@ impl Addresses {
self.ipv4 = ip; self.ipv4 = ip;
} }
} }
}
Err(e) => { Err(e) => {
let warn_msg = format!("Unable to fetch IPv4 from '{}'. Error: {}", self.ipv4_uri, e); let error_msg = format!("Unable to fetch IPv4 from '{}': {}", self.ipv4_uri, e);
match connected_to_journal() { match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"), true => error!("[ERROR] {error_msg}"),
false => println!("[WARN] {warn_msg}"), false => eprintln!("[ERROR] {error_msg}"),
} }
} }
} }
@ -82,6 +90,14 @@ impl Addresses {
match self.get_v6() { match self.get_v6() {
Ok(ip) => { Ok(ip) => {
if ip != self.ipv6 { if ip != self.ipv6 {
if ip == Ipv6Addr::new(0,0,0,0,0,0,0,0) {
let warn_msg = "'::' detected as new IPv6, skipping changes".to_owned();
match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"),
false => println!("[WARN] {warn_msg}"),
}
}
else {
let info_msg = format!("IPv6 changed from '{}' to '{}'", self.ipv6, ip); let info_msg = format!("IPv6 changed from '{}' to '{}'", self.ipv6, ip);
match connected_to_journal() { match connected_to_journal() {
true => info!("[INFO] {info_msg}"), true => info!("[INFO] {info_msg}"),
@ -90,11 +106,12 @@ impl Addresses {
self.ipv6 = ip; self.ipv6 = ip;
} }
} }
}
Err(e) => { Err(e) => {
let warn_msg = format!("Unable to fetch IPv6 from '{}'. Error: {}", self.ipv6_uri, e); let error_msg = format!("Unable to fetch IPv6 from '{}': {}", self.ipv6_uri, e);
match connected_to_journal() { match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"), true => error!("[ERROR] {error_msg}"),
false => println!("[WARN] {warn_msg}"), false => eprintln!("[ERROR] {error_msg}"),
} }
} }
} }
@ -105,7 +122,7 @@ impl Addresses {
Ok(res) => { Ok(res) => {
match res.status() { match res.status() {
StatusCode::OK => { StatusCode::OK => {
let ip_string = res.text().expect("Returned data should always contain text").trim_end().to_owned(); let ip_string = res.text().expect("Returned data should always contain text").trim_end().split(',').collect::<Vec<&str>>()[1].to_owned();
Ok(Ipv4Addr::from_str(ip_string.as_str()).expect("Returned IP should always be parseable")) Ok(Ipv4Addr::from_str(ip_string.as_str()).expect("Returned IP should always be parseable"))
}, },
_ => { _ => {
@ -128,7 +145,7 @@ impl Addresses {
Ok(res) => { Ok(res) => {
match res.status() { match res.status() {
StatusCode::OK => { StatusCode::OK => {
let ip_string = res.text().expect("Returned data should always contain text").trim_end().to_owned(); let ip_string: String = res.text().expect("Returned data should always contain text").trim_end().split(',').collect::<Vec<&str>>()[1].to_owned();
Ok(Ipv6Addr::from_str(ip_string.as_str()).expect("Returned IP should always be parseable")) Ok(Ipv6Addr::from_str(ip_string.as_str()).expect("Returned IP should always be parseable"))
}, },
_ => { _ => {
@ -233,10 +250,10 @@ fn compare_zones(old_zone: &ZoneConfig, new_zone: &ZoneConfig) -> Vec<String> {
} }
fn main() { fn main() {
dotenv().ok();
JournalLog::new().expect("Systemd-Logger crate error").install().expect("Systemd-Logger crate error"); JournalLog::new().expect("Systemd-Logger crate error").install().expect("Systemd-Logger crate error");
log::set_max_level(LevelFilter::Info); log::set_max_level(LevelFilter::Info);
let mut config = AppConfig::load().unwrap();
let mut ifaces = InterfaceConfig::load().unwrap(); let mut ifaces = InterfaceConfig::load().unwrap();
let mut zone_cfgs = ZoneConfig::load().unwrap(); let mut zone_cfgs = ZoneConfig::load().unwrap();
@ -248,32 +265,22 @@ fn main() {
Err(e) => panic!("{}", e) Err(e) => panic!("{}", e)
}; };
let reload_interval = match env::var("CHECK_INTERVAL_SECONDS") { let reload_interval = config.check_interval_seconds.unwrap_or_else(|| {
Ok(interval_string) => i64::from_str(&interval_string).unwrap_or_else(|e| { let warn_msg = "Reload interval option not set, defaulting to 60";
let warn_msg = format!("Expected integer number, got '{interval_string}'. Defaulting to 60");
match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"),
false => println!("[WARN] {warn_msg}"),
};
60
}),
Err(_) => {
let warn_msg = "Reload interval env not set, defaulting to 60";
match connected_to_journal() { match connected_to_journal() {
true => warn!("[WARN] {warn_msg}"), true => warn!("[WARN] {warn_msg}"),
false => println!("[WARN] {warn_msg}"), false => println!("[WARN] {warn_msg}"),
} }
60 60
}, }) as i64;
};
loop { loop {
now = Utc::now(); now = Utc::now();
if now >= start + Duration::seconds(reload_interval) { if now >= start + Duration::seconds(reload_interval) {
start = now; start = now;
if let Ok(uptime_url) = env::var("UPTIME_URL") { if let Some(uptime_url) = &config.uptime_url {
get(uptime_url); let _ = get(uptime_url);
} }
match InterfaceConfig::load() { match InterfaceConfig::load() {
@ -353,10 +360,9 @@ fn main() {
ifaces = new_cfg ifaces = new_cfg
} }
}, },
Err(e) => { Err(e) => {
let err_msg = format!("Unable to load ínterfaces.toml with error: {}", e); let err_msg = format!("Unable to load ínterfaces.toml with error: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -496,7 +502,72 @@ fn main() {
} }
} }
Err(e) => { Err(e) => {
let err_msg = format!("Unable to load from zones.d with error: {}", e); let err_msg = format!("Unable to load from zones.d with error: {e}");
match connected_to_journal() {
true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"),
}
}
}
match AppConfig::load() {
Ok(new_cfg) => {
if config != new_cfg {
if config.cloudflare_api_token != new_cfg.cloudflare_api_token {
let info_msg = "API token in config.toml changed";
match connected_to_journal() {
true => info!("[INFO] {info_msg}"),
false => println!("[INFO] {info_msg}"),
}
}
if config.check_interval_seconds != new_cfg.check_interval_seconds {
let info_msg = match config.check_interval_seconds {
Some(old_interval) => {
match new_cfg.check_interval_seconds {
Some(new_interval) => format!("Check interval in config.toml changed from {old_interval}s to {new_interval}s"),
None => format!("Check interval in config.toml changed from {old_interval}s to 60s"),
}
},
None => {
match new_cfg.check_interval_seconds {
Some(new_interval) => format!("Check interval in config.toml changed from 60s to {new_interval}s"),
None => "This is a unicorn error, congratulations.".to_owned(),
}
}
};
match connected_to_journal() {
true => info!("[INFO] {info_msg}"),
false => println!("[INFO] {info_msg}"),
}
}
if config.uptime_url != new_cfg.uptime_url {
let info_msg = match &config.uptime_url {
Some(old_url) => {
match &new_cfg.uptime_url {
Some(new_url) => format!("Uptime URL in config.toml changed from '{old_url}' to '{new_url}'"),
None => "Uptime URL in config.toml was removed".to_owned(),
}
},
None => {
match &new_cfg.uptime_url {
Some(new_url) => format!("Uptime URL '{new_url}' was added to config.toml"),
None => "This is a unicorn error, congratulations.".to_owned(),
}
}
};
match connected_to_journal() {
true => info!("[INFO] {info_msg}"),
false => println!("[INFO] {info_msg}"),
}
}
config = new_cfg
}
}
Err(e) => {
let err_msg = format!("Unable to load config.toml with error: {e}");
match connected_to_journal() { match connected_to_journal() {
true => error!("[ERROR] {err_msg}"), true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"), false => eprintln!("[ERROR] {err_msg}"),
@ -506,17 +577,7 @@ fn main() {
ips.update(); ips.update();
for zone in &zone_cfgs { for zone in &zone_cfgs {
let cf_zone = match CloudflareZone::new(zone) { let cf_zone = CloudflareZone::new(zone, &config);
Ok(data) => data,
Err(e) => {
let err_msg = format!("Cloudflare Token likely not set. Error: {}", e);
match connected_to_journal() {
true => error!("[ERROR] {err_msg}"),
false => eprintln!("[ERROR] {err_msg}"),
}
continue
}
};
let cf_entries = match cf_zone.get_entries() { let cf_entries = match cf_zone.get_entries() {
Ok(entries) => entries, Ok(entries) => entries,
@ -595,7 +656,7 @@ fn main() {
if cf_zone.update(entry, r#type, &cf_entry.id, ipv6, ipv4).is_ok() { if cf_zone.update(entry, r#type, &cf_entry.id, ipv6, ipv4).is_ok() {
let info_msg = format!("Updated {} DNS Record for entry '{}' in zone '{}'", r#type, entry.name, zone.name); let info_msg = format!("Updated {} DNS Record for entry '{}' in zone '{}'", r#type, entry.name, zone.name);
match connected_to_journal() { match connected_to_journal() {
true => warn!("[INFO] {info_msg}"), true => info!("[INFO] {info_msg}"),
false => println!("[INFO] {info_msg}"), false => println!("[INFO] {info_msg}"),
} }
} }