Compare commits
454 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ca5788561 | ||
|
|
1dc33129e5 | ||
|
|
c96463bda2 | ||
|
|
edbaf6d697 | ||
|
|
58275ecd13 | ||
|
|
c6d1137eb0 | ||
|
|
fb032ea6e7 | ||
|
|
536b3497c9 | ||
|
|
8f09a1d837 | ||
|
|
c255082ef5 | ||
|
|
76b7453f90 | ||
|
|
66ed7c9ea3 | ||
|
|
ac2f13adef | ||
|
|
6b919f3a2e | ||
|
|
4d21bae669 | ||
|
|
7ea0bbb85c | ||
|
|
3ddec99f4a | ||
|
|
e1f12668fa | ||
|
|
686da5a948 | ||
|
|
8a2829de87 | ||
|
|
3a592e56ba | ||
|
|
3c91b6558d | ||
|
|
b9a6970bfd | ||
|
|
20f8c6af3c | ||
|
|
c35ed68051 | ||
|
|
75a32d22a3 | ||
|
|
71e262c37f | ||
|
|
04b909c837 | ||
|
|
309ee78903 | ||
|
|
d6f5552ccf | ||
|
|
67a973a17d | ||
|
|
0b60601f86 | ||
|
|
0b5da9f0da | ||
|
|
0589641bf0 | ||
|
|
ddf972cede | ||
|
|
73de49323c | ||
|
|
16385af3ef | ||
|
|
6cb0be82ca | ||
|
|
2dd31ce6ee | ||
|
|
31a9e18997 | ||
|
|
821c7dc190 | ||
|
|
eedd93d782 | ||
|
|
c5faf3d174 | ||
|
|
1f3f849106 | ||
|
|
ca74152d1d | ||
|
|
4fd0f15d90 | ||
|
|
b9f19fc357 | ||
|
|
2380359270 | ||
|
|
d75adb49f4 | ||
|
|
90da155053 | ||
|
|
2a61a03bdf | ||
|
|
a4bdf2454b | ||
|
|
4b503a080b | ||
|
|
46fe37b4da | ||
|
|
d6275cdd7c | ||
|
|
45cab12392 | ||
|
|
5ecdfb53c2 | ||
|
|
d86b325dfe | ||
|
|
c65ea9c47c | ||
|
|
741717aa38 | ||
|
|
2d13cd2f1d | ||
|
|
788e7cc777 | ||
|
|
0ac89ac2e3 | ||
|
|
e5ea361b53 | ||
|
|
df0155abe1 | ||
|
|
ca00ffa101 | ||
|
|
3ad8965959 | ||
|
|
460f83580e | ||
|
|
c7ad7113d7 | ||
|
|
0a6ebadb52 | ||
|
|
b9e401aaa3 | ||
|
|
18ab94135f | ||
|
|
be0efa2332 | ||
|
|
9bde5de601 | ||
|
|
db42ed1e4f | ||
|
|
262ffe458b | ||
|
|
e59f5db145 | ||
|
|
362c604744 | ||
|
|
68a03cc877 | ||
|
|
671da760d3 | ||
|
|
3c3d913934 | ||
|
|
50be36400c | ||
|
|
5f9523afa6 | ||
|
|
81a31b9e7b | ||
|
|
d0affcb376 | ||
|
|
9939cf1d77 | ||
|
|
ce7f926e92 | ||
|
|
6b4f77bdfe | ||
|
|
267792aa1e | ||
|
|
9331cbff4b | ||
|
|
d30a5f1b95 | ||
|
|
d6e25403ee | ||
|
|
79f4a7cef0 | ||
|
|
9ed3ede0d9 | ||
|
|
771b7cfcc7 | ||
|
|
7bb86e4118 | ||
|
|
c992fd48b0 | ||
|
|
afc8241c2c | ||
|
|
6cae37e720 | ||
|
|
d604aec9f1 | ||
|
|
bb4698429f | ||
|
|
634e3b0e46 | ||
|
|
21c7c8a008 | ||
|
|
9048429bbb | ||
|
|
9c33fcb32a | ||
|
|
eb1f2ac01c | ||
|
|
d88e940a57 | ||
|
|
f27f796b34 | ||
|
|
318ee3b7d3 | ||
|
|
f894585a2e | ||
|
|
ac2f63b138 | ||
|
|
be8f25f8b8 | ||
|
|
c85e4227cf | ||
|
|
c9042704d5 | ||
|
|
57f29a2c5d | ||
|
|
142e9f4a1a | ||
|
|
0c65c27e0c | ||
|
|
4a53e56bd2 | ||
|
|
d349a4640f | ||
|
|
dfcdb1a747 | ||
|
|
e05ef73011 | ||
|
|
2c29b25782 | ||
|
|
d87cad76fb | ||
|
|
9e47b61c8f | ||
|
|
4413224a31 | ||
|
|
d882652a85 | ||
|
|
f73b965fcd | ||
|
|
fe598a05f6 | ||
|
|
09977fdfec | ||
|
|
b9ebb05246 | ||
|
|
955e36a955 | ||
|
|
972591fe39 | ||
|
|
14db88d6bb | ||
|
|
64d0621d2b | ||
|
|
5dabdfe354 | ||
|
|
e7c0ca47b4 | ||
|
|
2bb7c05ed1 | ||
|
|
20ad03fe15 | ||
|
|
58231e55df | ||
|
|
12674c0824 | ||
|
|
c59e11a332 | ||
|
|
ec1d4c5500 | ||
|
|
34f45d011d | ||
|
|
539f9d4da0 | ||
|
|
c6342ed84c | ||
|
|
9072a6a7f0 | ||
|
|
3b5d10d087 | ||
|
|
0d5d3a1b22 | ||
|
|
8d2e023ec0 | ||
|
|
4a1473aee9 | ||
|
|
78f9e38425 | ||
|
|
08c7691d1e | ||
|
|
62bf9957dc | ||
|
|
dafc9983f5 | ||
|
|
a44b8e4bfc | ||
|
|
c8e69c6139 | ||
|
|
da8893f477 | ||
|
|
7562376373 | ||
|
|
619cebb62c | ||
|
|
6a2200a8e6 | ||
|
|
661433c115 | ||
|
|
e7e7a817bb | ||
|
|
d245226053 | ||
|
|
a5d10a6256 | ||
|
|
c32761e786 | ||
|
|
095696ec04 | ||
|
|
7971cf0adc | ||
|
|
fc83883934 | ||
|
|
1550f29f06 | ||
|
|
a206980242 | ||
|
|
8c2f56b0e6 | ||
|
|
b4349b41ce | ||
|
|
67f04787d6 | ||
|
|
1ee922d16c | ||
|
|
14ab586603 | ||
|
|
372070ab39 | ||
|
|
4004a93d1a | ||
|
|
c2bb190dce | ||
|
|
b8eae60fcc | ||
|
|
c86ff5d084 | ||
|
|
126da094bd | ||
|
|
f713b14ba0 | ||
|
|
a4e20f79a3 | ||
|
|
6b146ed2d1 | ||
|
|
e0e0baf076 | ||
|
|
95e799ed6e | ||
|
|
202aa25c09 | ||
|
|
06de172952 | ||
|
|
ff5ee29566 | ||
|
|
d393497641 | ||
|
|
0034538794 | ||
|
|
33d2163f19 | ||
|
|
ea26171c18 | ||
|
|
82dfcbcd83 | ||
|
|
233453267e | ||
|
|
f3c27f706f | ||
|
|
983d79b3e6 | ||
|
|
6d8abc2e30 | ||
|
|
38775cffdf | ||
|
|
b13a75a223 | ||
|
|
21026d9414 | ||
|
|
ba74051502 | ||
|
|
cdbe4c9b86 | ||
|
|
ca04c13315 | ||
|
|
3c86af0e59 | ||
|
|
ddaa1bf0d4 | ||
|
|
6b8ba3c15e | ||
|
|
7536c312ee | ||
|
|
a8b6eb9b70 | ||
|
|
67385b7ed4 | ||
|
|
64e61aac4a | ||
|
|
2fd5b944ad | ||
|
|
f91606bb17 | ||
|
|
122bc6b927 | ||
|
|
3491dbfd04 | ||
|
|
871067acd8 | ||
|
|
06cf7afbc2 | ||
|
|
81927334f2 | ||
|
|
01bf9ca42a | ||
|
|
c8c6533440 | ||
|
|
f1b15f7e92 | ||
|
|
e0c351f0e4 | ||
|
|
7957acf42f | ||
|
|
c3e8d76d63 | ||
|
|
128a3ab1be | ||
|
|
df3e9e5f51 | ||
|
|
c322458dcb | ||
|
|
21be1bd58e | ||
|
|
469a267150 | ||
|
|
090727b1d3 | ||
|
|
85ffbcf05e | ||
|
|
528abc9c97 | ||
|
|
8b98fd06ed | ||
|
|
bc6fb0c934 | ||
|
|
e773e3302c | ||
|
|
0cf59cf0fa | ||
|
|
bc471cb0bd | ||
|
|
429510e168 | ||
|
|
4c9401175c | ||
|
|
235673dac8 | ||
|
|
d737948f64 | ||
|
|
52283478c8 | ||
|
|
c84be5de61 | ||
|
|
d85982dc51 | ||
|
|
5c61f6cb65 | ||
|
|
4c0a94d2b9 | ||
|
|
5c090d25e1 | ||
|
|
89c0706abc | ||
|
|
e5695f862f | ||
|
|
e3db5fc601 | ||
|
|
9c51050283 | ||
|
|
17779bad94 | ||
|
|
fed58f03bf | ||
|
|
c5b3b8dd68 | ||
|
|
46986714d4 | ||
|
|
4f3debcb5b | ||
|
|
223ef72250 | ||
|
|
cf467db61d | ||
|
|
fae1d13892 | ||
|
|
4265bcb178 | ||
|
|
9471c69882 | ||
|
|
79c0b446e1 | ||
|
|
a478f2460b | ||
|
|
2dc599f266 | ||
|
|
d7f7ef9965 | ||
|
|
888e44e53d | ||
|
|
18d28533eb | ||
|
|
56527e5dd9 | ||
|
|
997a771dc8 | ||
|
|
77f0012f6b | ||
|
|
b7b5ffa8dd | ||
|
|
34b66002e9 | ||
|
|
71b560667b | ||
|
|
9dd51b79b5 | ||
|
|
7fd062c4d8 | ||
|
|
3731b65bd5 | ||
|
|
6057b134ae | ||
|
|
0749de3d1f | ||
|
|
d48c557134 | ||
|
|
a705fbca73 | ||
|
|
276c480f50 | ||
|
|
25ba68104b | ||
|
|
3d01e4d0cf | ||
|
|
1b0b0ca445 | ||
|
|
e1a2591c4d | ||
|
|
f8a12917e2 | ||
|
|
37b45d411d | ||
|
|
22ebf21487 | ||
|
|
bf5fffaca7 | ||
|
|
9debd22179 | ||
|
|
a8ce1354c8 | ||
|
|
0a780a959a | ||
|
|
951b4ed002 | ||
|
|
755ec8bf2f | ||
|
|
1c1407e083 | ||
|
|
9463c3c69f | ||
|
|
54bcf5626f | ||
|
|
ba8a50c829 | ||
|
|
bb57a9e616 | ||
|
|
4f4dfe3ac0 | ||
|
|
d4ce5b1c2a | ||
|
|
b6d1bd7335 | ||
|
|
17ec88d96f | ||
|
|
0df38cd64e | ||
|
|
0932c5c498 | ||
|
|
73ca4ebdbc | ||
|
|
da6596e516 | ||
|
|
d88629e23f | ||
|
|
d581401f4e | ||
|
|
60c35cb93c | ||
|
|
2c3fea321b | ||
|
|
40f00c6f0b | ||
|
|
00e51f32b5 | ||
|
|
f90fb8b946 | ||
|
|
2ff1fa1b85 | ||
|
|
7eff36b3bb | ||
|
|
5332b31b92 | ||
|
|
16640ee174 | ||
|
|
5fe170666a | ||
|
|
7e6f81f814 | ||
|
|
80c770357c | ||
|
|
5cc317de5b | ||
|
|
515e5f8c8a | ||
|
|
3d53bda121 | ||
|
|
8bc5b16527 | ||
|
|
c1a927fff1 | ||
|
|
760325eb76 | ||
|
|
bf256aa5a7 | ||
|
|
8dbe6fc0b7 | ||
|
|
fe8b0e98ab | ||
|
|
ef45578af3 | ||
|
|
89b88416b3 | ||
|
|
5d913ad192 | ||
|
|
711035fd8f | ||
|
|
0f74165c9d | ||
|
|
46e1a87e9e | ||
|
|
f998eee467 | ||
|
|
230d6a435f | ||
|
|
53c0982c8b | ||
|
|
d6cfa57ef3 | ||
|
|
49b9dc8888 | ||
|
|
1335c44deb | ||
|
|
9b5ea13a33 | ||
|
|
66eeee5548 | ||
|
|
597c045f9e | ||
|
|
a4b899c256 | ||
|
|
5421aad03e | ||
|
|
eeccfb27f8 | ||
|
|
4cf3280500 | ||
|
|
8c4a9aa6e3 | ||
|
|
9ab566884d | ||
|
|
37102e5a01 | ||
|
|
5a98fa1f76 | ||
|
|
114f562758 | ||
|
|
b3c8045b52 | ||
|
|
a0419bc1f0 | ||
|
|
e35a9da921 | ||
|
|
97447b2f3b | ||
|
|
c67f313ee8 | ||
|
|
49a9f6f2db | ||
|
|
e6683803ed | ||
|
|
27fa284eda | ||
|
|
b98e331375 | ||
|
|
6c9bd7a632 | ||
|
|
5816f495f4 | ||
|
|
5d5a85b7b6 | ||
|
|
c78cf82fc6 | ||
|
|
d77677312c | ||
|
|
d38fcb0549 | ||
|
|
c7410b0be9 | ||
|
|
20c561c83c | ||
|
|
7320c10dd3 | ||
|
|
f418481b9f | ||
|
|
a3516474e8 | ||
|
|
9e2e0019fb | ||
|
|
aef3d89814 | ||
|
|
f2641fb0e5 | ||
|
|
e50438dc11 | ||
|
|
6062df0923 | ||
|
|
989c52ef24 | ||
|
|
4a589286b7 | ||
|
|
3327df8d9c | ||
|
|
3cdaad060b | ||
|
|
0b81dd387b | ||
|
|
64dc002c3f | ||
|
|
6c7a28a7b5 | ||
|
|
21158cb6bc | ||
|
|
71bc237639 | ||
|
|
c6da627b7d | ||
|
|
a3ac1caac6 | ||
|
|
8f3e6f1a50 | ||
|
|
99b7f996e2 | ||
|
|
aa0a9e2976 | ||
|
|
9028898ba7 | ||
|
|
0e8c1ec023 | ||
|
|
313c0ddf28 | ||
|
|
2c38de26b7 | ||
|
|
fc2a564cc0 | ||
|
|
b613758419 | ||
|
|
9c03915cb0 | ||
|
|
e29aa4e205 | ||
|
|
a45c9f9f50 | ||
|
|
b3ba17bfd4 | ||
|
|
2610739624 | ||
|
|
567a915336 | ||
|
|
68eddd2377 | ||
|
|
aeb92416c8 | ||
|
|
cca5c49eaa | ||
|
|
8c778c14dc | ||
|
|
d5c798d1a9 | ||
|
|
14e1eea22d | ||
|
|
ab6b37bdcf | ||
|
|
c8c4eb59b7 | ||
|
|
2651abbe6c | ||
|
|
7b77d991df | ||
|
|
64465510de | ||
|
|
f59749b1c3 | ||
|
|
27ef7e5538 | ||
|
|
a7a467a167 | ||
|
|
21af75a2d2 | ||
|
|
2bd3366bb1 | ||
|
|
d89720330f | ||
|
|
8d1f286f30 | ||
|
|
c7108a632c | ||
|
|
b025cfeea9 | ||
|
|
bc8fcc744c | ||
|
|
a3f1317add | ||
|
|
c90d8284ef | ||
|
|
7ab9664255 | ||
|
|
3a22657645 | ||
|
|
64d75c012e | ||
|
|
4567f264b4 | ||
|
|
cbcd12631d | ||
|
|
c4f9a475f3 | ||
|
|
71d310c50f | ||
|
|
b486786041 | ||
|
|
3dd26b500d | ||
|
|
aefbe1f5b6 | ||
|
|
13135498c1 | ||
|
|
9f918972d2 | ||
|
|
b25805348f | ||
|
|
d6c48f80f4 | ||
|
|
59dab6a568 | ||
|
|
ecfb96d339 | ||
|
|
e0baf4c7ec | ||
|
|
e4444ae6a5 | ||
|
|
8e4adb6e39 | ||
|
|
6aaa446354 | ||
|
|
7d5f6c8331 | ||
|
|
3d8672bc59 | ||
|
|
b49db58ec2 | ||
|
|
edc808ee89 | ||
|
|
518cbd10e0 | ||
|
|
0a8761ee68 |
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -10,3 +10,13 @@ updates:
|
||||
target-branch: development
|
||||
reviewers:
|
||||
- "pi-hole/core-maintainers"
|
||||
- package-ecosystem: pip
|
||||
directory: "/test"
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: saturday
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
target-branch: development
|
||||
reviewers:
|
||||
- "pi-hole/core-maintainers"
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v3.4.0
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
-
|
||||
name: Initialize CodeQL
|
||||
|
||||
21
.github/workflows/merge-conflict.yml
vendored
Normal file
21
.github/workflows/merge-conflict.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: "Check for merge conflicts"
|
||||
on:
|
||||
# So that PRs touching the same files as the push are updated
|
||||
push:
|
||||
# So that the `dirtyLabel` is removed if conflicts are resolve
|
||||
# We recommend `pull_request_target` so that github secrets are available.
|
||||
# In `pull_request` we wouldn't be able to change labels of fork PRs
|
||||
pull_request_target:
|
||||
types: [synchronize]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if PRs are have merge conflicts
|
||||
uses: eps1lon/actions-label-merge-conflict@v2.1.0
|
||||
with:
|
||||
dirtyLabel: "PR: Merge Conflict"
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."
|
||||
commentOnClean: "Conflicts have been resolved."
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
- uses: actions/stale@v7.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 30
|
||||
|
||||
35
.github/workflows/stale_pr.yml
vendored
Normal file
35
.github/workflows/stale_pr.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Close stale PR
|
||||
# This action will add a `stale` label and close immediately every PR that meets the following conditions:
|
||||
# - it is already marked with "merge conflict" label
|
||||
# - there was no update/comment on the PR in the last 30 days.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v7.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Do not automatically mark PR/issue as stale
|
||||
days-before-stale: -1
|
||||
# Override 'days-before-stale' for PR only
|
||||
days-before-pr-stale: 30
|
||||
# Close PRs immediately, after marking them 'stale'
|
||||
days-before-pr-close: 0
|
||||
# only run the action on merge conflict PR
|
||||
any-of-labels: 'PR: Merge Conflict'
|
||||
exempt-pr-labels: 'internal, never-stale, ON HOLD, WIP'
|
||||
exempt-all-pr-assignees: true
|
||||
operations-per-run: 300
|
||||
stale-pr-message: ''
|
||||
close-pr-message: 'Existing merge conflicts have not been addressed. This PR is considered abandoned.'
|
||||
37
.github/workflows/sync-back-to-dev.yml
vendored
37
.github/workflows/sync-back-to-dev.yml
vendored
@@ -5,23 +5,36 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
# The section is needed to drop the default write-all permissions for all jobs
|
||||
# that are granted on `push` event. By specifying any permission explicitly
|
||||
# all others are set to none. By using the principle of least privilege the damage a compromised
|
||||
# workflow can do (because of an injection or compromised third party tool or
|
||||
# action) is restricted. Adding labels to issues, commenting
|
||||
# on pull-requests, etc. may need additional permissions:
|
||||
#
|
||||
# Syntax for this section:
|
||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
||||
#
|
||||
# Reference for how to assign permissions on a job-by-job basis:
|
||||
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
|
||||
#
|
||||
# Reference for available permissions that we can enable if needed:
|
||||
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
sync-branches:
|
||||
# The job needs to be able to pull the code and create a pull request.
|
||||
permissions:
|
||||
contents: read # for actions/checkout
|
||||
pull-requests: write # to create pull request
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
name: Syncing branches
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v3.4.0
|
||||
- name: Opening pull request
|
||||
id: pull
|
||||
uses: tretuna/sync-branches@1.4.0
|
||||
with:
|
||||
run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'internal'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
FROM_BRANCH: 'master'
|
||||
TO_BRANCH: 'development'
|
||||
- name: Label the pull request to ignore for release note generation
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
labels: internal
|
||||
repo: ${{ github.repository }}
|
||||
number: ${{ steps.pull.outputs.PULL_REQUEST_NUMBER }}
|
||||
|
||||
91
.github/workflows/test.yml
vendored
91
.github/workflows/test.yml
vendored
@@ -12,51 +12,68 @@ jobs:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Check scripts in repository are executable
|
||||
run: |
|
||||
IFS=$'\n';
|
||||
for f in $(find . -name '*.sh'); do if [[ ! -x $f ]]; then echo "$f is not executable" && FAIL=1; fi ;done
|
||||
unset IFS;
|
||||
# If FAIL is 1 then we fail.
|
||||
[[ $FAIL == 1 ]] && exit 1 || echo "Scripts are executable!"
|
||||
-
|
||||
name: Spell-Checking
|
||||
uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
ignore_words_file: .codespellignore
|
||||
-
|
||||
name: Get editorconfig-checker
|
||||
uses: editorconfig-checker/action-editorconfig-checker@main
|
||||
-
|
||||
name: Run editorconfig-checker
|
||||
run: editorconfig-checker
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3.4.0
|
||||
|
||||
- name: Check scripts in repository are executable
|
||||
run: |
|
||||
IFS=$'\n';
|
||||
for f in $(find . -name '*.sh'); do if [[ ! -x $f ]]; then echo "$f is not executable" && FAIL=1; fi ;done
|
||||
unset IFS;
|
||||
# If FAIL is 1 then we fail.
|
||||
[[ $FAIL == 1 ]] && exit 1 || echo "Scripts are executable!"
|
||||
|
||||
- name: Spell-Checking
|
||||
uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
ignore_words_file: .codespellignore
|
||||
|
||||
- name: Get editorconfig-checker
|
||||
uses: editorconfig-checker/action-editorconfig-checker@main # tag v1.0.0 is really out of date
|
||||
|
||||
- name: Run editorconfig-checker
|
||||
run: editorconfig-checker
|
||||
|
||||
- name: Check python code formatting with black
|
||||
uses: psf/black@stable
|
||||
with:
|
||||
src: "./test"
|
||||
options: "--check --diff --color"
|
||||
|
||||
distro-test:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
needs: smoke-tests
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
distro: [debian_10, debian_11, ubuntu_18, ubuntu_20, ubuntu_21, ubuntu_22, centos_7, centos_8, fedora_34]
|
||||
distro:
|
||||
[
|
||||
debian_10,
|
||||
debian_11,
|
||||
ubuntu_20,
|
||||
ubuntu_22,
|
||||
centos_8,
|
||||
centos_9,
|
||||
fedora_36,
|
||||
fedora_37,
|
||||
]
|
||||
env:
|
||||
DISTRO: ${{matrix.distro}}
|
||||
steps:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
-
|
||||
name: Install dependencies
|
||||
run: pip install -r test/requirements.txt
|
||||
-
|
||||
name: Test with tox
|
||||
run: tox -c test/tox.${DISTRO}.ini
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3.4.0
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v4.5.0
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install wheel
|
||||
run: pip install wheel
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install -r test/requirements.txt
|
||||
|
||||
- name: Test with tox
|
||||
run: tox -c test/tox.${DISTRO}.ini
|
||||
|
||||
34
README.md
34
README.md
@@ -3,26 +3,26 @@
|
||||
#
|
||||
|
||||
<p align="center">
|
||||
<a href="https://pi-hole.net/#gh-light-mode-only">
|
||||
<img src="https://github.com/pi-hole/graphics/blob/master/Vortex/Vortex_Vertical_wordmark_lightmode.png?raw=true)" alt="Pi-hole">
|
||||
</a>
|
||||
<a href="https://pi-hole.net/#gh-dark-mode-only">
|
||||
<img src="https://github.com/pi-hole/graphics/blob/master/Vortex/Vortex_Vertical_wordmark_darkmode.png?raw=true" alt="Pi-hole">
|
||||
</a>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://pi-hole.github.io/graphics/Vortex/Vortex_Vertical_wordmark_darkmode.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://pi-hole.github.io/graphics/Vortex/Vortex_Vertical_wordmark_lightmode.png">
|
||||
<img src="https://pi-hole.github.io/graphics/Vortex/Vortex_Vertical_wordmark_lightmode.png" width="168" height="270" alt="Pi-hole website">
|
||||
</picture>
|
||||
<br>
|
||||
<strong>Network-wide ad blocking via your own Linux hardware</strong>
|
||||
</p>
|
||||
|
||||
<!-- markdownlint-enable MD033 -->
|
||||
|
||||
The Pi-hole® is a [DNS sinkhole](https://en.wikipedia.org/wiki/DNS_Sinkhole) that protects your devices from unwanted content without installing any client-side software.
|
||||
|
||||
- **Easy-to-install**: our versatile installer walks you through the process and takes less than ten minutes
|
||||
- **Easy-to-install**: our dialogs walk you through the simple installation process in less than ten minutes
|
||||
- **Resolute**: content is blocked in _non-browser locations_, such as ad-laden mobile apps and smart TVs
|
||||
- **Responsive**: seamlessly speeds up the feel of everyday browsing by caching DNS queries
|
||||
- **Lightweight**: runs smoothly with [minimal hardware and software requirements](https://docs.pi-hole.net/main/prerequisites/)
|
||||
- **Robust**: a command line interface that is quality assured for interoperability
|
||||
- **Robust**: a command-line interface that is quality assured for interoperability
|
||||
- **Insightful**: a beautiful responsive Web Interface dashboard to view and control your Pi-hole
|
||||
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring *all* your devices are protected automatically
|
||||
- **Versatile**: can optionally function as a [DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026), ensuring _all_ your devices are protected automatically
|
||||
- **Scalable**: [capable of handling hundreds of millions of queries](https://pi-hole.net/2017/05/24/how-much-traffic-can-pi-hole-handle/) when installed on server-grade hardware
|
||||
- **Modern**: blocks ads over both IPv4 and IPv6
|
||||
- **Free**: open source software that helps ensure _you_ are the sole person in control of your privacy
|
||||
@@ -53,12 +53,14 @@ sudo bash basic-install.sh
|
||||
wget -O basic-install.sh https://install.pi-hole.net
|
||||
sudo bash basic-install.sh
|
||||
```
|
||||
|
||||
### Method 3: Using Docker to deploy Pi-hole
|
||||
|
||||
Please refer to the [Pi-hole docker repo](https://github.com/pi-hole/docker-pi-hole) to use the Official Docker Images.
|
||||
|
||||
## [Post-install: Make your network take advantage of Pi-hole](https://docs.pi-hole.net/main/post-install/)
|
||||
|
||||
Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245) which ensures that all devices connecting to your network will have content blocked without any further intervention.
|
||||
Once the installer has been run, you will need to [configure your router to have **DHCP clients use Pi-hole as their DNS server**](https://discourse.pi-hole.net/t/how-do-i-configure-my-devices-to-use-pi-hole-as-their-dns-server/245). This router configuration will ensure that all devices connecting to your network will have content blocked without any further intervention.
|
||||
|
||||
If your router does not support setting the DNS server, you can [use Pi-hole's built-in DHCP server](https://discourse.pi-hole.net/t/how-do-i-use-pi-holes-built-in-dhcp-server-and-why-would-i-want-to/3026); be sure to disable DHCP on your router first (if it has that feature available).
|
||||
|
||||
@@ -68,7 +70,7 @@ As a last resort, you can manually set each device to use Pi-hole as their DNS s
|
||||
|
||||
## Pi-hole is free but powered by your support
|
||||
|
||||
There are many reoccurring costs involved with maintaining free, open source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software and the importance of keeping it maintained.
|
||||
There are many reoccurring costs involved with maintaining free, open-source, and privacy-respecting software; expenses which [our volunteer developers](https://github.com/orgs/pi-hole/people) pitch in to cover out-of-pocket. This is just one example of how strongly we feel about our software and the importance of keeping it maintained.
|
||||
|
||||
Make no mistake: **your support is absolutely vital to help keep us innovating!**
|
||||
|
||||
@@ -85,7 +87,7 @@ If you'd rather not donate (_which is okay!_), there are other ways you can help
|
||||
- [Hetzner Cloud](https://hetzner.cloud/?ref=7aceisRX3AzA) _affiliate link_
|
||||
- [Digital Ocean](https://www.digitalocean.com/?refcode=344d234950e1) _affiliate link_
|
||||
- [Stickermule](https://www.stickermule.com/unlock?ref_id=9127301701&utm_medium=link&utm_source=invite) _earn a $10 credit after your first purchase_
|
||||
- [Amazon US](http://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
|
||||
- [Amazon US](https://www.amazon.com/exec/obidos/redirect-home/pihole09-20) _affiliate link_
|
||||
- Spreading the word about our software and how you have benefited from it
|
||||
|
||||
### Contributing via GitHub
|
||||
@@ -115,7 +117,7 @@ While we are primarily reachable on our [Discourse User Forum](https://discourse
|
||||
|
||||
### [Faster-than-light Engine](https://github.com/pi-hole/ftl)
|
||||
|
||||
[FTLDNS](https://github.com/pi-hole/ftl) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all *very quickly*!
|
||||
[FTLDNS](https://github.com/pi-hole/ftl) is a lightweight, purpose-built daemon used to provide statistics needed for the Web Interface, and its API can be easily integrated into your own projects. As the name implies, FTLDNS does this all _very quickly_!
|
||||
|
||||
Some of the statistics you can integrate include:
|
||||
|
||||
@@ -130,9 +132,9 @@ Some of the statistics you can integrate include:
|
||||
|
||||
Access the API via [`telnet`](https://github.com/pi-hole/FTL), the Web (`admin/api.php`) and Command Line (`pihole -c -j`). You can find out [more details over here](https://discourse.pi-hole.net/t/pi-hole-api/1863).
|
||||
|
||||
### The Command Line Interface
|
||||
### The Command-Line Interface
|
||||
|
||||
The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to fully administer the Pi-hole, without the need of the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
|
||||
The [pihole](https://docs.pi-hole.net/core/pihole-command/) command has all the functionality necessary to fully administer the Pi-hole, without the need for the Web Interface. It's fast, user-friendly, and auditable by anyone with an understanding of `bash`.
|
||||
|
||||
Some notable features include:
|
||||
|
||||
@@ -142,7 +144,7 @@ Some notable features include:
|
||||
- [Updating Ad Lists](https://docs.pi-hole.net/core/pihole-command/#gravity)
|
||||
- [Querying Ad Lists for blocked domains](https://docs.pi-hole.net/core/pihole-command/#query)
|
||||
- [Enabling and Disabling Pi-hole](https://docs.pi-hole.net/core/pihole-command/#enable-disable)
|
||||
- ... and *many* more!
|
||||
- ... and _many_ more!
|
||||
|
||||
You can read our [Core Feature Breakdown](https://docs.pi-hole.net/core/pihole-command/#pi-hole-core) for more information.
|
||||
|
||||
|
||||
@@ -29,13 +29,6 @@ bogus-priv
|
||||
|
||||
no-resolv
|
||||
|
||||
server=@DNS1@
|
||||
server=@DNS2@
|
||||
|
||||
interface=@INT@
|
||||
|
||||
cache-size=@CACHE_SIZE@
|
||||
|
||||
log-queries
|
||||
log-facility=/var/log/pihole/pihole.log
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 35 B |
Binary file not shown.
|
Before Width: | Height: | Size: 26 B |
Binary file not shown.
|
Before Width: | Height: | Size: 37 B |
Binary file not shown.
|
Before Width: | Height: | Size: 43 B |
@@ -14,7 +14,9 @@ LC_NUMERIC=C
|
||||
# Retrieve stats from FTL engine
|
||||
pihole-FTL() {
|
||||
local ftl_port LINE
|
||||
ftl_port=$(cat /run/pihole-FTL.port 2> /dev/null)
|
||||
# shellcheck disable=SC1091
|
||||
. /opt/pihole/utils.sh
|
||||
ftl_port=$(getFTLAPIPort)
|
||||
if [[ -n "$ftl_port" ]]; then
|
||||
# Open connection to FTL
|
||||
exec 3<>"/dev/tcp/127.0.0.1/$ftl_port"
|
||||
@@ -503,11 +505,11 @@ chronoFunc() {
|
||||
fi
|
||||
|
||||
printFunc " Pi-hole: " "$ph_status" "$ph_info"
|
||||
printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info"
|
||||
printFunc " Blocked: " "$ads_percentage_today%" "$ads_info"
|
||||
printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info"
|
||||
|
||||
printFunc " Blocked: " "$recent_blocked"
|
||||
printFunc "Top Advert: " "$top_ad"
|
||||
printFunc "Last Block: " "$recent_blocked"
|
||||
printFunc " Top Block: " "$top_ad"
|
||||
|
||||
# Provide more stats on screens with more lines
|
||||
if [[ "$scr_lines" -eq 17 ]]; then
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||
PH_TEST="true"
|
||||
SKIP_INSTALL="true"
|
||||
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||
|
||||
# webInterfaceGitUrl set in basic-install.sh
|
||||
@@ -164,6 +164,8 @@ checkout() {
|
||||
exit 1
|
||||
fi
|
||||
checkout_pull_branch "${webInterfaceDir}" "${2}"
|
||||
# Update local and remote versions via updatechecker
|
||||
/opt/pihole/updatecheck.sh
|
||||
elif [[ "${1}" == "ftl" ]] ; then
|
||||
local path
|
||||
local oldbranch
|
||||
@@ -178,6 +180,8 @@ checkout() {
|
||||
FTLinstall "${binary}"
|
||||
restart_service pihole-FTL
|
||||
enable_service pihole-FTL
|
||||
# Update local and remote versions via updatechecker
|
||||
/opt/pihole/updatecheck.sh
|
||||
else
|
||||
echo " ${CROSS} Requested branch \"${2}\" is not available"
|
||||
ftlbranches=( $(git ls-remote https://github.com/pi-hole/ftl | grep 'heads' | sed 's/refs\/heads\///;s/ //g' | awk '{print $2}') )
|
||||
|
||||
@@ -41,18 +41,15 @@ else
|
||||
#OVER="\r\033[K"
|
||||
fi
|
||||
|
||||
OBFUSCATED_PLACEHOLDER="<DOMAIN OBFUSCATED>"
|
||||
# shellcheck disable=SC1091
|
||||
. /etc/pihole/versions
|
||||
|
||||
# FAQ URLs for use in showing the debug log
|
||||
FAQ_UPDATE_PI_HOLE="${COL_CYAN}https://discourse.pi-hole.net/t/how-do-i-update-pi-hole/249${COL_NC}"
|
||||
FAQ_CHECKOUT_COMMAND="${COL_CYAN}https://discourse.pi-hole.net/t/the-pihole-command-with-examples/738#checkout${COL_NC}"
|
||||
FAQ_HARDWARE_REQUIREMENTS="${COL_CYAN}https://docs.pi-hole.net/main/prerequisites/${COL_NC}"
|
||||
FAQ_HARDWARE_REQUIREMENTS_PORTS="${COL_CYAN}https://docs.pi-hole.net/main/prerequisites/#ports${COL_NC}"
|
||||
FAQ_HARDWARE_REQUIREMENTS_FIREWALLD="${COL_CYAN}https://docs.pi-hole.net/main/prerequisites/#firewalld${COL_NC}"
|
||||
FAQ_GATEWAY="${COL_CYAN}https://discourse.pi-hole.net/t/why-is-a-default-gateway-important-for-pi-hole/3546${COL_NC}"
|
||||
FAQ_ULA="${COL_CYAN}https://discourse.pi-hole.net/t/use-ipv6-ula-addresses-for-pi-hole/2127${COL_NC}"
|
||||
FAQ_FTL_COMPATIBILITY="${COL_CYAN}https://github.com/pi-hole/FTL#compatibility-list${COL_NC}"
|
||||
FAQ_BAD_ADDRESS="${COL_CYAN}https://discourse.pi-hole.net/t/why-do-i-see-bad-address-at-in-pihole-log/3972${COL_NC}"
|
||||
|
||||
# Other URLs we may use
|
||||
FORUMS_URL="${COL_CYAN}https://discourse.pi-hole.net${COL_NC}"
|
||||
@@ -69,9 +66,10 @@ RUN_DIRECTORY="/run"
|
||||
LOG_DIRECTORY="/var/log/pihole"
|
||||
WEB_SERVER_LOG_DIRECTORY="/var/log/lighttpd"
|
||||
WEB_SERVER_CONFIG_DIRECTORY="/etc/lighttpd"
|
||||
WEB_SERVER_CONFIG_DIRECTORY_FEDORA="${WEB_SERVER_CONFIG_DIRECTORY}/conf.d"
|
||||
WEB_SERVER_CONFIG_DIRECTORY_DEBIAN="${WEB_SERVER_CONFIG_DIRECTORY}/conf-enabled"
|
||||
HTML_DIRECTORY="/var/www/html"
|
||||
WEB_GIT_DIRECTORY="${HTML_DIRECTORY}/admin"
|
||||
#BLOCK_PAGE_DIRECTORY="${HTML_DIRECTORY}/pihole"
|
||||
SHM_DIRECTORY="/dev/shm"
|
||||
ETC="/etc"
|
||||
|
||||
@@ -81,6 +79,8 @@ PIHOLE_CRON_FILE="${CRON_D_DIRECTORY}/pihole"
|
||||
|
||||
WEB_SERVER_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/lighttpd.conf"
|
||||
WEB_SERVER_CUSTOM_CONFIG_FILE="${WEB_SERVER_CONFIG_DIRECTORY}/external.conf"
|
||||
WEB_SERVER_PIHOLE_CONFIG_FILE_DEBIAN="${WEB_SERVER_CONFIG_DIRECTORY_DEBIAN}/15-pihole-admin.conf"
|
||||
WEB_SERVER_PIHOLE_CONFIG_FILE_FEDORA="${WEB_SERVER_CONFIG_DIRECTORY_FEDORA}/pihole-admin.conf"
|
||||
|
||||
PIHOLE_INSTALL_LOG_FILE="${PIHOLE_DIRECTORY}/install.log"
|
||||
PIHOLE_RAW_BLOCKLIST_FILES="${PIHOLE_DIRECTORY}/list.*"
|
||||
@@ -89,6 +89,7 @@ PIHOLE_LOGROTATE_FILE="${PIHOLE_DIRECTORY}/logrotate"
|
||||
PIHOLE_SETUP_VARS_FILE="${PIHOLE_DIRECTORY}/setupVars.conf"
|
||||
PIHOLE_FTL_CONF_FILE="${PIHOLE_DIRECTORY}/pihole-FTL.conf"
|
||||
PIHOLE_CUSTOM_HOSTS_FILE="${PIHOLE_DIRECTORY}/custom.list"
|
||||
PIHOLE_VERSIONS_FILE="${PIHOLE_DIRECTORY}/versions"
|
||||
|
||||
# Read the value of an FTL config key. The value is printed to stdout.
|
||||
#
|
||||
@@ -124,7 +125,6 @@ PIHOLE_COMMAND="${BIN_DIRECTORY}/pihole"
|
||||
PIHOLE_COLTABLE_FILE="${BIN_DIRECTORY}/COL_TABLE"
|
||||
|
||||
FTL_PID="${RUN_DIRECTORY}/pihole-FTL.pid"
|
||||
FTL_PORT="${RUN_DIRECTORY}/pihole-FTL.port"
|
||||
|
||||
PIHOLE_LOG="${LOG_DIRECTORY}/pihole.log"
|
||||
PIHOLE_LOG_GZIPS="${LOG_DIRECTORY}/pihole.log.[0-9].*"
|
||||
@@ -144,6 +144,8 @@ PIHOLE_PROCESSES=( "lighttpd" "pihole-FTL" )
|
||||
REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
|
||||
"${WEB_SERVER_CONFIG_FILE}"
|
||||
"${WEB_SERVER_CUSTOM_CONFIG_FILE}"
|
||||
"${WEB_SERVER_PIHOLE_CONFIG_FILE_DEBIAN}"
|
||||
"${WEB_SERVER_PIHOLE_CONFIG_FILE_FEDORA}"
|
||||
"${PIHOLE_INSTALL_LOG_FILE}"
|
||||
"${PIHOLE_RAW_BLOCKLIST_FILES}"
|
||||
"${PIHOLE_LOCAL_HOSTS_FILE}"
|
||||
@@ -153,7 +155,6 @@ REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
|
||||
"${PIHOLE_COMMAND}"
|
||||
"${PIHOLE_COLTABLE_FILE}"
|
||||
"${FTL_PID}"
|
||||
"${FTL_PORT}"
|
||||
"${PIHOLE_LOG}"
|
||||
"${PIHOLE_LOG_GZIPS}"
|
||||
"${PIHOLE_DEBUG_LOG}"
|
||||
@@ -162,7 +163,8 @@ REQUIRED_FILES=("${PIHOLE_CRON_FILE}"
|
||||
"${PIHOLE_WEB_SERVER_ERROR_LOG_FILE}"
|
||||
"${RESOLVCONF}"
|
||||
"${DNSMASQ_CONF}"
|
||||
"${PIHOLE_CUSTOM_HOSTS_FILE}")
|
||||
"${PIHOLE_CUSTOM_HOSTS_FILE}"
|
||||
"${PIHOLE_VERSIONS_FILE}")
|
||||
|
||||
DISCLAIMER="This process collects information from your Pi-hole, and optionally uploads it to a unique and random directory on tricorder.pi-hole.net.
|
||||
|
||||
@@ -228,7 +230,7 @@ initialize_debug() {
|
||||
|
||||
# This is a function for visually displaying the current test that is being run.
|
||||
# Accepts one variable: the name of what is being diagnosed
|
||||
# Colors do not show in the dasboard, but the icons do: [i], [✓], and [✗]
|
||||
# Colors do not show in the dashboard, but the icons do: [i], [✓], and [✗]
|
||||
echo_current_diagnostic() {
|
||||
# Colors are used for visually distinguishing each test in the output
|
||||
# These colors do not show in the GUI, but the formatting will
|
||||
@@ -240,15 +242,7 @@ compare_local_version_to_git_version() {
|
||||
local git_dir="${1}"
|
||||
# The named component of the project (Core or Web)
|
||||
local pihole_component="${2}"
|
||||
# If we are checking the Core versions,
|
||||
if [[ "${pihole_component}" == "Core" ]]; then
|
||||
# We need to search for "Pi-hole" when using pihole -v
|
||||
local search_term="Pi-hole"
|
||||
elif [[ "${pihole_component}" == "Web" ]]; then
|
||||
# We need to search for "AdminLTE" so store it in a variable as well
|
||||
#shellcheck disable=2034
|
||||
local search_term="AdminLTE"
|
||||
fi
|
||||
|
||||
# Display what we are checking
|
||||
echo_current_diagnostic "${pihole_component} version"
|
||||
# Store the error message in a variable in case we want to change and/or reuse it
|
||||
@@ -261,43 +255,35 @@ compare_local_version_to_git_version() {
|
||||
log_write "${COL_RED}Could not cd into ${git_dir}$COL_NC"
|
||||
if git status &> /dev/null; then
|
||||
# The current version the user is on
|
||||
local remote_version
|
||||
remote_version=$(git describe --tags --abbrev=0);
|
||||
local local_version
|
||||
local_version=$(git describe --tags --abbrev=0);
|
||||
# What branch they are on
|
||||
local remote_branch
|
||||
remote_branch=$(git rev-parse --abbrev-ref HEAD);
|
||||
local local_branch
|
||||
local_branch=$(git rev-parse --abbrev-ref HEAD);
|
||||
# The commit they are on
|
||||
local remote_commit
|
||||
remote_commit=$(git describe --long --dirty --tags --always)
|
||||
local local_commit
|
||||
local_commit=$(git describe --long --dirty --tags --always)
|
||||
# Status of the repo
|
||||
local local_status
|
||||
local_status=$(git status -s)
|
||||
# echo this information out to the user in a nice format
|
||||
# If the current version matches what pihole -v produces, the user is up-to-date
|
||||
if [[ "${remote_version}" == "$(pihole -v | awk '/${search_term}/ {print $6}' | cut -d ')' -f1)" ]]; then
|
||||
log_write "${TICK} ${pihole_component}: ${COL_GREEN}${remote_version}${COL_NC}"
|
||||
# If not,
|
||||
else
|
||||
# echo the current version in yellow, signifying it's something to take a look at, but not a critical error
|
||||
# Also add a URL to an FAQ
|
||||
log_write "${INFO} ${pihole_component}: ${COL_YELLOW}${remote_version:-Untagged}${COL_NC} (${FAQ_UPDATE_PI_HOLE})"
|
||||
fi
|
||||
log_write "${TICK} Version: ${local_version}"
|
||||
|
||||
# Print the repo upstreams
|
||||
remotes=$(git remote -v)
|
||||
log_write "${INFO} Remotes: ${remotes//$'\n'/'\n '}"
|
||||
|
||||
# If the repo is on the master branch, they are on the stable codebase
|
||||
if [[ "${remote_branch}" == "master" ]]; then
|
||||
if [[ "${local_branch}" == "master" ]]; then
|
||||
# so the color of the text is green
|
||||
log_write "${INFO} Branch: ${COL_GREEN}${remote_branch}${COL_NC}"
|
||||
log_write "${INFO} Branch: ${COL_GREEN}${local_branch}${COL_NC}"
|
||||
# If it is any other branch, they are in a development branch
|
||||
else
|
||||
# So show that in yellow, signifying it's something to take a look at, but not a critical error
|
||||
log_write "${INFO} Branch: ${COL_YELLOW}${remote_branch:-Detached}${COL_NC} (${FAQ_CHECKOUT_COMMAND})"
|
||||
log_write "${INFO} Branch: ${COL_YELLOW}${local_branch:-Detached}${COL_NC}"
|
||||
fi
|
||||
# echo the current commit
|
||||
log_write "${INFO} Commit: ${remote_commit}"
|
||||
log_write "${INFO} Commit: ${local_commit}"
|
||||
# if `local_status` is non-null, then the repo is not clean, display details here
|
||||
if [[ ${local_status} ]]; then
|
||||
# Replace new lines in the status with 12 spaces to make the output cleaner
|
||||
@@ -331,18 +317,28 @@ compare_local_version_to_git_version() {
|
||||
}
|
||||
|
||||
check_ftl_version() {
|
||||
local ftl_name="FTL"
|
||||
echo_current_diagnostic "${ftl_name} version"
|
||||
local FTL_VERSION FTL_COMMIT FTL_BRANCH
|
||||
echo_current_diagnostic "FTL version"
|
||||
# Use the built in command to check FTL's version
|
||||
FTL_VERSION=$(pihole-FTL version)
|
||||
# Compare the current FTL version to the remote version
|
||||
if [[ "${FTL_VERSION}" == "$(pihole -v | awk '/FTL/ {print $6}' | cut -d ')' -f1)" ]]; then
|
||||
# If they are the same, FTL is up-to-date
|
||||
log_write "${TICK} ${ftl_name}: ${COL_GREEN}${FTL_VERSION}${COL_NC}"
|
||||
FTL_BRANCH=$(pihole-FTL branch)
|
||||
FTL_COMMIT=$(pihole-FTL --hash)
|
||||
|
||||
|
||||
log_write "${TICK} Version: ${FTL_VERSION}"
|
||||
|
||||
# If they use the master branch, they are on the stable codebase
|
||||
if [[ "${FTL_BRANCH}" == "master" ]]; then
|
||||
# so the color of the text is green
|
||||
log_write "${INFO} Branch: ${COL_GREEN}${FTL_BRANCH}${COL_NC}"
|
||||
# If it is any other branch, they are in a development branch
|
||||
else
|
||||
# If not, show it in yellow, signifying there is an update
|
||||
log_write "${TICK} ${ftl_name}: ${COL_YELLOW}${FTL_VERSION}${COL_NC} (${FAQ_UPDATE_PI_HOLE})"
|
||||
# So show that in yellow, signifying it's something to take a look at, but not a critical error
|
||||
log_write "${INFO} Branch: ${COL_YELLOW}${FTL_BRANCH}${COL_NC}"
|
||||
fi
|
||||
|
||||
# echo the current commit
|
||||
log_write "${INFO} Commit: ${FTL_COMMIT}"
|
||||
}
|
||||
|
||||
# Checks the core version of the Pi-hole codebase
|
||||
@@ -404,41 +400,53 @@ os_check() {
|
||||
# Extract dig response
|
||||
response="${cmdResult%%$'\n'*}"
|
||||
|
||||
IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"')
|
||||
for distro_and_versions in "${supportedOS[@]}"
|
||||
do
|
||||
distro_part="${distro_and_versions%%=*}"
|
||||
versions_part="${distro_and_versions##*=}"
|
||||
|
||||
if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then
|
||||
valid_os=true
|
||||
IFS="," read -r -a supportedVer <<<"${versions_part}"
|
||||
for version in "${supportedVer[@]}"
|
||||
do
|
||||
if [[ "${detected_version}" =~ $version ]]; then
|
||||
valid_version=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
log_write "${INFO} dig return code: ${digReturnCode}"
|
||||
log_write "${INFO} dig response: ${response}"
|
||||
|
||||
if [ "$valid_os" = true ]; then
|
||||
log_write "${TICK} Distro: ${COL_GREEN}${detected_os^}${COL_NC}"
|
||||
|
||||
if [ "$valid_version" = true ]; then
|
||||
log_write "${TICK} Version: ${COL_GREEN}${detected_version}${COL_NC}"
|
||||
else
|
||||
log_write "${CROSS} Version: ${COL_RED}${detected_version}${COL_NC}"
|
||||
log_write "${CROSS} Error: ${COL_RED}${detected_os^} is supported but version ${detected_version} is currently unsupported (${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}"
|
||||
fi
|
||||
if [ "${digReturnCode}" -ne 0 ]; then
|
||||
log_write "${INFO} Distro: ${detected_os^}"
|
||||
log_write "${INFO} Version: ${detected_version}"
|
||||
log_write "${CROSS} dig return code: ${COL_RED}${digReturnCode}${COL_NC}"
|
||||
log_write "${CROSS} dig response: ${response}"
|
||||
log_write "${CROSS} Error: ${COL_RED}dig command failed - Unable to check OS${COL_NC}"
|
||||
else
|
||||
log_write "${CROSS} Distro: ${COL_RED}${detected_os^}${COL_NC}"
|
||||
log_write "${CROSS} Error: ${COL_RED}${detected_os^} is not a supported distro (${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}"
|
||||
IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"')
|
||||
for distro_and_versions in "${supportedOS[@]}"
|
||||
do
|
||||
distro_part="${distro_and_versions%%=*}"
|
||||
versions_part="${distro_and_versions##*=}"
|
||||
|
||||
if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then
|
||||
valid_os=true
|
||||
IFS="," read -r -a supportedVer <<<"${versions_part}"
|
||||
for version in "${supportedVer[@]}"
|
||||
do
|
||||
if [[ "${detected_version}" =~ $version ]]; then
|
||||
valid_version=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
local finalmsg
|
||||
if [ "$valid_os" = true ]; then
|
||||
log_write "${TICK} Distro: ${COL_GREEN}${detected_os^}${COL_NC}"
|
||||
|
||||
if [ "$valid_version" = true ]; then
|
||||
log_write "${TICK} Version: ${COL_GREEN}${detected_version}${COL_NC}"
|
||||
finalmsg="${TICK} ${COL_GREEN}Distro and version supported${COL_NC}"
|
||||
else
|
||||
log_write "${CROSS} Version: ${COL_RED}${detected_version}${COL_NC}"
|
||||
finalmsg="${CROSS} Error: ${COL_RED}${detected_os^} is supported but version ${detected_version} is currently unsupported ${COL_NC}(${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}"
|
||||
fi
|
||||
else
|
||||
log_write "${CROSS} Distro: ${COL_RED}${detected_os^}${COL_NC}"
|
||||
finalmsg="${CROSS} Error: ${COL_RED}${detected_os^} is not a supported distro ${COL_NC}(${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}"
|
||||
fi
|
||||
|
||||
# Print dig response and the final check result
|
||||
log_write "${TICK} dig return code: ${COL_GREEN}${digReturnCode}${COL_NC}"
|
||||
log_write "${INFO} dig response: ${response}"
|
||||
log_write "${finalmsg}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -448,8 +456,8 @@ diagnose_operating_system() {
|
||||
# Display the current test that is running
|
||||
echo_current_diagnostic "Operating system"
|
||||
|
||||
# If the PIHOLE_DOCKER_TAG variable is set, include this information in the debug output
|
||||
[ -n "${PIHOLE_DOCKER_TAG}" ] && log_write "${INFO} Pi-hole Docker Container: ${PIHOLE_DOCKER_TAG}"
|
||||
# If DOCKER_VERSION is set (Sourced from /etc/pihole/versions at start of script), include this information in the debug output
|
||||
[ -n "${DOCKER_VERSION}" ] && log_write "${INFO} Pi-hole Docker Container: ${DOCKER_VERSION}"
|
||||
|
||||
# If there is a /etc/*release file, it's probably a supported operating system, so we can
|
||||
if ls /etc/*release 1> /dev/null 2>&1; then
|
||||
@@ -581,7 +589,7 @@ disk_usage() {
|
||||
# Some lines of df might contain sensitive information like usernames and passwords.
|
||||
# E.g. curlftpfs filesystems (https://www.looklinux.com/mount-ftp-share-on-linux-using-curlftps/)
|
||||
# We are not interested in those lines so we collect keyword, to remove them from the output
|
||||
# Additinal keywords can be added, separated by "|"
|
||||
# Additional keywords can be added, separated by "|"
|
||||
hide="curlftpfs"
|
||||
|
||||
# only show those lines not containing a sensitive phrase
|
||||
@@ -659,15 +667,20 @@ ping_gateway() {
|
||||
local protocol="${1}"
|
||||
ping_ipv4_or_ipv6 "${protocol}"
|
||||
# Check if we are using IPv4 or IPv6
|
||||
# Find the default gateway using IPv4 or IPv6
|
||||
# Find the default gateways using IPv4 or IPv6
|
||||
local gateway
|
||||
gateway="$(ip -"${protocol}" route | grep default | grep "${PIHOLE_INTERFACE}" | cut -d ' ' -f 3)"
|
||||
|
||||
# If the gateway variable has a value (meaning a gateway was found),
|
||||
if [[ -n "${gateway}" ]]; then
|
||||
log_write "${INFO} Default IPv${protocol} gateway: ${gateway}"
|
||||
log_write "${INFO} Default IPv${protocol} gateway(s):"
|
||||
|
||||
while IFS= read -r gateway; do
|
||||
log_write " ${gateway}"
|
||||
done < <(ip -"${protocol}" route | grep default | grep "${PIHOLE_INTERFACE}" | cut -d ' ' -f 3)
|
||||
|
||||
gateway=$(ip -"${protocol}" route | grep default | grep "${PIHOLE_INTERFACE}" | cut -d ' ' -f 3 | head -n 1)
|
||||
# If there was at least one gateway
|
||||
if [ -n "${gateway}" ]; then
|
||||
# Let the user know we will ping the gateway for a response
|
||||
log_write " * Pinging ${gateway}..."
|
||||
log_write " * Pinging first gateway ${gateway}..."
|
||||
# Try to quietly ping the gateway 3 times, with a timeout of 3 seconds, using numeric output only,
|
||||
# on the pihole interface, and tail the last three lines of the output
|
||||
# If pinging the gateway is not successful,
|
||||
@@ -785,7 +798,7 @@ check_networking() {
|
||||
ping_gateway "6"
|
||||
# Skip the following check if installed in docker container. Unpriv'ed containers do not have access to the information required
|
||||
# to resolve the service name listening - and the container should not start if there was a port conflict anyway
|
||||
[ -z "${PIHOLE_DOCKER_TAG}" ] && check_required_ports
|
||||
[ -z "${DOCKER_VERSION}" ] && check_required_ports
|
||||
}
|
||||
|
||||
check_x_headers() {
|
||||
@@ -795,39 +808,24 @@ check_x_headers() {
|
||||
# Similarly, it will show "X-Pi-hole: The Pi-hole Web interface is working!" if you view the header returned
|
||||
# when accessing the dashboard (i.e curl -I pi.hole/admin/)
|
||||
# server is operating correctly
|
||||
echo_current_diagnostic "Dashboard and block page"
|
||||
echo_current_diagnostic "Dashboard headers"
|
||||
# Use curl -I to get the header and parse out just the X-Pi-hole one
|
||||
local block_page
|
||||
block_page=$(curl -Is localhost | awk '/X-Pi-hole/' | tr -d '\r')
|
||||
# Do it for the dashboard as well, as the header is different than above
|
||||
local full_curl_output_dashboard
|
||||
local dashboard
|
||||
dashboard=$(curl -Is localhost/admin/ | awk '/X-Pi-hole/' | tr -d '\r')
|
||||
full_curl_output_dashboard="$(curl -Is localhost/admin/)"
|
||||
dashboard=$(echo "${full_curl_output_dashboard}" | awk '/X-Pi-hole/' | tr -d '\r')
|
||||
# Store what the X-Header should be in variables for comparison later
|
||||
local block_page_working
|
||||
block_page_working="X-Pi-hole: A black hole for Internet advertisements."
|
||||
local dashboard_working
|
||||
dashboard_working="X-Pi-hole: The Pi-hole Web interface is working!"
|
||||
local full_curl_output_block_page
|
||||
full_curl_output_block_page="$(curl -Is localhost)"
|
||||
local full_curl_output_dashboard
|
||||
full_curl_output_dashboard="$(curl -Is localhost/admin/)"
|
||||
# If the X-header found by curl matches what is should be,
|
||||
if [[ $block_page == "$block_page_working" ]]; then
|
||||
# display a success message
|
||||
log_write "$TICK Block page X-Header: ${COL_GREEN}${block_page}${COL_NC}"
|
||||
else
|
||||
# Otherwise, show an error
|
||||
log_write "$CROSS Block page X-Header: ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
|
||||
log_write "${COL_RED}${full_curl_output_block_page}${COL_NC}"
|
||||
fi
|
||||
|
||||
# Same logic applies to the dashboard as above, if the X-Header matches what a working system should have,
|
||||
# If the X-Header matches what a working system should have,
|
||||
if [[ $dashboard == "$dashboard_working" ]]; then
|
||||
# then we can show a success
|
||||
log_write "$TICK Web interface X-Header: ${COL_GREEN}${dashboard}${COL_NC}"
|
||||
else
|
||||
# Otherwise, it's a failure since the X-Headers either don't exist or have been modified in some way
|
||||
log_write "$CROSS Web interface X-Header: ${COL_RED}X-Header does not match or could not be retrieved.${COL_NC}"
|
||||
|
||||
log_write "${COL_RED}${full_curl_output_dashboard}${COL_NC}"
|
||||
fi
|
||||
}
|
||||
@@ -945,10 +943,21 @@ process_status(){
|
||||
else
|
||||
# Otherwise, use the service command and mock the output of `systemctl is-active`
|
||||
local status_of_process
|
||||
if service "${i}" status | grep -E 'is\srunning' &> /dev/null; then
|
||||
status_of_process="active"
|
||||
|
||||
# If DOCKER_VERSION is set, the output is slightly different (s6 init system on Docker)
|
||||
if [ -n "${DOCKER_VERSION}" ]; then
|
||||
if service "${i}" status | grep -E '^up' &> /dev/null; then
|
||||
status_of_process="active"
|
||||
else
|
||||
status_of_process="inactive"
|
||||
fi
|
||||
else
|
||||
status_of_process="inactive"
|
||||
# non-Docker system
|
||||
if service "${i}" status | grep -E 'is\srunning' &> /dev/null; then
|
||||
status_of_process="active"
|
||||
else
|
||||
status_of_process="inactive"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# and print it out to the user
|
||||
@@ -974,6 +983,20 @@ ftl_full_status(){
|
||||
fi
|
||||
}
|
||||
|
||||
lighttpd_test_configuration(){
|
||||
# let lighttpd test it's own configuration
|
||||
local lighttpd_conf_test
|
||||
echo_current_diagnostic "Lighttpd configuration test"
|
||||
lighttpd_conf_test=$(lighttpd -tt -f /etc/lighttpd/lighttpd.conf)
|
||||
if [ -z "${lighttpd_conf_test}" ]; then
|
||||
# empty output
|
||||
log_write "${TICK} ${COL_GREEN}No error in lighttpd configuration${COL_NC}"
|
||||
else
|
||||
log_write "${CROSS} ${COL_RED}Error in lighttpd configuration${COL_NC}"
|
||||
log_write " ${lighttpd_conf_test}"
|
||||
fi
|
||||
}
|
||||
|
||||
make_array_from_file() {
|
||||
local filename="${1}"
|
||||
# The second argument can put a limit on how many line should be read from the file
|
||||
@@ -990,7 +1013,7 @@ make_array_from_file() {
|
||||
else
|
||||
# Otherwise, read the file line by line
|
||||
while IFS= read -r line;do
|
||||
# Othwerise, strip out comments and blank lines
|
||||
# Otherwise, strip out comments and blank lines
|
||||
new_line=$(echo "${line}" | sed -e 's/^\s*#.*$//' -e '/^$/d')
|
||||
# If the line still has content (a non-zero value)
|
||||
if [[ -n "${new_line}" ]]; then
|
||||
@@ -1048,7 +1071,7 @@ parse_file() {
|
||||
}
|
||||
|
||||
check_name_resolution() {
|
||||
# Check name resolution from localhost, Pi-hole's IP, and Google's name severs
|
||||
# Check name resolution from localhost, Pi-hole's IP, and Google's name servers
|
||||
# using the function we created earlier
|
||||
dig_at 4
|
||||
dig_at 6
|
||||
@@ -1066,10 +1089,13 @@ dir_check() {
|
||||
# check if exists first; if it does,
|
||||
if ls "${filename}" 1> /dev/null 2>&1; then
|
||||
# do nothing
|
||||
:
|
||||
true
|
||||
return
|
||||
else
|
||||
# Otherwise, show an error
|
||||
log_write "${COL_RED}${directory} does not exist.${COL_NC}"
|
||||
false
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1077,6 +1103,19 @@ dir_check() {
|
||||
list_files_in_dir() {
|
||||
# Set the first argument passed to this function as a named variable for better readability
|
||||
local dir_to_parse="${1}"
|
||||
|
||||
# show files and sizes of some directories, don't print the file content (yet)
|
||||
if [[ "${dir_to_parse}" == "${SHM_DIRECTORY}" ]]; then
|
||||
# SHM file - we do not want to see the content, but we want to see the files and their sizes
|
||||
log_write "$(ls -lh "${dir_to_parse}/")"
|
||||
elif [[ "${dir_to_parse}" == "${WEB_SERVER_CONFIG_DIRECTORY_FEDORA}" ]]; then
|
||||
# we want to see all files files in /etc/lighttpd/conf.d
|
||||
log_write "$(ls -lh "${dir_to_parse}/" 2> /dev/null )"
|
||||
elif [[ "${dir_to_parse}" == "${WEB_SERVER_CONFIG_DIRECTORY_DEBIAN}" ]]; then
|
||||
# we want to see all files files in /etc/lighttpd/conf.d
|
||||
log_write "$(ls -lh "${dir_to_parse}/"/ 2> /dev/null )"
|
||||
fi
|
||||
|
||||
# Store the files found in an array
|
||||
mapfile -t files_found < <(ls "${dir_to_parse}")
|
||||
# For each file in the array,
|
||||
@@ -1092,11 +1131,8 @@ list_files_in_dir() {
|
||||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_WEB_SERVER_ACCESS_LOG_FILE}" ]] || \
|
||||
[[ "${dir_to_parse}/${each_file}" == "${PIHOLE_LOG_GZIPS}" ]]; then
|
||||
:
|
||||
elif [[ "${dir_to_parse}" == "${SHM_DIRECTORY}" ]]; then
|
||||
# SHM file - we do not want to see the content, but we want to see the files and their sizes
|
||||
log_write "$(ls -lhd "${dir_to_parse}"/"${each_file}")"
|
||||
elif [[ "${dir_to_parse}" == "${DNSMASQ_D_DIRECTORY}" ]]; then
|
||||
# in case of the dnsmasq directory inlcuede all files in the debug output
|
||||
# in case of the dnsmasq directory include all files in the debug output
|
||||
log_write "\\n${COL_GREEN}$(ls -lhd "${dir_to_parse}"/"${each_file}")${COL_NC}"
|
||||
make_array_from_file "${dir_to_parse}/${each_file}"
|
||||
else
|
||||
@@ -1129,9 +1165,10 @@ show_content_of_files_in_dir() {
|
||||
# Set a local variable for better readability
|
||||
local directory="${1}"
|
||||
# Check if the directory exists
|
||||
dir_check "${directory}"
|
||||
# if it does, list the files in it
|
||||
list_files_in_dir "${directory}"
|
||||
if dir_check "${directory}"; then
|
||||
# if it does, list the files in it
|
||||
list_files_in_dir "${directory}"
|
||||
fi
|
||||
}
|
||||
|
||||
show_content_of_pihole_files() {
|
||||
@@ -1139,6 +1176,8 @@ show_content_of_pihole_files() {
|
||||
show_content_of_files_in_dir "${PIHOLE_DIRECTORY}"
|
||||
show_content_of_files_in_dir "${DNSMASQ_D_DIRECTORY}"
|
||||
show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY}"
|
||||
show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY_FEDORA}"
|
||||
show_content_of_files_in_dir "${WEB_SERVER_CONFIG_DIRECTORY_DEBIAN}"
|
||||
show_content_of_files_in_dir "${CRON_D_DIRECTORY}"
|
||||
show_content_of_files_in_dir "${WEB_SERVER_LOG_DIRECTORY}"
|
||||
show_content_of_files_in_dir "${LOG_DIRECTORY}"
|
||||
@@ -1230,7 +1269,7 @@ check_dhcp_servers() {
|
||||
OLD_IFS="$IFS"
|
||||
IFS=$'\n'
|
||||
local entries=()
|
||||
mapfile -t entries < <(pihole-FTL dhcp-discover)
|
||||
mapfile -t entries < <(pihole-FTL dhcp-discover & spinner)
|
||||
|
||||
for line in "${entries[@]}"; do
|
||||
log_write " ${line}"
|
||||
@@ -1259,12 +1298,21 @@ show_messages() {
|
||||
show_FTL_db_entries "Pi-hole diagnosis messages" "SELECT count (message) as count, datetime(max(timestamp),'unixepoch','localtime') as 'last timestamp', type, message, blob1, blob2, blob3, blob4, blob5 FROM message GROUP BY type, message, blob1, blob2, blob3, blob4, blob5;" "6 19 20 60 20 20 20 20 20"
|
||||
}
|
||||
|
||||
database_permissions() {
|
||||
local permissions
|
||||
permissions=$(ls -lhd "${1}")
|
||||
log_write "${COL_GREEN}${permissions}${COL_NC}"
|
||||
}
|
||||
|
||||
analyze_gravity_list() {
|
||||
echo_current_diagnostic "Gravity Database"
|
||||
|
||||
local gravity_permissions
|
||||
gravity_permissions=$(ls -lhd "${PIHOLE_GRAVITY_DB_FILE}")
|
||||
log_write "${COL_GREEN}${gravity_permissions}${COL_NC}"
|
||||
database_permissions "${PIHOLE_GRAVITY_DB_FILE}"
|
||||
|
||||
# if users want to check database integrity
|
||||
if [[ "${CHECK_DATABASE}" = true ]]; then
|
||||
database_integrity_check "${PIHOLE_GRAVITY_DB_FILE}"
|
||||
fi
|
||||
|
||||
show_db_entries "Info table" "SELECT property,value FROM info" "20 40"
|
||||
gravity_updated_raw="$(pihole-FTL sqlite3 "${PIHOLE_GRAVITY_DB_FILE}" "SELECT value FROM info where property = 'updated'")"
|
||||
@@ -1286,49 +1334,87 @@ analyze_gravity_list() {
|
||||
IFS="$OLD_IFS"
|
||||
}
|
||||
|
||||
obfuscated_pihole_log() {
|
||||
local pihole_log=("$@")
|
||||
local line
|
||||
local error_to_check_for
|
||||
local line_to_obfuscate
|
||||
local obfuscated_line
|
||||
for line in "${pihole_log[@]}"; do
|
||||
# A common error in the pihole.log is when there is a non-hosts formatted file
|
||||
# that the DNS server is attempting to read. Since it's not formatted
|
||||
# correctly, there will be an entry for "bad address at line n"
|
||||
# So we can check for that here and highlight it in red so the user can see it easily
|
||||
error_to_check_for=$(echo "${line}" | grep 'bad address at')
|
||||
# Some users may not want to have the domains they visit sent to us
|
||||
# To that end, we check for lines in the log that would contain a domain name
|
||||
line_to_obfuscate=$(echo "${line}" | grep ': query\|: forwarded\|: reply')
|
||||
# If the variable contains a value, it found an error in the log
|
||||
if [[ -n ${error_to_check_for} ]]; then
|
||||
# So we can print it in red to make it visible to the user
|
||||
log_write " ${CROSS} ${COL_RED}${line}${COL_NC} (${FAQ_BAD_ADDRESS})"
|
||||
analyze_ftl_db() {
|
||||
echo_current_diagnostic "Pi-hole FTL Query Database"
|
||||
database_permissions "${PIHOLE_FTL_DB_FILE}"
|
||||
# if users want to check database integrity
|
||||
if [[ "${CHECK_DATABASE}" = true ]]; then
|
||||
database_integrity_check "${PIHOLE_FTL_DB_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
database_integrity_check(){
|
||||
local result
|
||||
local database="${1}"
|
||||
|
||||
log_write "${INFO} Checking integrity of ${database} ... (this can take several minutes)"
|
||||
result="$(pihole-FTL "${database}" "PRAGMA integrity_check" 2>&1 & spinner)"
|
||||
if [[ ${result} = "ok" ]]; then
|
||||
log_write "${TICK} Integrity of ${database} intact"
|
||||
|
||||
|
||||
log_write "${INFO} Checking foreign key constraints of ${database} ... (this can take several minutes)"
|
||||
unset result
|
||||
result="$(pihole-FTL sqlite3 "${database}" -cmd ".headers on" -cmd ".mode column" "PRAGMA foreign_key_check" 2>&1 & spinner)"
|
||||
if [[ -z ${result} ]]; then
|
||||
log_write "${TICK} No foreign key errors in ${database}"
|
||||
else
|
||||
# If the variable does not a value (the current default behavior), so do not obfuscate anything
|
||||
if [[ -z ${OBFUSCATE} ]]; then
|
||||
log_write " ${line}"
|
||||
# Othwerise, a flag was passed to this command to obfuscate domains in the log
|
||||
else
|
||||
# So first check if there are domains in the log that should be obfuscated
|
||||
if [[ -n ${line_to_obfuscate} ]]; then
|
||||
# If there are, we need to use awk to replace only the domain name (the 6th field in the log)
|
||||
# so we substitute the domain for the placeholder value
|
||||
obfuscated_line=$(echo "${line_to_obfuscate}" | awk -v placeholder="${OBFUSCATED_PLACEHOLDER}" '{sub($6,placeholder); print $0}')
|
||||
log_write " ${obfuscated_line}"
|
||||
else
|
||||
log_write " ${line}"
|
||||
fi
|
||||
fi
|
||||
log_write "${CROSS} ${COL_RED}Foreign key errors in ${database} found.${COL_NC}"
|
||||
while IFS= read -r line ; do
|
||||
log_write " $line"
|
||||
done <<< "$result"
|
||||
fi
|
||||
done
|
||||
|
||||
else
|
||||
log_write "${CROSS} ${COL_RED}Integrity errors in ${database} found.\n${COL_NC}"
|
||||
while IFS= read -r line ; do
|
||||
log_write " $line"
|
||||
done <<< "$result"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# Show a text spinner during a long process run
|
||||
spinner(){
|
||||
# Show the spinner only if there is a tty
|
||||
if tty -s; then
|
||||
# PID of the most recent background process
|
||||
_PID=$!
|
||||
_spin="/-\|"
|
||||
_start=0
|
||||
_elapsed=0
|
||||
_i=1
|
||||
|
||||
# Start the counter
|
||||
_start=$(date +%s)
|
||||
|
||||
# Hide the cursor
|
||||
tput civis > /dev/tty
|
||||
|
||||
# ensures cursor is visible again, in case of premature exit
|
||||
trap 'tput cnorm > /dev/tty' EXIT
|
||||
|
||||
while [ -d /proc/$_PID ]; do
|
||||
_elapsed=$(( $(date +%s) - _start ))
|
||||
# use hours only if needed
|
||||
if [ "$_elapsed" -lt 3600 ]; then
|
||||
printf "\r${_spin:_i++%${#_spin}:1} %02d:%02d" $((_elapsed/60)) $((_elapsed%60)) >"$(tty)"
|
||||
else
|
||||
printf "\r${_spin:_i++%${#_spin}:1} %02d:%02d:%02d" $((_elapsed/3600)) $(((_elapsed/60)%60)) $((_elapsed%60)) >"$(tty)"
|
||||
fi
|
||||
sleep 0.25
|
||||
done
|
||||
|
||||
# Return to the begin of the line after completion (the spinner will be overwritten)
|
||||
printf "\r" >"$(tty)"
|
||||
|
||||
# Restore cursor visibility
|
||||
tput cnorm > /dev/tty
|
||||
fi
|
||||
}
|
||||
|
||||
analyze_pihole_log() {
|
||||
echo_current_diagnostic "Pi-hole log"
|
||||
local pihole_log_head=()
|
||||
local pihole_log_tail=()
|
||||
local pihole_log_permissions
|
||||
local logging_enabled
|
||||
|
||||
@@ -1338,22 +1424,10 @@ analyze_pihole_log() {
|
||||
log_write "${INFO} Query logging is disabled"
|
||||
log_write ""
|
||||
fi
|
||||
# Put the current Internal Field Separator into another variable so it can be restored later
|
||||
OLD_IFS="$IFS"
|
||||
# Get the lines that are in the file(s) and store them in an array for parsing later
|
||||
IFS=$'\r\n'
|
||||
|
||||
pihole_log_permissions=$(ls -lhd "${PIHOLE_LOG}")
|
||||
log_write "${COL_GREEN}${pihole_log_permissions}${COL_NC}"
|
||||
mapfile -t pihole_log_head < <(head -n 20 ${PIHOLE_LOG})
|
||||
log_write " ${COL_CYAN}-----head of $(basename ${PIHOLE_LOG})------${COL_NC}"
|
||||
obfuscated_pihole_log "${pihole_log_head[@]}"
|
||||
log_write ""
|
||||
mapfile -t pihole_log_tail < <(tail -n 20 ${PIHOLE_LOG})
|
||||
log_write " ${COL_CYAN}-----tail of $(basename ${PIHOLE_LOG})------${COL_NC}"
|
||||
obfuscated_pihole_log "${pihole_log_tail[@]}"
|
||||
log_write ""
|
||||
# Set the IFS back to what it was
|
||||
IFS="$OLD_IFS"
|
||||
head_tail_log "${PIHOLE_LOG}" 20
|
||||
}
|
||||
|
||||
curl_to_tricorder() {
|
||||
@@ -1431,7 +1505,7 @@ upload_to_tricorder() {
|
||||
if [[ "${WEBCALL}" ]] && [[ ! "${AUTOMATED}" ]]; then
|
||||
:
|
||||
else
|
||||
log_write "${CROSS} ${COL_RED}There was an error uploading your debug log.${COL_NC}"
|
||||
log_write "${CROSS} ${COL_RED}There was an error uploading your debug log.${COL_NC}"
|
||||
log_write " * Please try again or contact the Pi-hole team for assistance."
|
||||
fi
|
||||
fi
|
||||
@@ -1458,8 +1532,10 @@ check_name_resolution
|
||||
check_dhcp_servers
|
||||
process_status
|
||||
ftl_full_status
|
||||
lighttpd_test_configuration
|
||||
parse_setup_vars
|
||||
check_x_headers
|
||||
analyze_ftl_db
|
||||
analyze_gravity_list
|
||||
show_groups
|
||||
show_domainlist
|
||||
|
||||
@@ -16,7 +16,6 @@ GRAVITYDB="${piholeDir}/gravity.db"
|
||||
options="$*"
|
||||
all=""
|
||||
exact=""
|
||||
blockpage=""
|
||||
matchType="match"
|
||||
# Source pihole-FTL from install script
|
||||
pihole_FTL="${piholeDir}/pihole-FTL.conf"
|
||||
@@ -31,33 +30,6 @@ gravityDBfile="${GRAVITYDB}"
|
||||
colfile="/opt/pihole/COL_TABLE"
|
||||
source "${colfile}"
|
||||
|
||||
# Scan an array of files for matching strings
|
||||
scanList(){
|
||||
# Escape full stops
|
||||
local domain="${1}" esc_domain="${1//./\\.}" lists="${2}" type="${3:-}"
|
||||
|
||||
# Prevent grep from printing file path
|
||||
cd "$piholeDir" || exit 1
|
||||
|
||||
# Prevent grep -i matching slowly: https://bit.ly/2xFXtUX
|
||||
export LC_CTYPE=C
|
||||
|
||||
# /dev/null forces filename to be printed when only one list has been generated
|
||||
case "${type}" in
|
||||
"exact" ) grep -i -E -l "(^|(?<!#)\\s)${esc_domain}($|\\s|#)" ${lists} /dev/null 2>/dev/null;;
|
||||
# Iterate through each regexp and check whether it matches the domainQuery
|
||||
# If it does, print the matching regexp and continue looping
|
||||
# Input 1 - regexps | Input 2 - domainQuery
|
||||
"regex" )
|
||||
for list in ${lists}; do
|
||||
if [[ "${domain}" =~ ${list} ]]; then
|
||||
printf "%b\n" "${list}";
|
||||
fi
|
||||
done;;
|
||||
* ) grep -i "${esc_domain}" ${lists} /dev/null 2>/dev/null;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ "${options}" == "-h" ]] || [[ "${options}" == "--help" ]]; then
|
||||
echo "Usage: pihole -q [option] <domain>
|
||||
Example: 'pihole -q -exact domain.com'
|
||||
@@ -71,57 +43,108 @@ Options:
|
||||
fi
|
||||
|
||||
# Handle valid options
|
||||
if [[ "${options}" == *"-bp"* ]]; then
|
||||
exact="exact"; blockpage=true
|
||||
else
|
||||
[[ "${options}" == *"-all"* ]] && all=true
|
||||
if [[ "${options}" == *"-exact"* ]]; then
|
||||
exact="exact"; matchType="exact ${matchType}"
|
||||
fi
|
||||
[[ "${options}" == *"-all"* ]] && all=true
|
||||
if [[ "${options}" == *"-exact"* ]]; then
|
||||
exact="exact"; matchType="exact ${matchType}"
|
||||
fi
|
||||
|
||||
# Strip valid options, leaving only the domain and invalid options
|
||||
# This allows users to place the options before or after the domain
|
||||
options=$(sed -E 's/ ?-(bp|adlists?|all|exact) ?//g' <<< "${options}")
|
||||
options=$(sed -E 's/ ?-(all|exact) ?//g' <<< "${options}")
|
||||
|
||||
# Handle remaining options
|
||||
# If $options contain non ASCII characters, convert to punycode
|
||||
case "${options}" in
|
||||
"" ) str="No domain specified";;
|
||||
*" "* ) str="Unknown query option specified";;
|
||||
*[![:ascii:]]* ) domainQuery=$(idn2 "${options}");;
|
||||
* ) domainQuery="${options}";;
|
||||
*[![:ascii:]]* ) rawDomainQuery=$(idn2 "${options}");;
|
||||
* ) rawDomainQuery="${options}";;
|
||||
esac
|
||||
|
||||
# convert the domain to lowercase
|
||||
domainQuery=$(echo "${rawDomainQuery}" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
if [[ -n "${str:-}" ]]; then
|
||||
echo -e "${str}${COL_NC}\\nTry 'pihole -q --help' for more information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Scan an array of files for matching strings
|
||||
scanList(){
|
||||
# Escape full stops
|
||||
local domain="${1}" esc_domain="${1//./\\.}" lists="${2}" list_type="${3:-}"
|
||||
|
||||
# Prevent grep from printing file path
|
||||
cd "$piholeDir" || exit 1
|
||||
|
||||
# Prevent grep -i matching slowly: https://bit.ly/2xFXtUX
|
||||
export LC_CTYPE=C
|
||||
|
||||
# /dev/null forces filename to be printed when only one list has been generated
|
||||
case "${list_type}" in
|
||||
"exact" ) grep -i -E -l "(^|(?<!#)\\s)${esc_domain}($|\\s|#)" "${lists}" /dev/null 2>/dev/null;;
|
||||
# Iterate through each regexp and check whether it matches the domainQuery
|
||||
# If it does, print the matching regexp and continue looping
|
||||
# Input 1 - regexps | Input 2 - domainQuery
|
||||
"regex" )
|
||||
for list in ${lists}; do
|
||||
if [[ "${domain}" =~ ${list} ]]; then
|
||||
printf "%b\n" "${list}";
|
||||
fi
|
||||
done;;
|
||||
* ) grep -i "${esc_domain}" "${lists}" /dev/null 2>/dev/null;;
|
||||
esac
|
||||
}
|
||||
|
||||
scanDatabaseTable() {
|
||||
local domain table type querystr result extra
|
||||
local domain table list_type querystr result extra abpquerystr abpfound abpentry searchstr
|
||||
domain="$(printf "%q" "${1}")"
|
||||
table="${2}"
|
||||
type="${3:-}"
|
||||
list_type="${3:-}"
|
||||
|
||||
# As underscores are legitimate parts of domains, we escape them when using the LIKE operator.
|
||||
# Underscores are SQLite wildcards matching exactly one character. We obviously want to suppress this
|
||||
# behavior. The "ESCAPE '\'" clause specifies that an underscore preceded by an '\' should be matched
|
||||
# as a literal underscore character. We pretreat the $domain variable accordingly to escape underscores.
|
||||
if [[ "${table}" == "gravity" ]]; then
|
||||
|
||||
# Are there ABP entries on gravity?
|
||||
# Return 1 if abp_domain=1 or Zero if abp_domain=0 or not set
|
||||
abpquerystr="SELECT EXISTS (SELECT 1 FROM info WHERE property='abp_domains' and value='1')"
|
||||
abpfound="$(pihole-FTL sqlite3 "${gravityDBfile}" "${abpquerystr}")" 2> /dev/null
|
||||
|
||||
# Create search string for ABP entries only if needed
|
||||
if [ "${abpfound}" -eq 1 ]; then
|
||||
abpentry="${domain}"
|
||||
|
||||
searchstr="'||${abpentry}^'"
|
||||
|
||||
# While a dot is found ...
|
||||
while [ "${abpentry}" != "${abpentry/./}" ]
|
||||
do
|
||||
# ... remove text before the dot (including the dot) and append the result to $searchstr
|
||||
abpentry=$(echo "${abpentry}" | cut -f 2- -d '.')
|
||||
searchstr="$searchstr, '||${abpentry}^'"
|
||||
done
|
||||
|
||||
# The final search string will look like:
|
||||
# "domain IN ('||sub2.sub1.domain.com^', '||sub1.domain.com^', '||domain.com^', '||com^') OR"
|
||||
searchstr="domain IN (${searchstr}) OR "
|
||||
fi
|
||||
|
||||
case "${exact}" in
|
||||
"exact" ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain = '${domain}'";;
|
||||
* ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
* ) querystr="SELECT gravity.domain,adlist.address,adlist.enabled FROM gravity LEFT JOIN adlist ON adlist.id = gravity.adlist_id WHERE ${searchstr} domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
esac
|
||||
else
|
||||
case "${exact}" in
|
||||
"exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain = '${domain}'";;
|
||||
* ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
"exact" ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${list_type}' AND domain = '${domain}'";;
|
||||
* ) querystr="SELECT domain,enabled FROM domainlist WHERE type = '${list_type}' AND domain LIKE '%${domain//_/\\_}%' ESCAPE '\\'";;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Send prepared query to gravity database
|
||||
result="$(pihole-FTL sqlite3 "${gravityDBfile}" "${querystr}")" 2> /dev/null
|
||||
result="$(pihole-FTL sqlite3 -separator ',' "${gravityDBfile}" "${querystr}")" 2> /dev/null
|
||||
if [[ -z "${result}" ]]; then
|
||||
# Return early when there are no matches in this table
|
||||
return
|
||||
@@ -136,19 +159,13 @@ scanDatabaseTable() {
|
||||
wbMatch=true
|
||||
|
||||
# Print table name
|
||||
if [[ -z "${blockpage}" ]]; then
|
||||
echo " ${matchType^} found in ${COL_BOLD}exact ${table}${COL_NC}"
|
||||
fi
|
||||
echo " ${matchType^} found in ${COL_BOLD}exact ${table}${COL_NC}"
|
||||
|
||||
# Loop over results and print them
|
||||
mapfile -t results <<< "${result}"
|
||||
for result in "${results[@]}"; do
|
||||
if [[ -n "${blockpage}" ]]; then
|
||||
echo "π ${result}"
|
||||
exit 0
|
||||
fi
|
||||
domain="${result/|*}"
|
||||
if [[ "${result#*|}" == "0" ]]; then
|
||||
domain="${result/,*}"
|
||||
if [[ "${result#*,}" == "0" ]]; then
|
||||
extra=" (disabled)"
|
||||
else
|
||||
extra=""
|
||||
@@ -158,13 +175,13 @@ scanDatabaseTable() {
|
||||
}
|
||||
|
||||
scanRegexDatabaseTable() {
|
||||
local domain list
|
||||
local domain list list_type
|
||||
domain="${1}"
|
||||
list="${2}"
|
||||
type="${3:-}"
|
||||
list_type="${3:-}"
|
||||
|
||||
# Query all regex from the corresponding database tables
|
||||
mapfile -t regexList < <(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT domain FROM domainlist WHERE type = ${type}" 2> /dev/null)
|
||||
mapfile -t regexList < <(pihole-FTL sqlite3 "${gravityDBfile}" "SELECT domain FROM domainlist WHERE type = ${list_type}" 2> /dev/null)
|
||||
|
||||
# If we have regexps to process
|
||||
if [[ "${#regexList[@]}" -ne 0 ]]; then
|
||||
@@ -181,18 +198,13 @@ scanRegexDatabaseTable() {
|
||||
# Form a "results" message
|
||||
str_result="${COL_BOLD}${str_regexMatches}${COL_NC}"
|
||||
# If we are displaying more than just the source of the block
|
||||
if [[ -z "${blockpage}" ]]; then
|
||||
# Set the wildcard match flag
|
||||
wcMatch=true
|
||||
# Echo the "matched" message, indented by one space
|
||||
echo " ${str_message}"
|
||||
# Echo the "results" message, each line indented by three spaces
|
||||
# shellcheck disable=SC2001
|
||||
echo "${str_result}" | sed 's/^/ /'
|
||||
else
|
||||
echo "π .wildcard"
|
||||
exit 0
|
||||
fi
|
||||
# Set the wildcard match flag
|
||||
wcMatch=true
|
||||
# Echo the "matched" message, indented by one space
|
||||
echo " ${str_message}"
|
||||
# Echo the "results" message, each line indented by three spaces
|
||||
# shellcheck disable=SC2001
|
||||
echo "${str_result}" | sed 's/^/ /'
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -222,25 +234,23 @@ elif [[ -z "${all}" ]] && [[ "${#results[*]}" -ge 100 ]]; then
|
||||
fi
|
||||
|
||||
# Print "Exact matches for" title
|
||||
if [[ -n "${exact}" ]] && [[ -z "${blockpage}" ]]; then
|
||||
if [[ -n "${exact}" ]]; then
|
||||
plural=""; [[ "${#results[*]}" -gt 1 ]] && plural="es"
|
||||
echo " ${matchType^}${plural} for ${COL_BOLD}${domainQuery}${COL_NC} found in:"
|
||||
fi
|
||||
|
||||
for result in "${results[@]}"; do
|
||||
match="${result/|*/}"
|
||||
extra="${result#*|}"
|
||||
adlistAddress="${extra/|*/}"
|
||||
extra="${extra#*|}"
|
||||
match="${result/,*/}"
|
||||
extra="${result#*,}"
|
||||
adlistAddress="${extra/,*/}"
|
||||
extra="${extra#*,}"
|
||||
if [[ "${extra}" == "0" ]]; then
|
||||
extra=" (disabled)"
|
||||
else
|
||||
extra=""
|
||||
fi
|
||||
|
||||
if [[ -n "${blockpage}" ]]; then
|
||||
echo "0 ${adlistAddress}"
|
||||
elif [[ -n "${exact}" ]]; then
|
||||
if [[ -n "${exact}" ]]; then
|
||||
echo " - ${adlistAddress}${extra}"
|
||||
else
|
||||
if [[ ! "${adlistAddress}" == "${adlistAddress_prev:-}" ]]; then
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
#
|
||||
# Automatically configures the Pi to use the 2.8 LCD screen to display stats on it (also works over ssh)
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
|
||||
|
||||
############ FUNCTIONS ###########
|
||||
|
||||
# Borrowed from adafruit-pitft-helper < borrowed from raspi-config
|
||||
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L324-L334
|
||||
getInitSys() {
|
||||
if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then
|
||||
SYSTEMD=1
|
||||
elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then
|
||||
SYSTEMD=0
|
||||
else
|
||||
echo "Unrecognized init system"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Borrowed from adafruit-pitft-helper:
|
||||
# https://github.com/adafruit/Adafruit-PiTFT-Helper/blob/master/adafruit-pitft-helper#L274-L285
|
||||
autoLoginPiToConsole() {
|
||||
if [ -e /etc/init.d/lightdm ]; then
|
||||
if [ ${SYSTEMD} -eq 1 ]; then
|
||||
systemctl set-default multi-user.target
|
||||
ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service
|
||||
else
|
||||
update-rc.d lightdm disable 2
|
||||
sed /etc/inittab -i -e "s/1:2345:respawn:\/sbin\/getty --noclear 38400 tty1/1:2345:respawn:\/bin\/login -f pi tty1 <\/dev\/tty1 >\/dev\/tty1 2>&1/"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
######### SCRIPT ###########
|
||||
# Set pi to log in automatically
|
||||
getInitSys
|
||||
autoLoginPiToConsole
|
||||
|
||||
# Set chronomter to run automatically when pi logs in
|
||||
echo /usr/local/bin/chronometer.sh >> /home/pi/.bashrc
|
||||
# OR
|
||||
#$SUDO echo /usr/local/bin/chronometer.sh >> /etc/profile
|
||||
|
||||
# Set up the LCD screen based on Adafruits instuctions:
|
||||
# https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/easy-install
|
||||
curl -SLs https://apt.adafruit.com/add-pin | bash
|
||||
apt-get -y install raspberrypi-bootloader
|
||||
apt-get -y install adafruit-pitft-helper
|
||||
adafruit-pitft-helper -t 28r
|
||||
|
||||
# Download the cmdline.txt file that prevents the screen from going blank after a period of time
|
||||
mv /boot/cmdline.txt /boot/cmdline.orig
|
||||
curl -o /boot/cmdline.txt https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/cmdline.txt
|
||||
|
||||
# Back up the original file and download the new one
|
||||
mv /etc/default/console-setup /etc/default/console-setup.orig
|
||||
curl -o /etc/default/console-setup https://raw.githubusercontent.com/pi-hole/pi-hole/master/advanced/console-setup
|
||||
|
||||
# Instantly apply the font change to the LCD screen
|
||||
setupcon
|
||||
|
||||
reboot
|
||||
|
||||
# Start showing the stats on the screen by running the command on another tty:
|
||||
# https://unix.stackexchange.com/questions/170063/start-a-process-on-a-different-tty
|
||||
#setsid sh -c 'exec /usr/local/bin/chronometer.sh <> /dev/tty1 >&0 2>&1'
|
||||
@@ -17,7 +17,7 @@ readonly PI_HOLE_GIT_URL="https://github.com/pi-hole/pi-hole.git"
|
||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
PH_TEST=true
|
||||
SKIP_INSTALL=true
|
||||
|
||||
# when --check-only is passed to this script, it will not perform the actual update
|
||||
CHECK_ONLY=false
|
||||
@@ -216,9 +216,8 @@ main() {
|
||||
fi
|
||||
|
||||
if [[ "${FTL_update}" == true || "${core_update}" == true || "${web_update}" == true ]]; then
|
||||
# Force an update of the updatechecker
|
||||
# Update local and remote versions via updatechecker
|
||||
/opt/pihole/updatecheck.sh
|
||||
/opt/pihole/updatecheck.sh x remote
|
||||
echo -e " ${INFO} Local version file information updated."
|
||||
fi
|
||||
|
||||
|
||||
@@ -8,23 +8,6 @@
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
# Credit: https://stackoverflow.com/a/46324904
|
||||
function json_extract() {
|
||||
local key=$1
|
||||
local json=$2
|
||||
|
||||
local string_regex='"([^"\]|\\.)*"'
|
||||
local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
|
||||
local value_regex="${string_regex}|${number_regex}|true|false|null"
|
||||
local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"
|
||||
|
||||
if [[ ${json} =~ ${pair_regex} ]]; then
|
||||
echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function get_local_branch() {
|
||||
# Return active branch
|
||||
cd "${1}" 2> /dev/null || return 1
|
||||
@@ -32,63 +15,119 @@ function get_local_branch() {
|
||||
}
|
||||
|
||||
function get_local_version() {
|
||||
# Return active branch
|
||||
# Return active version
|
||||
cd "${1}" 2> /dev/null || return 1
|
||||
git describe --long --dirty --tags 2> /dev/null || return 1
|
||||
git describe --tags --always 2> /dev/null || return 1
|
||||
}
|
||||
|
||||
function get_local_hash() {
|
||||
cd "${1}" 2> /dev/null || return 1
|
||||
git rev-parse --short=8 HEAD || return 1
|
||||
}
|
||||
|
||||
function get_remote_version() {
|
||||
curl -s "https://api.github.com/repos/pi-hole/${1}/releases/latest" 2> /dev/null | jq --raw-output .tag_name || return 1
|
||||
}
|
||||
|
||||
|
||||
function get_remote_hash(){
|
||||
git ls-remote "https://github.com/pi-hole/${1}" --tags "${2}" | awk '{print substr($0, 0,8);}' || return 1
|
||||
}
|
||||
|
||||
# Source the setupvars config file
|
||||
# shellcheck disable=SC1091
|
||||
. /etc/pihole/setupVars.conf
|
||||
|
||||
if [[ "$2" == "remote" ]]; then
|
||||
# Source the utils file for addOrEditKeyValPair()
|
||||
# shellcheck disable=SC1091
|
||||
. /opt/pihole/utils.sh
|
||||
|
||||
if [[ "$3" == "reboot" ]]; then
|
||||
# Remove the below three legacy files if they exist
|
||||
rm -f "/etc/pihole/GitHubVersions"
|
||||
rm -f "/etc/pihole/localbranches"
|
||||
rm -f "/etc/pihole/localversions"
|
||||
|
||||
# Create new versions file if it does not exist
|
||||
VERSION_FILE="/etc/pihole/versions"
|
||||
touch "${VERSION_FILE}"
|
||||
chmod 644 "${VERSION_FILE}"
|
||||
|
||||
# if /pihole.docker.tag file exists, we will use it's value later in this script
|
||||
DOCKER_TAG=$(cat /pihole.docker.tag 2>/dev/null)
|
||||
regex='^([0-9]+\.){1,2}(\*|[0-9]+)(-.*)?$|(^nightly$)|(^dev.*$)'
|
||||
if [[ ! "${DOCKER_TAG}" =~ $regex ]]; then
|
||||
# DOCKER_TAG does not match the pattern (see https://regex101.com/r/RsENuz/1), so unset it.
|
||||
unset DOCKER_TAG
|
||||
fi
|
||||
|
||||
# used in cronjob
|
||||
if [[ "$1" == "reboot" ]]; then
|
||||
sleep 30
|
||||
fi
|
||||
fi
|
||||
|
||||
GITHUB_VERSION_FILE="/etc/pihole/GitHubVersions"
|
||||
|
||||
GITHUB_CORE_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/pi-hole/releases/latest' 2> /dev/null)")"
|
||||
echo -n "${GITHUB_CORE_VERSION}" > "${GITHUB_VERSION_FILE}"
|
||||
chmod 644 "${GITHUB_VERSION_FILE}"
|
||||
# get Core versions
|
||||
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||
GITHUB_WEB_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/AdminLTE/releases/latest' 2> /dev/null)")"
|
||||
echo -n " ${GITHUB_WEB_VERSION}" >> "${GITHUB_VERSION_FILE}"
|
||||
fi
|
||||
CORE_VERSION="$(get_local_version /etc/.pihole)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "CORE_VERSION" "${CORE_VERSION}"
|
||||
|
||||
GITHUB_FTL_VERSION="$(json_extract tag_name "$(curl -s 'https://api.github.com/repos/pi-hole/FTL/releases/latest' 2> /dev/null)")"
|
||||
echo -n " ${GITHUB_FTL_VERSION}" >> "${GITHUB_VERSION_FILE}"
|
||||
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "CORE_BRANCH" "${CORE_BRANCH}"
|
||||
|
||||
else
|
||||
CORE_HASH="$(get_local_hash /etc/.pihole)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "CORE_HASH" "${CORE_HASH}"
|
||||
|
||||
LOCAL_BRANCH_FILE="/etc/pihole/localbranches"
|
||||
GITHUB_CORE_VERSION="$(get_remote_version pi-hole)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_CORE_VERSION" "${GITHUB_CORE_VERSION}"
|
||||
|
||||
CORE_BRANCH="$(get_local_branch /etc/.pihole)"
|
||||
echo -n "${CORE_BRANCH}" > "${LOCAL_BRANCH_FILE}"
|
||||
chmod 644 "${LOCAL_BRANCH_FILE}"
|
||||
GITHUB_CORE_HASH="$(get_remote_hash pi-hole "${CORE_BRANCH}")"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_CORE_HASH" "${GITHUB_CORE_HASH}"
|
||||
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||
WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
|
||||
echo -n " ${WEB_BRANCH}" >> "${LOCAL_BRANCH_FILE}"
|
||||
fi
|
||||
|
||||
FTL_BRANCH="$(pihole-FTL branch)"
|
||||
echo -n " ${FTL_BRANCH}" >> "${LOCAL_BRANCH_FILE}"
|
||||
# get Web versions
|
||||
|
||||
LOCAL_VERSION_FILE="/etc/pihole/localversions"
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||
|
||||
CORE_VERSION="$(get_local_version /etc/.pihole)"
|
||||
echo -n "${CORE_VERSION}" > "${LOCAL_VERSION_FILE}"
|
||||
chmod 644 "${LOCAL_VERSION_FILE}"
|
||||
WEB_VERSION="$(get_local_version /var/www/html/admin)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "WEB_VERSION" "${WEB_VERSION}"
|
||||
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||
WEB_VERSION="$(get_local_version /var/www/html/admin)"
|
||||
echo -n " ${WEB_VERSION}" >> "${LOCAL_VERSION_FILE}"
|
||||
fi
|
||||
WEB_BRANCH="$(get_local_branch /var/www/html/admin)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "WEB_BRANCH" "${WEB_BRANCH}"
|
||||
|
||||
FTL_VERSION="$(pihole-FTL version)"
|
||||
echo -n " ${FTL_VERSION}" >> "${LOCAL_VERSION_FILE}"
|
||||
WEB_HASH="$(get_local_hash /var/www/html/admin)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "WEB_HASH" "${WEB_HASH}"
|
||||
|
||||
GITHUB_WEB_VERSION="$(get_remote_version AdminLTE)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_WEB_VERSION" "${GITHUB_WEB_VERSION}"
|
||||
|
||||
GITHUB_WEB_HASH="$(get_remote_hash AdminLTE "${WEB_BRANCH}")"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_WEB_HASH" "${GITHUB_WEB_HASH}"
|
||||
|
||||
fi
|
||||
|
||||
# get FTL versions
|
||||
|
||||
FTL_VERSION="$(pihole-FTL version)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "FTL_VERSION" "${FTL_VERSION}"
|
||||
|
||||
FTL_BRANCH="$(pihole-FTL branch)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "FTL_BRANCH" "${FTL_BRANCH}"
|
||||
|
||||
FTL_HASH="$(pihole-FTL --hash)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "FTL_HASH" "${FTL_HASH}"
|
||||
|
||||
GITHUB_FTL_VERSION="$(get_remote_version FTL)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_FTL_VERSION" "${GITHUB_FTL_VERSION}"
|
||||
|
||||
GITHUB_FTL_HASH="$(get_remote_hash FTL "${FTL_BRANCH}")"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_FTL_HASH" "${GITHUB_FTL_HASH}"
|
||||
|
||||
|
||||
# get Docker versions
|
||||
|
||||
if [[ "${DOCKER_TAG}" ]]; then
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "DOCKER_VERSION" "${DOCKER_TAG}"
|
||||
|
||||
GITHUB_DOCKER_VERSION="$(get_remote_version docker-pi-hole)"
|
||||
addOrEditKeyValPair "${VERSION_FILE}" "GITHUB_DOCKER_VERSION" "${GITHUB_DOCKER_VERSION}"
|
||||
fi
|
||||
|
||||
@@ -31,9 +31,12 @@ addOrEditKeyValPair() {
|
||||
local key="${2}"
|
||||
local value="${3}"
|
||||
|
||||
# touch file to prevent grep error if file does not exist yet
|
||||
touch "${file}"
|
||||
|
||||
if grep -q "^${key}=" "${file}"; then
|
||||
# Key already exists in file, modify the value
|
||||
sed -i "/^${key}=/c\\${key}=${value}" "${file}"
|
||||
# Key already exists in file, modify the value
|
||||
sed -i "/^${key}=/c\\${key}=${value}" "${file}"
|
||||
else
|
||||
# Key does not already exist, add it and it's value
|
||||
echo "${key}=${value}" >> "${file}"
|
||||
@@ -51,9 +54,16 @@ addKey(){
|
||||
local file="${1}"
|
||||
local key="${2}"
|
||||
|
||||
if ! grep -q "^${key}" "${file}"; then
|
||||
# Key does not exist, add it.
|
||||
echo "${key}" >> "${file}"
|
||||
# touch file to prevent grep error if file does not exist yet
|
||||
touch "${file}"
|
||||
|
||||
# Match key against entire line, using both anchors. We assume
|
||||
# that the file's keys never have bounding whitespace. Anchors
|
||||
# are necessary to ensure the key is considered absent when it
|
||||
# is a substring of another key present in the file.
|
||||
if ! grep -q "^${key}$" "${file}"; then
|
||||
# Key does not exist, add it.
|
||||
echo "${key}" >> "${file}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -70,29 +80,68 @@ removeKey() {
|
||||
sed -i "/^${key}/d" "${file}"
|
||||
}
|
||||
|
||||
|
||||
#######################
|
||||
# returns FTL's current telnet API port
|
||||
#######################
|
||||
# returns FTL's current telnet API port based on the setting in /etc/pihole-FTL.conf
|
||||
########################
|
||||
getFTLAPIPort(){
|
||||
local FTLCONFFILE="/etc/pihole/pihole-FTL.conf"
|
||||
local DEFAULT_PORT_FILE="/run/pihole-FTL.port"
|
||||
local DEFAULT_FTL_PORT=4711
|
||||
local PORTFILE
|
||||
local ftl_api_port
|
||||
local FTLCONFFILE="/etc/pihole/pihole-FTL.conf"
|
||||
local DEFAULT_FTL_PORT=4711
|
||||
local ftl_api_port
|
||||
|
||||
if [ -f "$FTLCONFFILE" ]; then
|
||||
# if PORTFILE is not set in pihole-FTL.conf, use the default path
|
||||
PORTFILE="$( (grep "^PORTFILE=" $FTLCONFFILE || echo "$DEFAULT_PORT_FILE") | cut -d"=" -f2-)"
|
||||
fi
|
||||
if [ -s "$FTLCONFFILE" ]; then
|
||||
# if FTLPORT is not set in pihole-FTL.conf, use the default port
|
||||
ftl_api_port="$({ grep '^FTLPORT=' "${FTLCONFFILE}" || echo "${DEFAULT_FTL_PORT}"; } | cut -d'=' -f2-)"
|
||||
# Exploit prevention: set the port to the default port if there is malicious (non-numeric)
|
||||
# content set in pihole-FTL.conf
|
||||
expr "${ftl_api_port}" : "[^[:digit:]]" > /dev/null && ftl_api_port="${DEFAULT_FTL_PORT}"
|
||||
else
|
||||
# if there is no pihole-FTL.conf, use the default port
|
||||
ftl_api_port="${DEFAULT_FTL_PORT}"
|
||||
fi
|
||||
|
||||
if [ -s "$PORTFILE" ]; then
|
||||
# -s: FILE exists and has a size greater than zero
|
||||
ftl_api_port=$(cat "${PORTFILE}")
|
||||
# Exploit prevention: unset the variable if there is malicious content
|
||||
# Verify that the value read from the file is numeric
|
||||
expr "$ftl_api_port" : "[^[:digit:]]" > /dev/null && unset ftl_api_port
|
||||
fi
|
||||
|
||||
# echo the port found in the portfile or default to the default port
|
||||
echo "${ftl_api_port:=$DEFAULT_FTL_PORT}"
|
||||
echo "${ftl_api_port}"
|
||||
}
|
||||
|
||||
#######################
|
||||
# returns path of FTL's PID file
|
||||
#######################
|
||||
getFTLPIDFile() {
|
||||
local FTLCONFFILE="/etc/pihole/pihole-FTL.conf"
|
||||
local DEFAULT_PID_FILE="/run/pihole-FTL.pid"
|
||||
local FTL_PID_FILE
|
||||
|
||||
if [ -s "${FTLCONFFILE}" ]; then
|
||||
# if PIDFILE is not set in pihole-FTL.conf, use the default path
|
||||
FTL_PID_FILE="$({ grep '^PIDFILE=' "${FTLCONFFILE}" || echo "${DEFAULT_PID_FILE}"; } | cut -d'=' -f2-)"
|
||||
else
|
||||
# if there is no pihole-FTL.conf, use the default path
|
||||
FTL_PID_FILE="${DEFAULT_PID_FILE}"
|
||||
fi
|
||||
|
||||
echo "${FTL_PID_FILE}"
|
||||
}
|
||||
|
||||
#######################
|
||||
# returns FTL's PID based on the content of the pihole-FTL.pid file
|
||||
#
|
||||
# Takes one argument: path to pihole-FTL.pid
|
||||
# Example getFTLPID "/run/pihole-FTL.pid"
|
||||
#######################
|
||||
getFTLPID() {
|
||||
local FTL_PID_FILE="${1}"
|
||||
local FTL_PID
|
||||
|
||||
if [ -s "${FTL_PID_FILE}" ]; then
|
||||
# -s: FILE exists and has a size greater than zero
|
||||
FTL_PID="$(cat "${FTL_PID_FILE}")"
|
||||
# Exploit prevention: unset the variable if there is malicious content
|
||||
# Verify that the value read from the file is numeric
|
||||
expr "${FTL_PID}" : "[^[:digit:]]" > /dev/null && unset FTL_PID
|
||||
fi
|
||||
|
||||
# If FTL is not running, or the PID file contains malicious stuff, substitute
|
||||
# negative PID to signal this
|
||||
FTL_PID=${FTL_PID:=-1}
|
||||
echo "${FTL_PID}"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
@@ -8,178 +8,104 @@
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
# Variables
|
||||
DEFAULT="-1"
|
||||
COREGITDIR="/etc/.pihole/"
|
||||
WEBGITDIR="/var/www/html/admin/"
|
||||
|
||||
# Source the setupvars config file
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/pihole/setupVars.conf
|
||||
. /etc/pihole/setupVars.conf
|
||||
|
||||
# Source the versions file poupulated by updatechecker.sh
|
||||
cachedVersions="/etc/pihole/versions"
|
||||
|
||||
if [ -f ${cachedVersions} ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "$cachedVersions"
|
||||
else
|
||||
echo "Could not find /etc/pihole/versions. Running update now."
|
||||
pihole updatechecker
|
||||
# shellcheck disable=SC1090
|
||||
. "$cachedVersions"
|
||||
fi
|
||||
|
||||
getLocalVersion() {
|
||||
# FTL requires a different method
|
||||
if [[ "$1" == "FTL" ]]; then
|
||||
pihole-FTL version
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get the tagged version of the local repository
|
||||
local directory="${1}"
|
||||
local version
|
||||
|
||||
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
||||
version=$(git describe --tags --always || echo "$DEFAULT")
|
||||
if [[ "${version}" =~ ^v ]]; then
|
||||
echo "${version}"
|
||||
elif [[ "${version}" == "${DEFAULT}" ]]; then
|
||||
echo "ERROR"
|
||||
return 1
|
||||
else
|
||||
echo "Untagged"
|
||||
fi
|
||||
return 0
|
||||
case ${1} in
|
||||
"Pi-hole" ) echo "${CORE_VERSION:=N/A}";;
|
||||
"AdminLTE" ) [ "${INSTALL_WEB_INTERFACE}" = true ] && echo "${WEB_VERSION:=N/A}";;
|
||||
"FTL" ) echo "${FTL_VERSION:=N/A}";;
|
||||
esac
|
||||
}
|
||||
|
||||
getLocalHash() {
|
||||
# Local FTL hash does not exist on filesystem
|
||||
if [[ "$1" == "FTL" ]]; then
|
||||
echo "N/A"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get the short hash of the local repository
|
||||
local directory="${1}"
|
||||
local hash
|
||||
|
||||
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
||||
hash=$(git rev-parse --short HEAD || echo "$DEFAULT")
|
||||
if [[ "${hash}" == "${DEFAULT}" ]]; then
|
||||
echo "ERROR"
|
||||
return 1
|
||||
else
|
||||
echo "${hash}"
|
||||
fi
|
||||
return 0
|
||||
case ${1} in
|
||||
"Pi-hole" ) echo "${CORE_HASH:=N/A}";;
|
||||
"AdminLTE" ) [ "${INSTALL_WEB_INTERFACE}" = true ] && echo "${WEB_HASH:=N/A}";;
|
||||
"FTL" ) echo "${FTL_HASH:=N/A}";;
|
||||
esac
|
||||
}
|
||||
|
||||
getRemoteHash(){
|
||||
# Remote FTL hash is not applicable
|
||||
if [[ "$1" == "FTL" ]]; then
|
||||
echo "N/A"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local daemon="${1}"
|
||||
local branch="${2}"
|
||||
|
||||
hash=$(git ls-remote --heads "https://github.com/pi-hole/${daemon}" | \
|
||||
awk -v bra="$branch" '$0~bra {print substr($0,0,8);exit}')
|
||||
if [[ -n "$hash" ]]; then
|
||||
echo "$hash"
|
||||
else
|
||||
echo "ERROR"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
case ${1} in
|
||||
"Pi-hole" ) echo "${GITHUB_CORE_HASH:=N/A}";;
|
||||
"AdminLTE" ) [ "${INSTALL_WEB_INTERFACE}" = true ] && echo "${GITHUB_WEB_HASH:=N/A}";;
|
||||
"FTL" ) echo "${GITHUB_FTL_HASH:=N/A}";;
|
||||
esac
|
||||
}
|
||||
|
||||
getRemoteVersion(){
|
||||
# Get the version from the remote origin
|
||||
local daemon="${1}"
|
||||
local version
|
||||
local cachedVersions
|
||||
local arrCache
|
||||
cachedVersions="/etc/pihole/GitHubVersions"
|
||||
|
||||
#If the above file exists, then we can read from that. Prevents overuse of GitHub API
|
||||
if [[ -f "$cachedVersions" ]]; then
|
||||
IFS=' ' read -r -a arrCache < "$cachedVersions"
|
||||
|
||||
case $daemon in
|
||||
"pi-hole" ) echo "${arrCache[0]}";;
|
||||
"AdminLTE" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[1]}";;
|
||||
"FTL" ) [[ "${INSTALL_WEB_INTERFACE}" == true ]] && echo "${arrCache[2]}" || echo "${arrCache[1]}";;
|
||||
esac
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
version=$(curl --silent --fail "https://api.github.com/repos/pi-hole/${daemon}/releases/latest" | \
|
||||
awk -F: '$1 ~/tag_name/ { print $2 }' | \
|
||||
tr -cd '[[:alnum:]]._-')
|
||||
if [[ "${version}" =~ ^v ]]; then
|
||||
echo "${version}"
|
||||
else
|
||||
echo "ERROR"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
case ${1} in
|
||||
"Pi-hole" ) echo "${GITHUB_CORE_VERSION:=N/A}";;
|
||||
"AdminLTE" ) [ "${INSTALL_WEB_INTERFACE}" = true ] && echo "${GITHUB_WEB_VERSION:=N/A}";;
|
||||
"FTL" ) echo "${GITHUB_FTL_VERSION:=N/A}";;
|
||||
esac
|
||||
}
|
||||
|
||||
getLocalBranch(){
|
||||
# Get the checked out branch of the local directory
|
||||
local directory="${1}"
|
||||
local branch
|
||||
|
||||
# Local FTL btranch is stored in /etc/pihole/ftlbranch
|
||||
if [[ "$1" == "FTL" ]]; then
|
||||
branch="$(pihole-FTL branch)"
|
||||
else
|
||||
cd "${directory}" 2> /dev/null || { echo "${DEFAULT}"; return 1; }
|
||||
branch=$(git rev-parse --abbrev-ref HEAD || echo "$DEFAULT")
|
||||
fi
|
||||
if [[ ! "${branch}" =~ ^v ]]; then
|
||||
if [[ "${branch}" == "master" ]]; then
|
||||
echo ""
|
||||
elif [[ "${branch}" == "HEAD" ]]; then
|
||||
echo "in detached HEAD state at "
|
||||
else
|
||||
echo "${branch} "
|
||||
fi
|
||||
else
|
||||
# Branch started in "v"
|
||||
echo "release "
|
||||
fi
|
||||
return 0
|
||||
case ${1} in
|
||||
"Pi-hole" ) echo "${CORE_BRANCH:=N/A}";;
|
||||
"AdminLTE" ) [ "${INSTALL_WEB_INTERFACE}" = true ] && echo "${WEB_BRANCH:=N/A}";;
|
||||
"FTL" ) echo "${FTL_BRANCH:=N/A}";;
|
||||
esac
|
||||
}
|
||||
|
||||
versionOutput() {
|
||||
if [[ "$1" == "AdminLTE" && "${INSTALL_WEB_INTERFACE}" != true ]]; then
|
||||
if [ "$1" = "AdminLTE" ] && [ "${INSTALL_WEB_INTERFACE}" != true ]; then
|
||||
echo " WebAdmin not installed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
[[ "$1" == "pi-hole" ]] && GITDIR=$COREGITDIR
|
||||
[[ "$1" == "AdminLTE" ]] && GITDIR=$WEBGITDIR
|
||||
[[ "$1" == "FTL" ]] && GITDIR="FTL"
|
||||
|
||||
[[ "$2" == "-c" ]] || [[ "$2" == "--current" ]] || [[ -z "$2" ]] && current=$(getLocalVersion $GITDIR) && branch=$(getLocalBranch $GITDIR)
|
||||
[[ "$2" == "-l" ]] || [[ "$2" == "--latest" ]] || [[ -z "$2" ]] && latest=$(getRemoteVersion "$1")
|
||||
if [[ "$2" == "-h" ]] || [[ "$2" == "--hash" ]]; then
|
||||
[[ "$3" == "-c" ]] || [[ "$3" == "--current" ]] || [[ -z "$3" ]] && curHash=$(getLocalHash "$GITDIR") && branch=$(getLocalBranch $GITDIR)
|
||||
[[ "$3" == "-l" ]] || [[ "$3" == "--latest" ]] || [[ -z "$3" ]] && latHash=$(getRemoteHash "$1" "$(cd "$GITDIR" 2> /dev/null && git rev-parse --abbrev-ref HEAD)")
|
||||
[ "$2" = "-c" ] || [ "$2" = "--current" ] || [ -z "$2" ] && current=$(getLocalVersion "${1}") && branch=$(getLocalBranch "${1}")
|
||||
[ "$2" = "-l" ] || [ "$2" = "--latest" ] || [ -z "$2" ] && latest=$(getRemoteVersion "${1}")
|
||||
if [ "$2" = "--hash" ]; then
|
||||
[ "$3" = "-c" ] || [ "$3" = "--current" ] || [ -z "$3" ] && curHash=$(getLocalHash "${1}") && branch=$(getLocalBranch "${1}")
|
||||
[ "$3" = "-l" ] || [ "$3" = "--latest" ] || [ -z "$3" ] && latHash=$(getRemoteHash "${1}") && branch=$(getLocalBranch "${1}")
|
||||
fi
|
||||
if [[ -n "$current" ]] && [[ -n "$latest" ]]; then
|
||||
output="${1^} version is $branch$current (Latest: $latest)"
|
||||
elif [[ -n "$current" ]] && [[ -z "$latest" ]]; then
|
||||
output="Current ${1^} version is $branch$current"
|
||||
elif [[ -z "$current" ]] && [[ -n "$latest" ]]; then
|
||||
output="Latest ${1^} version is $latest"
|
||||
elif [[ "$curHash" == "N/A" ]] || [[ "$latHash" == "N/A" ]]; then
|
||||
output="${1^} hash is not applicable"
|
||||
elif [[ -n "$curHash" ]] && [[ -n "$latHash" ]]; then
|
||||
output="${1^} hash is $curHash (Latest: $latHash)"
|
||||
elif [[ -n "$curHash" ]] && [[ -z "$latHash" ]]; then
|
||||
output="Current ${1^} hash is $curHash"
|
||||
elif [[ -z "$curHash" ]] && [[ -n "$latHash" ]]; then
|
||||
output="Latest ${1^} hash is $latHash"
|
||||
|
||||
# We do not want to show the branch name when we are on master,
|
||||
# blank out the variable in this case
|
||||
if [ "$branch" = "master" ]; then
|
||||
branch=""
|
||||
else
|
||||
branch="$branch "
|
||||
fi
|
||||
|
||||
if [ -n "$current" ] && [ -n "$latest" ]; then
|
||||
output="${1} version is $branch$current (Latest: $latest)"
|
||||
elif [ -n "$current" ] && [ -z "$latest" ]; then
|
||||
output="Current ${1} version is $branch$current"
|
||||
elif [ -z "$current" ] && [ -n "$latest" ]; then
|
||||
output="Latest ${1} version is $latest"
|
||||
elif [ -n "$curHash" ] && [ -n "$latHash" ]; then
|
||||
output="Local ${1} hash is $curHash (Remote: $latHash)"
|
||||
elif [ -n "$curHash" ] && [ -z "$latHash" ]; then
|
||||
output="Current local ${1} hash is $curHash"
|
||||
elif [ -z "$curHash" ] && [ -n "$latHash" ]; then
|
||||
output="Latest remote ${1} hash is $latHash"
|
||||
elif [ -z "$curHash" ] && [ -z "$latHash" ]; then
|
||||
output="Hashes for ${1} not available"
|
||||
else
|
||||
errorOutput
|
||||
return 1
|
||||
fi
|
||||
|
||||
[[ -n "$output" ]] && echo " $output"
|
||||
[ -n "$output" ] && echo " $output"
|
||||
}
|
||||
|
||||
errorOutput() {
|
||||
@@ -188,9 +114,9 @@ errorOutput() {
|
||||
}
|
||||
|
||||
defaultOutput() {
|
||||
versionOutput "pi-hole" "$@"
|
||||
versionOutput "Pi-hole" "$@"
|
||||
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||
if [ "${INSTALL_WEB_INTERFACE}" = true ]; then
|
||||
versionOutput "AdminLTE" "$@"
|
||||
fi
|
||||
|
||||
@@ -216,7 +142,7 @@ Options:
|
||||
}
|
||||
|
||||
case "${1}" in
|
||||
"-p" | "--pihole" ) shift; versionOutput "pi-hole" "$@";;
|
||||
"-p" | "--pihole" ) shift; versionOutput "Pi-hole" "$@";;
|
||||
"-a" | "--admin" ) shift; versionOutput "AdminLTE" "$@";;
|
||||
"-f" | "--ftl" ) shift; versionOutput "FTL" "$@";;
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
|
||||
@@ -24,8 +24,8 @@ readonly gravityDBfile="/etc/pihole/gravity.db"
|
||||
|
||||
# Source install script for ${setupVars}, ${PI_HOLE_BIN_DIR} and valid_ip()
|
||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||
# shellcheck disable=SC2034 # used in basic-install
|
||||
PH_TEST="true"
|
||||
# shellcheck disable=SC2034 # used in basic-install to source the script without running it
|
||||
SKIP_INSTALL="true"
|
||||
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||
|
||||
utilsfile="/opt/pihole/utils.sh"
|
||||
@@ -46,7 +46,6 @@ Options:
|
||||
-c, celsius Set Celsius as preferred temperature unit
|
||||
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||
-k, kelvin Set Kelvin as preferred temperature unit
|
||||
-e, email Set an administrative contact address for the Block Page
|
||||
-h, --help Show this help dialog
|
||||
-i, interface Specify dnsmasq's interface listening behavior
|
||||
-l, privacylevel Set privacy level (0 = lowest, 3 = highest)
|
||||
@@ -394,13 +393,8 @@ ProcessDHCPSettings() {
|
||||
if [[ "${DHCP_LEASETIME}" == "0" ]]; then
|
||||
leasetime="infinite"
|
||||
elif [[ "${DHCP_LEASETIME}" == "" ]]; then
|
||||
leasetime="24"
|
||||
addOrEditKeyValPair "${setupVars}" "DHCP_LEASETIME" "${leasetime}"
|
||||
elif [[ "${DHCP_LEASETIME}" == "24h" ]]; then
|
||||
#Installation is affected by known bug, introduced in a previous version.
|
||||
#This will automatically clean up setupVars.conf and remove the unnecessary "h"
|
||||
leasetime="24"
|
||||
addOrEditKeyValPair "${setupVars}" "DHCP_LEASETIME" "${leasetime}"
|
||||
leasetime="24h"
|
||||
addOrEditKeyValPair "${setupVars}" "DHCP_LEASETIME" "24"
|
||||
else
|
||||
leasetime="${DHCP_LEASETIME}h"
|
||||
fi
|
||||
@@ -568,37 +562,6 @@ RemoveDHCPStaticAddress() {
|
||||
|
||||
}
|
||||
|
||||
SetAdminEmail() {
|
||||
if [[ "${1}" == "-h" ]] || [[ "${1}" == "--help" ]]; then
|
||||
echo "Usage: pihole -a email <address>
|
||||
Example: 'pihole -a email admin@address.com'
|
||||
Set an administrative contact address for the Block Page
|
||||
|
||||
Options:
|
||||
\"\" Empty: Remove admin contact
|
||||
-h, --help Show this help dialog"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -n "${args[2]}" ]]; then
|
||||
|
||||
# Sanitize email address in case of security issues
|
||||
# Regex from https://stackoverflow.com/a/2138832/4065967
|
||||
local regex
|
||||
regex="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\$"
|
||||
if [[ ! "${args[2]}" =~ ${regex} ]]; then
|
||||
echo -e " ${CROSS} Invalid email address"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
addOrEditKeyValPair "${setupVars}" "ADMIN_EMAIL" "${args[2]}"
|
||||
echo -e " ${TICK} Setting admin contact to ${args[2]}"
|
||||
else
|
||||
addOrEditKeyValPair "${setupVars}" "ADMIN_EMAIL" ""
|
||||
echo -e " ${TICK} Removing admin contact"
|
||||
fi
|
||||
}
|
||||
|
||||
SetListeningMode() {
|
||||
source "${setupVars}"
|
||||
|
||||
@@ -664,6 +627,14 @@ checkDomain()
|
||||
echo "${validDomain}"
|
||||
}
|
||||
|
||||
escapeDots()
|
||||
{
|
||||
# SC suggest bashism ${variable//search/replace}
|
||||
# shellcheck disable=SC2001
|
||||
escaped=$(echo "$1" | sed 's/\./\\./g')
|
||||
echo "${escaped}"
|
||||
}
|
||||
|
||||
addAudit()
|
||||
{
|
||||
shift # skip "-a"
|
||||
@@ -739,6 +710,7 @@ RemoveCustomDNSAddress() {
|
||||
validHost="$(checkDomain "${host}")"
|
||||
if [[ -n "${validHost}" ]]; then
|
||||
if valid_ip "${ip}" || valid_ip6 "${ip}" ; then
|
||||
validHost=$(escapeDots "${validHost}")
|
||||
sed -i "/^${ip} ${validHost}$/Id" "${dnscustomfile}"
|
||||
else
|
||||
echo -e " ${CROSS} Invalid IP has been passed"
|
||||
@@ -766,7 +738,12 @@ AddCustomCNAMERecord() {
|
||||
if [[ -n "${validDomain}" ]]; then
|
||||
validTarget="$(checkDomain "${target}")"
|
||||
if [[ -n "${validTarget}" ]]; then
|
||||
echo "cname=${validDomain},${validTarget}" >> "${dnscustomcnamefile}"
|
||||
if [ "${validDomain}" = "${validTarget}" ]; then
|
||||
echo " ${CROSS} Domain and target are the same. This would cause a DNS loop."
|
||||
exit 1
|
||||
else
|
||||
echo "cname=${validDomain},${validTarget}" >> "${dnscustomcnamefile}"
|
||||
fi
|
||||
else
|
||||
echo " ${CROSS} Invalid Target Passed!"
|
||||
exit 1
|
||||
@@ -792,7 +769,9 @@ RemoveCustomCNAMERecord() {
|
||||
if [[ -n "${validDomain}" ]]; then
|
||||
validTarget="$(checkDomain "${target}")"
|
||||
if [[ -n "${validTarget}" ]]; then
|
||||
sed -i "/cname=${validDomain},${validTarget}$/Id" "${dnscustomcnamefile}"
|
||||
validDomain=$(escapeDots "${validDomain}")
|
||||
validTarget=$(escapeDots "${validTarget}")
|
||||
sed -i "/^cname=${validDomain},${validTarget}$/Id" "${dnscustomcnamefile}"
|
||||
else
|
||||
echo " ${CROSS} Invalid Target Passed!"
|
||||
exit 1
|
||||
@@ -847,7 +826,6 @@ main() {
|
||||
"-h" | "--help" ) helpFunc;;
|
||||
"addstaticdhcp" ) AddDHCPStaticAddress;;
|
||||
"removestaticdhcp" ) RemoveDHCPStaticAddress;;
|
||||
"-e" | "email" ) SetAdminEmail "$3";;
|
||||
"-i" | "interface" ) SetListeningMode "$@";;
|
||||
"-t" | "teleporter" ) Teleporter;;
|
||||
"adlist" ) CustomizeAdLists;;
|
||||
|
||||
13
advanced/Templates/pihole-FTL-poststop.sh
Executable file
13
advanced/Templates/pihole-FTL-poststop.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Source utils.sh for getFTLPIDFile()
|
||||
PI_HOLE_SCRIPT_DIR='/opt/pihole'
|
||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
||||
# shellcheck disable=SC1090
|
||||
. "${utilsfile}"
|
||||
|
||||
# Get file paths
|
||||
FTL_PID_FILE="$(getFTLPIDFile)"
|
||||
|
||||
# Cleanup
|
||||
rm -f /run/pihole/FTL.sock /dev/shm/FTL-* "${FTL_PID_FILE}"
|
||||
38
advanced/Templates/pihole-FTL-prestart.sh
Executable file
38
advanced/Templates/pihole-FTL-prestart.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Source utils.sh for getFTLPIDFile()
|
||||
PI_HOLE_SCRIPT_DIR='/opt/pihole'
|
||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
||||
# shellcheck disable=SC1090
|
||||
. "${utilsfile}"
|
||||
|
||||
# Get file paths
|
||||
FTL_PID_FILE="$(getFTLPIDFile)"
|
||||
|
||||
# Touch files to ensure they exist (create if non-existing, preserve if existing)
|
||||
# shellcheck disable=SC2174
|
||||
mkdir -pm 0755 /run/pihole /var/log/pihole
|
||||
[ -f "${FTL_PID_FILE}" ] || install -D -m 644 -o pihole -g pihole /dev/null "${FTL_PID_FILE}"
|
||||
[ -f /var/log/pihole/FTL.log ] || install -m 644 -o pihole -g pihole /dev/null /var/log/pihole/FTL.log
|
||||
[ -f /var/log/pihole/pihole.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/pihole.log
|
||||
[ -f /etc/pihole/dhcp.leases ] || install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases
|
||||
# Ensure that permissions are set so that pihole-FTL can edit all necessary files
|
||||
chown pihole:pihole /run/pihole /etc/pihole /var/log/pihole /var/log/pihole/FTL.log /var/log/pihole/pihole.log /etc/pihole/dhcp.leases
|
||||
# Ensure that permissions are set so that pihole-FTL can edit the files. We ignore errors as the file may not (yet) exist
|
||||
chmod -f 0644 /etc/pihole/macvendor.db /etc/pihole/dhcp.leases /var/log/pihole/FTL.log
|
||||
chmod -f 0640 /var/log/pihole/pihole.log
|
||||
# Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist
|
||||
chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db
|
||||
# Chmod database file permissions so that the pihole group (web interface) can edit the file. We ignore errors as the files may not (yet) exist
|
||||
chmod -f 0664 /etc/pihole/pihole-FTL.db
|
||||
|
||||
# Backward compatibility for user-scripts that still expect log files in /var/log instead of /var/log/pihole
|
||||
# Should be removed with Pi-hole v6.0
|
||||
if [ ! -f /var/log/pihole.log ]; then
|
||||
ln -sf /var/log/pihole/pihole.log /var/log/pihole.log
|
||||
chown -h pihole:pihole /var/log/pihole.log
|
||||
fi
|
||||
if [ ! -f /var/log/pihole-FTL.log ]; then
|
||||
ln -sf /var/log/pihole/FTL.log /var/log/pihole-FTL.log
|
||||
chown -h pihole:pihole /var/log/pihole-FTL.log
|
||||
fi
|
||||
@@ -9,48 +9,11 @@
|
||||
# Description: Enable service provided by pihole-FTL daemon
|
||||
### END INIT INFO
|
||||
|
||||
# Global variables
|
||||
FTLCONFFILE="/etc/pihole/pihole-FTL.conf"
|
||||
DEFAULT_PID_FILE="/run/pihole-FTL.pid"
|
||||
DEFAULT_PORT_FILE="/run/pihole-FTL.port"
|
||||
FTL_PID=''
|
||||
|
||||
# Get the file path of the pihole-FTL.pid file
|
||||
getFTLPIDFile() {
|
||||
if [ -s "${FTLCONFFILE}" ]; then
|
||||
# if PIDFILE is not set in pihole-FTL.conf, use the default path
|
||||
FTL_PID_FILE="$({ grep '^PIDFILE=' "${FTLCONFFILE}" || echo "${DEFAULT_PID_FILE}"; } | cut -d'=' -f2-)"
|
||||
else
|
||||
# if there is no pihole-FTL.conf, use the default path
|
||||
FTL_PID_FILE="${DEFAULT_PID_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the PID of the FTL process based on the content of the pihole-FTL.pid file
|
||||
getFTLPID() {
|
||||
if [ -s "${FTL_PID_FILE}" ]; then
|
||||
# -s: FILE exists and has a size greater than zero
|
||||
FTL_PID="$(cat "${FTL_PID_FILE}")"
|
||||
# Exploit prevention: unset the variable if there is malicious content
|
||||
# Verify that the value read from the file is numeric
|
||||
expr "${FTL_PID}" : "[^[:digit:]]" > /dev/null && unset FTL_PID
|
||||
fi
|
||||
|
||||
# If FTL is not running, or the PID file contains malicious stuff, substitute
|
||||
# negative PID to signal this
|
||||
FTL_PID=${FTL_PID:=-1}
|
||||
}
|
||||
|
||||
# Get the file path of the pihole-FTL.port file
|
||||
getFTLPortFile() {
|
||||
if [ -s "${FTLCONFFILE}" ]; then
|
||||
# if PORTFILE is not set in pihole-FTL.conf, use the default path
|
||||
FTL_PORT_FILE="$({ grep '^PORTFILE=' "${FTLCONFFILE}" || echo "${DEFAULT_PORT_FILE}"; } | cut -d'=' -f2-)"
|
||||
else
|
||||
# if there is no pihole-FTL.conf, use the default path
|
||||
FTL_PORT_FILE="${DEFAULT_PORT_FILE}"
|
||||
fi
|
||||
}
|
||||
# Source utils.sh for getFTLPIDFile(), getFTLPID()
|
||||
PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
||||
# shellcheck disable=SC1090
|
||||
. "${utilsfile}"
|
||||
|
||||
|
||||
is_running() {
|
||||
@@ -60,40 +23,19 @@ is_running() {
|
||||
return 1
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
# Run post-stop script, which does cleanup among runtime files
|
||||
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-poststop.sh"
|
||||
}
|
||||
|
||||
|
||||
# Start the service
|
||||
start() {
|
||||
if is_running; then
|
||||
echo "pihole-FTL is already running"
|
||||
else
|
||||
# Touch files to ensure they exist (create if non-existing, preserve if existing)
|
||||
mkdir -pm 0755 /run/pihole /var/log/pihole
|
||||
[ ! -f "${FTL_PID_FILE}" ] && install -m 644 -o pihole -g pihole /dev/null "${FTL_PID_FILE}"
|
||||
[ ! -f "${FTL_PORT_FILE}" ] && install -m 644 -o pihole -g pihole /dev/null "${FTL_PORT_FILE}"
|
||||
[ ! -f /var/log/pihole/FTL.log ] && install -m 644 -o pihole -g pihole /dev/null /var/log/pihole/FTL.log
|
||||
[ ! -f /var/log/pihole/pihole.log ] && install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/pihole.log
|
||||
[ ! -f /etc/pihole/dhcp.leases ] && install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases
|
||||
# Ensure that permissions are set so that pihole-FTL can edit all necessary files
|
||||
chown pihole:pihole /run/pihole /etc/pihole /var/log/pihole /var/log/pihole/FTL.log /var/log/pihole/pihole.log /etc/pihole/dhcp.leases
|
||||
# Ensure that permissions are set so that pihole-FTL can edit the files. We ignore errors as the file may not (yet) exist
|
||||
chmod -f 0644 /etc/pihole/macvendor.db /etc/pihole/dhcp.leases /var/log/pihole/FTL.log
|
||||
chmod -f 0640 /var/log/pihole/pihole.log
|
||||
# Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist
|
||||
chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db
|
||||
# Chown database file permissions so that the pihole group (web interface) can edit the file. We ignore errors as the files may not (yet) exist
|
||||
chmod -f 0664 /etc/pihole/pihole-FTL.db
|
||||
|
||||
# Backward compatibility for user-scripts that still expect log files in /var/log instead of /var/log/pihole/
|
||||
# Should be removed with Pi-hole v6.0
|
||||
if [ ! -f /var/log/pihole.log ]; then
|
||||
ln -s /var/log/pihole/pihole.log /var/log/pihole.log
|
||||
chown -h pihole:pihole /var/log/pihole.log
|
||||
|
||||
fi
|
||||
if [ ! -f /var/log/pihole-FTL.log ]; then
|
||||
ln -s /var/log/pihole/FTL.log /var/log/pihole-FTL.log
|
||||
chown -h pihole:pihole /var/log/pihole-FTL.log
|
||||
fi
|
||||
# Run pre-start script, which pre-creates all expected files with correct permissions
|
||||
sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-prestart.sh"
|
||||
|
||||
if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE,CAP_IPC_LOCK,CAP_CHOWN+eip "/usr/bin/pihole-FTL"; then
|
||||
su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole
|
||||
@@ -101,6 +43,12 @@ start() {
|
||||
echo "Warning: Starting pihole-FTL as root because setting capabilities is not supported on this system"
|
||||
/usr/bin/pihole-FTL
|
||||
fi
|
||||
rc=$?
|
||||
# Cleanup if startup failed
|
||||
if [ "${rc}" != 0 ]; then
|
||||
cleanup
|
||||
exit $rc
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
}
|
||||
@@ -128,8 +76,7 @@ stop() {
|
||||
else
|
||||
echo "Not running"
|
||||
fi
|
||||
# Cleanup
|
||||
rm -f /run/pihole/FTL.sock /dev/shm/FTL-* "${FTL_PID_FILE}" "${FTL_PORT_FILE}"
|
||||
cleanup
|
||||
echo
|
||||
}
|
||||
|
||||
@@ -147,12 +94,14 @@ status() {
|
||||
|
||||
### main logic ###
|
||||
|
||||
# Get file paths
|
||||
getFTLPIDFile
|
||||
getFTLPortFile
|
||||
# catch sudden termination
|
||||
trap 'cleanup; exit 1' INT HUP TERM ABRT
|
||||
|
||||
# Get FTL's PID file path
|
||||
FTL_PID_FILE="$(getFTLPIDFile)"
|
||||
|
||||
# Get FTL's current PID
|
||||
getFTLPID
|
||||
FTL_PID="$(getFTLPID "${FTL_PID_FILE}")"
|
||||
|
||||
case "$1" in
|
||||
stop)
|
||||
|
||||
41
advanced/Templates/pihole-FTL.systemd
Normal file
41
advanced/Templates/pihole-FTL.systemd
Normal file
@@ -0,0 +1,41 @@
|
||||
[Unit]
|
||||
Description=Pi-hole FTL
|
||||
# This unit is supposed to indicate when network functionality is available, but it is only
|
||||
# very weakly defined what that is supposed to mean, with one exception: at shutdown, a unit
|
||||
# that is ordered after network-online.target will be stopped before the network
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
# A target that should be used as synchronization point for all host/network name service lookups.
|
||||
# All services for which the availability of full host/network name resolution is essential should
|
||||
# be ordered after this target, but not pull it in.
|
||||
Wants=nss-lookup.target
|
||||
Before=nss-lookup.target
|
||||
|
||||
# Limit (re)start loop to 5 within 1 minute
|
||||
StartLimitBurst=5
|
||||
StartLimitIntervalSec=60s
|
||||
|
||||
[Service]
|
||||
User=pihole
|
||||
PermissionsStartOnly=true
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN CAP_SYS_NICE CAP_IPC_LOCK CAP_CHOWN
|
||||
|
||||
ExecStartPre=/opt/pihole/pihole-FTL-prestart.sh
|
||||
ExecStart=/usr/bin/pihole-FTL -f
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
ExecStopPost=/opt/pihole/pihole-FTL-poststop.sh
|
||||
|
||||
# Use graceful shutdown with a reasonable timeout
|
||||
TimeoutStopSec=10s
|
||||
|
||||
# Make /usr, /boot, /etc and possibly some more folders read-only...
|
||||
ProtectSystem=full
|
||||
# ... except /etc/pihole
|
||||
# This merely retains r/w access rights, it does not add any new.
|
||||
# Must still be writable on the host!
|
||||
ReadWriteDirectories=/etc/pihole
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -28,9 +28,6 @@
|
||||
|
||||
@reboot root /usr/sbin/logrotate --state /var/lib/logrotate/pihole /etc/pihole/logrotate
|
||||
|
||||
# Pi-hole: Grab local version and branch every 10 minutes
|
||||
*/10 * * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker local
|
||||
|
||||
# Pi-hole: Grab remote version every 24 hours
|
||||
59 17 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker remote
|
||||
@reboot root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker remote reboot
|
||||
# Pi-hole: Grab remote and local version every 24 hours
|
||||
59 17 * * * root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker
|
||||
@reboot root PATH="$PATH:/usr/sbin:/usr/local/bin/" pihole updatechecker reboot
|
||||
|
||||
@@ -15,7 +15,7 @@ _pihole() {
|
||||
COMPREPLY=( $(compgen -W "${opts_lists}" -- ${cur}) )
|
||||
;;
|
||||
"admin")
|
||||
opts_admin="celsius email fahrenheit interface kelvin password privacylevel"
|
||||
opts_admin="celsius fahrenheit interface kelvin password privacylevel"
|
||||
COMPREPLY=( $(compgen -W "${opts_admin}" -- ${cur}) )
|
||||
;;
|
||||
"checkout")
|
||||
|
||||
@@ -1,455 +0,0 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
/* Text Customisation Options ======> */
|
||||
.title::before { content: "Website Blocked"; }
|
||||
.altBtn::before { content: "Why am I here?"; }
|
||||
.linkPH::before { content: "About Pi-hole"; }
|
||||
.linkEmail::before { content: "Contact Admin"; }
|
||||
|
||||
#bpOutput.add::before { content: "Info"; }
|
||||
#bpOutput.add::after { content: "The domain is being whitelisted..."; }
|
||||
#bpOutput.error::before, .unhandled::before { content: "Error"; }
|
||||
#bpOutput.unhandled::after { content: "An unhandled exception occurred. This may happen when your browser is unable to load jQuery, or when the webserver is denying access to the Pi-hole API."; }
|
||||
#bpOutput.success::before { content: "Success"; }
|
||||
#bpOutput.success::after { content: "Website has been whitelisted! You may need to flush your DNS cache"; }
|
||||
|
||||
.recentwl::before { content: "This site has been whitelisted. Please flush your DNS cache and/or restart your browser."; }
|
||||
.unknown::before { content: "This website is not found in any of Pi-hole's blacklists. The reason you have arrived here is unknown."; }
|
||||
.cname::before { content: "This site is an alias for "; } /* <a href="http://cname.com">cname.com</a> */
|
||||
.cname::after { content: ", which may be blocked by Pi-hole."; }
|
||||
|
||||
.blacklist::before { content: "Manually Blacklisted"; }
|
||||
.wildcard::before { content: "Manually Blacklisted by Wildcard"; }
|
||||
.noblock::before { content: "Not found on any Blacklist"; }
|
||||
|
||||
#bpBlock::before { content: "Access to the following website has been denied:"; }
|
||||
#bpFlag::before { content: "This is primarily due to being flagged as:"; }
|
||||
|
||||
#bpHelpTxt::before { content: "If you have an ongoing use for this website, please "; }
|
||||
#bpHelpTxt a::before, #bpHelpTxt span::before { content: "ask the administrator"; }
|
||||
#bpHelpTxt::after{ content: " of the Pi-hole on this network to have it whitelisted"; }
|
||||
|
||||
#bpBack::before { content: "Back to safety"; }
|
||||
#bpInfo::before { content: "Technical Info"; }
|
||||
#bpFoundIn::before { content: "This site is found in "; }
|
||||
#bpFoundIn span::after { content: " of "; }
|
||||
#bpFoundIn::after { content: " lists:"; }
|
||||
#bpWhitelist::before { content: "Whitelist"; }
|
||||
|
||||
footer span::before { content: "Page generated on "; }
|
||||
|
||||
/* Hide whitelisting form entirely */
|
||||
/* #bpWLButtons { display: none; } */
|
||||
|
||||
/* Text Customisation Options <=============================== */
|
||||
|
||||
/* http://necolas.github.io/normalize.css ======> */
|
||||
html { font-family: sans-serif; line-height: 1.15; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
|
||||
body { margin: 0; }
|
||||
article, aside, footer, header, nav, section { display: block; }
|
||||
h1 { font-size: 2em; margin: 0.67em 0; }
|
||||
figcaption, figure, main { display: block; }
|
||||
figure { margin: 1em 40px; }
|
||||
hr { box-sizing: content-box; height: 0; overflow: visible; }
|
||||
pre { font-family: monospace, monospace; font-size: 1em; }
|
||||
a { background-color: transparent; -webkit-text-decoration-skip: objects; }
|
||||
a:active, a:hover { outline-width: 0; }
|
||||
abbr[title] { border-bottom: none; text-decoration: underline; text-decoration: underline dotted; }
|
||||
b, strong { font-weight: inherit; }
|
||||
b, strong { font-weight: bolder; }
|
||||
code, kbd, samp { font-family: monospace, monospace; font-size: 1em; }
|
||||
dfn { font-style: italic; }
|
||||
mark { background-color: #ff0; color: #000; }
|
||||
small { font-size: 80%; }
|
||||
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
|
||||
sub { bottom: -0.25em; }
|
||||
sup { top: -0.5em; }
|
||||
audio, video { display: inline-block; }
|
||||
audio:not([controls]) { display: none; height: 0; }
|
||||
img { border-style: none; }
|
||||
svg:not(:root) { overflow: hidden; }
|
||||
button, input, optgroup, select, textarea { font-family: sans-serif; font-size: 100%; line-height: 1.15; margin: 0; }
|
||||
button, input { overflow: visible; }
|
||||
button, select { text-transform: none; }
|
||||
button, html [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; }
|
||||
button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; }
|
||||
button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; }
|
||||
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
|
||||
legend { box-sizing: border-box; color: inherit; display: table; max-width: 100%; padding: 0; white-space: normal; }
|
||||
progress { display: inline-block; vertical-align: baseline; }
|
||||
textarea { overflow: auto; }
|
||||
[type="checkbox"], [type="radio"] { box-sizing: border-box; padding: 0; }
|
||||
[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; }
|
||||
[type="search"] { -webkit-appearance: textfield; outline-offset: -2px; }
|
||||
[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
|
||||
::-webkit-file-upload-button { -webkit-appearance: button; font: inherit; }
|
||||
details, menu { display: block; }
|
||||
summary { display: list-item; }
|
||||
canvas { display: inline-block; }
|
||||
template { display: none; }
|
||||
[hidden] { display: none; }
|
||||
/* Normalize.css <=============================== */
|
||||
|
||||
html { font-size: 62.5%; }
|
||||
|
||||
a { color: #3c8dbc; text-decoration: none; }
|
||||
a:hover { color: #72afda; text-decoration: underline; }
|
||||
b { color: rgb(68, 68, 68); }
|
||||
p { margin: 0; }
|
||||
|
||||
label, .buttons a {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
label, .buttons *:not([disabled]) { cursor: pointer; }
|
||||
|
||||
/* Touch device dark tap highlight */
|
||||
header h1 a, label, .buttons * { -webkit-tap-highlight-color: transparent; }
|
||||
|
||||
/* Webkit Focus Glow */
|
||||
textarea, input, button { outline: none; }
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Sans Pro";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local("Source Sans Pro Regular"), local("SourceSansPro-Regular"),
|
||||
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-regular.woff2") format("woff2"),
|
||||
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-regular.woff") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Source Sans Pro";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: local("Source Sans Pro Bold"), local("SourceSansPro-Bold"),
|
||||
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-700.woff2") format("woff2"),
|
||||
url("/admin/style/vendor/SourceSansPro/source-sans-pro-v13-latin-700.woff") format("woff");
|
||||
}
|
||||
|
||||
body {
|
||||
background: #dbdbdb url("/admin/img/boxed-bg.jpg") repeat fixed;
|
||||
color: #333;
|
||||
font: 1.4rem "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
line-height: 2.2rem;
|
||||
}
|
||||
|
||||
/* User is greeted with a splash page when browsing to Pi-hole IP address */
|
||||
#splashpage {
|
||||
background: #222;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#splashpage img { margin: 5px; width: 256px; }
|
||||
#splashpage b { color: inherit; }
|
||||
|
||||
#bpWrapper {
|
||||
margin: 0 auto;
|
||||
max-width: 1250px;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
header {
|
||||
background: #3c8dbc;
|
||||
display: table;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header h1, header h1 a, header .spc, header #bpAlt label {
|
||||
display: table-cell;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
height: 50px; /* Must match #bpAbout top value */
|
||||
}
|
||||
|
||||
h1 a {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 2rem;
|
||||
font-weight: 400;
|
||||
min-width: 230px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 a:hover, header #bpAlt:hover { background-color: rgba(0, 0, 0, 0.12); color: inherit; text-decoration: none; }
|
||||
|
||||
header .spc { width: 100%; }
|
||||
|
||||
header #bpAlt label {
|
||||
background: url("/admin/img/logo.svg") no-repeat center left 15px;
|
||||
background-size: 15px 23px;
|
||||
padding: 0 15px;
|
||||
text-indent: 30px;
|
||||
}
|
||||
|
||||
[type="checkbox"][id$="Toggle"] { display: none; }
|
||||
[type="checkbox"][id$="Toggle"]:checked ~ #bpAbout,
|
||||
[type="checkbox"][id$="Toggle"]:checked ~ #bpMoreInfo {
|
||||
display: block;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#pihole_card {
|
||||
width: 400px;
|
||||
height: auto;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
#pihole_card p, #pihole_card a {
|
||||
font-size: 13pt;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#pihole_logo_splash {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Click anywhere else on screen to hide #bpAbout */
|
||||
#bpAboutToggle:checked {
|
||||
display: block;
|
||||
height: 300px; /* VH Fallback */
|
||||
height: 100vh;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#bpAbout {
|
||||
background: #3c8dbc;
|
||||
border-bottom-left-radius: 5px;
|
||||
border: 1px solid #fff;
|
||||
border-right-width: 0;
|
||||
box-shadow: -1px 1px 1px rgba(0, 0, 0, 0.12);
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
font-size: 1.7rem;
|
||||
top: 50px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 280px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.aboutPH {
|
||||
box-sizing: border-box;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
display: block;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.aboutImg {
|
||||
background: url("/admin/img/logo.svg") no-repeat center;
|
||||
background-size: 90px 90px;
|
||||
height: 90px;
|
||||
margin: 0 auto;
|
||||
padding: 2px;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.aboutPH p { margin: 10px 0; }
|
||||
.aboutPH small { display: block; font-size: 1.2rem; }
|
||||
|
||||
.aboutLink {
|
||||
background: #fff;
|
||||
border-top: 1px solid #ddd;
|
||||
display: table;
|
||||
font-size: 1.4rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aboutLink a {
|
||||
display: table-cell;
|
||||
padding: 14px;
|
||||
min-width: 50%;
|
||||
}
|
||||
|
||||
main {
|
||||
background: #ecf0f5;
|
||||
font-size: 1.65rem;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#bpOutput {
|
||||
background: #00c0ef;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
color: #fff;
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 5px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#bpOutput::before {
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='7' height='14' viewBox='0 0 7 14'%3E%3Cpath fill='%23fff' d='M6 11a1.371 1.371 0 011 1v1a1.371 1.371 0 01-1 1H1a1.371 1.371 0 01-1-1v-1a1.371 1.371 0 011-1h1V8H1a1.371 1.371 0 01-1-1V6a1.371 1.371 0 011-1h3a1.371 1.371 0 011 1v5h1zM3.5 0A1.5 1.5 0 112 1.5 1.5 1.5 0 013.5 0z'/%3E%3C/svg%3E") no-repeat center left;
|
||||
display: block;
|
||||
font-size: 1.8rem;
|
||||
text-indent: 15px;
|
||||
}
|
||||
|
||||
#bpOutput.hidden { display: none; }
|
||||
#bpOutput.success { background: #00a65a; }
|
||||
#bpOutput.error { background: #dd4b39; }
|
||||
|
||||
.blockMsg, .flagMsg {
|
||||
font: 700 1.8rem Consolas, Courier, monospace;
|
||||
padding: 5px 10px 10px;
|
||||
text-indent: 15px;
|
||||
}
|
||||
|
||||
#bpHelpTxt { padding-bottom: 10px; }
|
||||
|
||||
.buttons {
|
||||
border-spacing: 5px 0;
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.buttons * {
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-sizing: content-box;
|
||||
display: table-cell;
|
||||
font-size: 1.65rem;
|
||||
margin-right: 5px;
|
||||
min-height: 20px;
|
||||
padding: 6px 12px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.buttons a:hover { text-decoration: none; }
|
||||
|
||||
/* Button hover dark overlay */
|
||||
.buttons *:not(input):not([disabled]):hover {
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1));
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Button active shadow inset */
|
||||
.buttons *:not([disabled]):not(input):active {
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
/* Input border color */
|
||||
.buttons *:not([disabled]):hover, .buttons input:focus {
|
||||
border-color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
#bpButtons * { width: 50%; color: #fff; }
|
||||
#bpBack { background-color: #00a65a; }
|
||||
#bpInfo { background-color: #3c8dbc; }
|
||||
#bpWhitelist { background-color: #dd4b39; }
|
||||
|
||||
#blockpage .buttons [type="password"][disabled] { color: rgba(0, 0, 0, 1); }
|
||||
#blockpage .buttons [disabled] { color: rgba(0, 0, 0, 0.55); background-color: #e3e3e3; }
|
||||
#blockpage .buttons [type="password"]:-ms-input-placeholder { color: rgba(51, 51, 51, 0.8); }
|
||||
|
||||
input[type="password"] { font-size: 1.5rem; }
|
||||
|
||||
@-webkit-keyframes slidein { from { max-height: 0; opacity: 0; } to { max-height: 300px; opacity: 1; } }
|
||||
|
||||
@keyframes slidein { from { max-height: 0; opacity: 0; } to { max-height: 300px; opacity: 1; } }
|
||||
#bpMoreToggle:checked ~ #bpMoreInfo { display: block; margin-top: 8px; -webkit-animation: slidein 0.05s linear; animation: slidein 0.05s linear; }
|
||||
#bpMoreInfo { display: none; margin-top: 10px; }
|
||||
|
||||
#bpQueryOutput {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.65rem;
|
||||
margin: 5px 0 0;
|
||||
overflow: auto;
|
||||
padding: 0 5px;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
#bpQueryOutput span { margin-right: 4px; }
|
||||
|
||||
#bpWLButtons { width: auto; margin-top: 10px; }
|
||||
#bpWLButtons * { display: inline-block; }
|
||||
#bpWLDomain { display: none; }
|
||||
#bpWLPassword { width: 160px; }
|
||||
#bpWhitelist { color: #fff; }
|
||||
|
||||
footer {
|
||||
background: #fff;
|
||||
border-top: 1px solid #d2d6de;
|
||||
color: #444;
|
||||
font: 1.2rem Consolas, Courier, monospace;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
/* Responsive Content */
|
||||
@media only screen and (max-width: 500px) {
|
||||
h1 a {
|
||||
font-size: 1.8rem;
|
||||
min-width: 170px;
|
||||
}
|
||||
|
||||
footer span::before {
|
||||
content: "Generated ";
|
||||
}
|
||||
|
||||
footer span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1251px) {
|
||||
#bpWrapper, footer {
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
||||
#bpAbout {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 400px) {
|
||||
#pihole_card {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#pihole_card p, #pihole_card a {
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 256px) {
|
||||
#pihole_logo_splash {
|
||||
width: 90% !important;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait fbcon=map:10 fbcon=font:VGA8x8 consoleblank=0
|
||||
@@ -1,17 +0,0 @@
|
||||
# CONFIGURATION FILE FOR SETUPCON
|
||||
|
||||
# Consult the console-setup(5) manual page.
|
||||
|
||||
ACTIVE_CONSOLES="/dev/tty[1-6]"
|
||||
|
||||
CHARMAP="UTF-8"
|
||||
|
||||
# For best results with the Adafruit 2.8 LCD and Pi-hole's chronometer
|
||||
CODESET="guess"
|
||||
FONTFACE="Terminus"
|
||||
FONTSIZE="10x20"
|
||||
|
||||
VIDEOMODE=
|
||||
|
||||
# The following is an example how to use a braille font
|
||||
# FONT='lat9w-08.psf.gz brl-8x8.psf'
|
||||
@@ -1,417 +0,0 @@
|
||||
<?php
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
// Sanitize SERVER_NAME output
|
||||
$serverName = htmlspecialchars($_SERVER["SERVER_NAME"]);
|
||||
// Remove external ipv6 brackets if any
|
||||
$serverName = preg_replace('/^\[(.*)\]$/', '${1}', $serverName);
|
||||
|
||||
if (!is_file("/etc/pihole/setupVars.conf"))
|
||||
die("[ERROR] File not found: <code>/etc/pihole/setupVars.conf</code>");
|
||||
|
||||
// Get values from setupVars.conf
|
||||
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||
$svPasswd = !empty($setupVars["WEBPASSWORD"]);
|
||||
$svEmail = (!empty($setupVars["ADMIN_EMAIL"]) && filter_var($setupVars["ADMIN_EMAIL"], FILTER_VALIDATE_EMAIL)) ? $setupVars["ADMIN_EMAIL"] : "";
|
||||
unset($setupVars);
|
||||
|
||||
// Set landing page location, found within /var/www/html/
|
||||
$landPage = "../landing.php";
|
||||
|
||||
// Define array for hostnames to be accepted as self address for splash page
|
||||
$authorizedHosts = [ "localhost" ];
|
||||
if (!empty($_SERVER["FQDN"])) {
|
||||
// If setenv.add-environment = ("fqdn" => "true") is configured in lighttpd,
|
||||
// append $serverName to $authorizedHosts
|
||||
array_push($authorizedHosts, $serverName);
|
||||
} else if (!empty($_SERVER["VIRTUAL_HOST"])) {
|
||||
// Append virtual hostname to $authorizedHosts
|
||||
array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]);
|
||||
}
|
||||
|
||||
// Set which extension types render as Block Page (Including "" for index.ext)
|
||||
$validExtTypes = array("asp", "htm", "html", "php", "rss", "xml", "");
|
||||
|
||||
// Get extension of current URL
|
||||
$currentUrlExt = pathinfo($_SERVER["REQUEST_URI"], PATHINFO_EXTENSION);
|
||||
|
||||
// Set mobile friendly viewport
|
||||
$viewPort = '<meta name="viewport" content="width=device-width, initial-scale=1">';
|
||||
|
||||
// Set response header
|
||||
function setHeader($type = "x") {
|
||||
header("X-Pi-hole: A black hole for Internet advertisements.");
|
||||
if (isset($type) && $type === "js") header("Content-Type: application/javascript");
|
||||
}
|
||||
|
||||
// Determine block page type
|
||||
if ($serverName === "pi.hole"
|
||||
|| (!empty($_SERVER["VIRTUAL_HOST"]) && $serverName === $_SERVER["VIRTUAL_HOST"])) {
|
||||
// Redirect to Web Interface
|
||||
exit(header("Location: /admin"));
|
||||
} elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) {
|
||||
// When directly browsing via IP or authorized hostname
|
||||
// Render splash/landing page based off presence of $landPage file
|
||||
// Unset variables so as to not be included in $landPage or $splashPage
|
||||
unset($svPasswd, $svEmail, $authorizedHosts, $validExtTypes, $currentUrlExt);
|
||||
// If $landPage file is present
|
||||
if (is_file(getcwd()."/$landPage")) {
|
||||
unset($serverName, $viewPort); // unset extra variables not to be included in $landpage
|
||||
include $landPage;
|
||||
exit();
|
||||
}
|
||||
// If $landPage file was not present, Set Splash Page output
|
||||
$splashPage = <<<EOT
|
||||
<!doctype html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
$viewPort
|
||||
<title>● $serverName</title>
|
||||
<link rel='stylesheet' href='/pihole/blockingpage.css'>
|
||||
<link rel='shortcut icon' href='/admin/img/favicons/favicon.ico' type='image/x-icon'>
|
||||
</head>
|
||||
<body id='splashpage'>
|
||||
<div id="pihole_card">
|
||||
<img src='/admin/img/logo.svg' alt='Pi-hole logo' id="pihole_logo_splash" />
|
||||
<p>Pi-<strong>hole</strong>: Your black hole for Internet advertisements</p>
|
||||
<a href='/admin'>Did you mean to go to the admin panel?</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
EOT;
|
||||
exit($splashPage);
|
||||
} elseif ($currentUrlExt === "js") {
|
||||
// Serve Pi-hole JavaScript for blocked domains requesting JS
|
||||
exit(setHeader("js").'var x = "Pi-hole: A black hole for Internet advertisements."');
|
||||
} elseif (strpos($_SERVER["REQUEST_URI"], "?") !== FALSE && isset($_SERVER["HTTP_REFERER"])) {
|
||||
// Serve blank image upon receiving REQUEST_URI w/ query string & HTTP_REFERRER
|
||||
// e.g: An iframe of a blocked domain
|
||||
exit(setHeader().'<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"><script>window.close();</script>
|
||||
</head>
|
||||
<body>
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=">
|
||||
</body>
|
||||
</html>');
|
||||
} elseif (!in_array($currentUrlExt, $validExtTypes) || substr_count($_SERVER["REQUEST_URI"], "?")) {
|
||||
// Serve SVG upon receiving non $validExtTypes URL extension or query string
|
||||
// e.g: Not an iframe of a blocked domain, such as when browsing to a file/query directly
|
||||
// QoL addition: Allow the SVG to be clicked on in order to quickly show the full Block Page
|
||||
$blockImg = '<a href="/">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="110" height="16">
|
||||
<circle cx="8" cy="8" r="7" fill="none" stroke="rgba(152,2,2,.5)" stroke-width="2"/>
|
||||
<path fill="rgba(152,2,2,.5)" d="M11.526 3.04l1.414 1.415-8.485 8.485-1.414-1.414z"/>
|
||||
<text x="19.3" y="12" opacity=".3" style="font:11px Arial">
|
||||
Blocked by Pi-hole
|
||||
</text>
|
||||
</svg>
|
||||
</a>';
|
||||
exit(setHeader()."<!doctype html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
$viewPort
|
||||
</head>
|
||||
<body>$blockImg</body>
|
||||
</html>");
|
||||
}
|
||||
|
||||
/* Start processing Block Page from here */
|
||||
|
||||
// Define admin email address text based off $svEmail presence
|
||||
$bpAskAdmin = !empty($svEmail) ? '<a href="mailto:'.$svEmail.'?subject=Site Blocked: '.$serverName.'"></a>' : "<span/>";
|
||||
|
||||
// Get possible non-standard location of FTL's database
|
||||
$FTLsettings = parse_ini_file("/etc/pihole/pihole-FTL.conf");
|
||||
if (isset($FTLsettings["GRAVITYDB"])) {
|
||||
$gravityDBFile = $FTLsettings["GRAVITYDB"];
|
||||
} else {
|
||||
$gravityDBFile = "/etc/pihole/gravity.db";
|
||||
}
|
||||
|
||||
// Connect to gravity.db
|
||||
try {
|
||||
$db = new SQLite3($gravityDBFile, SQLITE3_OPEN_READONLY);
|
||||
} catch (Exception $exception) {
|
||||
die("[ERROR]: Failed to connect to gravity.db");
|
||||
}
|
||||
|
||||
// Get all adlist addresses
|
||||
$adlistResults = $db->query("SELECT address FROM vw_adlist");
|
||||
$adlistsUrls = array();
|
||||
while ($row = $adlistResults->fetchArray()) {
|
||||
array_push($adlistsUrls, $row[0]);
|
||||
}
|
||||
|
||||
if (empty($adlistsUrls))
|
||||
die("[ERROR]: There are no adlists enabled");
|
||||
|
||||
// Get total number of blocklists (Including Whitelist, Blacklist & Wildcard lists)
|
||||
$adlistsCount = count($adlistsUrls) + 3;
|
||||
|
||||
// Set query timeout
|
||||
ini_set("default_socket_timeout", 3);
|
||||
|
||||
// Logic for querying blocklists
|
||||
function queryAds($serverName) {
|
||||
// Determine the time it takes while querying adlists
|
||||
$preQueryTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
|
||||
|
||||
// Determine which protocol should be used
|
||||
$protocol = "http";
|
||||
if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ||
|
||||
(isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] === 'https') ||
|
||||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
|
||||
) {
|
||||
$protocol = "https";
|
||||
}
|
||||
|
||||
// Format the URL
|
||||
$queryAdsURL = sprintf(
|
||||
"%s://127.0.0.1:%s/admin/scripts/pi-hole/php/queryads.php?domain=%s&bp",
|
||||
$protocol,
|
||||
$_SERVER["SERVER_PORT"],
|
||||
$serverName
|
||||
);
|
||||
|
||||
// Request the file and receive the response
|
||||
$queryAdsFile = file($queryAdsURL, FILE_IGNORE_NEW_LINES);
|
||||
|
||||
// $queryAdsFile must be an array (to avoid PHP 8.0+ error)
|
||||
if (is_array($queryAdsFile)) {
|
||||
$queryAds = array_values(array_filter(preg_replace("/data:\s+/", "", $queryAdsFile)));
|
||||
} else {
|
||||
// if not an array, return an error message
|
||||
return array("0" => "error", "1" => "<br>(".gettype($queryAdsFile).")<br>".print_r($queryAdsFile, true));
|
||||
}
|
||||
|
||||
$queryTime = sprintf("%.0f", (microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"]) - $preQueryTime);
|
||||
|
||||
// Exception Handling
|
||||
try {
|
||||
// Define Exceptions
|
||||
if (strpos($queryAds[0], "No exact results") !== FALSE) {
|
||||
// Return "none" into $queryAds array
|
||||
return array("0" => "none");
|
||||
} else if ($queryTime >= ini_get("default_socket_timeout")) {
|
||||
// Connection Timeout
|
||||
throw new Exception ("Connection timeout (".ini_get("default_socket_timeout")."s)");
|
||||
} elseif (!strpos($queryAds[0], ".") !== false) {
|
||||
// Unknown $queryAds output
|
||||
throw new Exception ("Unhandled error message (<code>$queryAds[0]</code>)");
|
||||
}
|
||||
return $queryAds;
|
||||
} catch (Exception $e) {
|
||||
// Return exception as array
|
||||
return array("0" => "error", "1" => $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Get results of queryads.php exact search
|
||||
$queryAds = queryAds($serverName);
|
||||
|
||||
// Pass error through to Block Page
|
||||
if ($queryAds[0] === "error")
|
||||
die("[ERROR]: Unable to parse results from <i>queryads.php</i>: <code>".$queryAds[1]."</code>");
|
||||
|
||||
// Count total number of matching blocklists
|
||||
$featuredTotal = count($queryAds);
|
||||
|
||||
// Place results into key => value array
|
||||
$queryResults = null;
|
||||
foreach ($queryAds as $str) {
|
||||
$value = explode(" ", $str);
|
||||
@$queryResults[$value[0]] .= "$value[1]";
|
||||
}
|
||||
|
||||
// Determine if domain has been blacklisted, whitelisted, wildcarded or CNAME blocked
|
||||
if (strpos($queryAds[0], "blacklist") !== FALSE) {
|
||||
$notableFlagClass = "blacklist";
|
||||
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||
} elseif (strpos($queryAds[0], "whitelist") !== FALSE) {
|
||||
$notableFlagClass = "noblock";
|
||||
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||
$wlInfo = "recentwl";
|
||||
} elseif (strpos($queryAds[0], "wildcard") !== FALSE) {
|
||||
$notableFlagClass = "wildcard";
|
||||
$adlistsUrls = array("π" => substr($queryAds[0], 2));
|
||||
} elseif ($queryAds[0] === "none") {
|
||||
$featuredTotal = "0";
|
||||
$notableFlagClass = "noblock";
|
||||
|
||||
// QoL addition: Determine appropriate info message if CNAME exists
|
||||
// Suggests to the user that $serverName has a CNAME (alias) that may be blocked
|
||||
$dnsRecord = dns_get_record("$serverName")[0];
|
||||
if (array_key_exists("target", $dnsRecord)) {
|
||||
$wlInfo = $dnsRecord['target'];
|
||||
} else {
|
||||
$wlInfo = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// Set #bpOutput notification
|
||||
$wlOutputClass = (isset($wlInfo) && $wlInfo === "recentwl") ? $wlInfo : "hidden";
|
||||
$wlOutput = (isset($wlInfo) && $wlInfo !== "recentwl") ? "<a href='http://$wlInfo'>$wlInfo</a>" : "";
|
||||
|
||||
// Get Pi-hole Core version
|
||||
$phVersion = exec("cd /etc/.pihole/ && git describe --long --tags");
|
||||
|
||||
// Print $execTime on development branches
|
||||
// Testing for - is marginally faster than "git rev-parse --abbrev-ref HEAD"
|
||||
if (explode("-", $phVersion)[1] != "0")
|
||||
$execTime = microtime(true)-$_SERVER["REQUEST_TIME_FLOAT"];
|
||||
|
||||
// Please Note: Text is added via CSS to allow an admin to provide a localized
|
||||
// language without the need to edit this file
|
||||
|
||||
setHeader();
|
||||
?>
|
||||
<!doctype html>
|
||||
<!-- Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL. -->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<?=$viewPort ?>
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
<meta http-equiv="x-dns-prefetch-control" content="off">
|
||||
<link rel="stylesheet" href="pihole/blockingpage.css">
|
||||
<link rel="shortcut icon" href="admin/img/favicons/favicon.ico" type="image/x-icon">
|
||||
<title>● <?=$serverName ?></title>
|
||||
<script src="admin/scripts/vendor/jquery.min.js"></script>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
<?php
|
||||
// Remove href fallback from "Back to safety" button
|
||||
if ($featuredTotal > 0) {
|
||||
echo '$("#bpBack").removeAttr("href");';
|
||||
|
||||
// Enable whitelisting if JS is available
|
||||
echo '$("#bpWhitelist").prop("disabled", false);';
|
||||
|
||||
// Enable password input if necessary
|
||||
if (!empty($svPasswd)) {
|
||||
echo '$("#bpWLPassword").attr("placeholder", "Password");';
|
||||
echo '$("#bpWLPassword").prop("disabled", false);';
|
||||
}
|
||||
// Otherwise hide the input
|
||||
else {
|
||||
echo '$("#bpWLPassword").hide();';
|
||||
}
|
||||
}
|
||||
?>
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body id="blockpage"><div id="bpWrapper">
|
||||
<header>
|
||||
<h1 id="bpTitle">
|
||||
<a class="title" href="/"><?php //Website Blocked ?></a>
|
||||
</h1>
|
||||
<div class="spc"></div>
|
||||
|
||||
<input id="bpAboutToggle" type="checkbox">
|
||||
<div id="bpAbout">
|
||||
<div class="aboutPH">
|
||||
<div class="aboutImg"></div>
|
||||
<p>Open Source Ad Blocker
|
||||
<small>Designed for Raspberry Pi</small>
|
||||
</p>
|
||||
</div>
|
||||
<div class="aboutLink">
|
||||
<a class="linkPH" href="https://docs.pi-hole.net/"><?php //About PH ?></a>
|
||||
<?php if (!empty($svEmail)) echo '<a class="linkEmail" href="mailto:'.$svEmail.'"></a>'; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="bpAlt">
|
||||
<label class="altBtn" for="bpAboutToggle"><?php //Why am I here? ?></label>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div id="bpOutput" class="<?=$wlOutputClass ?>"><?=$wlOutput ?></div>
|
||||
<div id="bpBlock">
|
||||
<p class="blockMsg"><?=$serverName ?></p>
|
||||
</div>
|
||||
<?php if(isset($notableFlagClass)) { ?>
|
||||
<div id="bpFlag">
|
||||
<p class="flagMsg <?=$notableFlagClass ?>"></p>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<div id="bpHelpTxt"><?=$bpAskAdmin ?></div>
|
||||
<div id="bpButtons" class="buttons">
|
||||
<a id="bpBack" onclick="javascript:history.back()" href="about:home"></a>
|
||||
<?php if ($featuredTotal > 0) echo '<label id="bpInfo" for="bpMoreToggle"></label>'; ?>
|
||||
</div>
|
||||
<input id="bpMoreToggle" type="checkbox">
|
||||
<div id="bpMoreInfo">
|
||||
<span id="bpFoundIn"><span><?=$featuredTotal ?></span><?=$adlistsCount ?></span>
|
||||
<pre id='bpQueryOutput'><?php if ($featuredTotal > 0) foreach ($queryResults as $num => $value) { echo "<span>[$num]:</span>$adlistsUrls[$num]\n"; } ?></pre>
|
||||
|
||||
<form id="bpWLButtons" class="buttons">
|
||||
<input id="bpWLDomain" type="text" value="<?=$serverName ?>" disabled>
|
||||
<input id="bpWLPassword" type="password" placeholder="JavaScript disabled" disabled>
|
||||
<button id="bpWhitelist" type="button" disabled></button>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer><span><?=date("l g:i A, F dS"); ?>.</span> Pi-hole <?=$phVersion ?> (<?=gethostname()."/".$_SERVER["SERVER_ADDR"]; if (isset($execTime)) printf("/%.2fs", $execTime); ?>)</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function add() {
|
||||
$("#bpOutput").removeClass("hidden error exception");
|
||||
$("#bpOutput").addClass("add");
|
||||
var domain = "<?=$serverName ?>";
|
||||
var pw = $("#bpWLPassword");
|
||||
if(domain.length === 0) {
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: "/admin/scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain, "list":"white", "pw":pw.val()},
|
||||
success: function(response) {
|
||||
if(response.indexOf("Pi-hole blocking") !== -1) {
|
||||
setTimeout(function(){window.location.reload(1);}, 10000);
|
||||
$("#bpOutput").removeClass("add");
|
||||
$("#bpOutput").addClass("success");
|
||||
$("#bpOutput").html("");
|
||||
} else {
|
||||
$("#bpOutput").removeClass("add");
|
||||
$("#bpOutput").addClass("error");
|
||||
$("#bpOutput").html(""+response+"");
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
$("#bpOutput").removeClass("add");
|
||||
$("#bpOutput").addClass("exception");
|
||||
$("#bpOutput").html("");
|
||||
}
|
||||
});
|
||||
}
|
||||
<?php if ($featuredTotal > 0) { ?>
|
||||
$(document).keypress(function(e) {
|
||||
if(e.which === 13 && $("#bpWLPassword").is(":focus")) {
|
||||
add();
|
||||
}
|
||||
});
|
||||
$("#bpWhitelist").on("click", function() {
|
||||
add();
|
||||
});
|
||||
<?php } ?>
|
||||
</script>
|
||||
</body></html>
|
||||
@@ -7,17 +7,18 @@
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
###############################################################################
|
||||
# FILE AUTOMATICALLY OVERWRITTEN BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
|
||||
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
|
||||
# #
|
||||
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE: #
|
||||
# /etc/lighttpd/external.conf #
|
||||
###############################################################################
|
||||
###################################################################################################
|
||||
# IF THIS HEADER EXISTS, THE FILE WILL BE OVERWRITTEN BY PI-HOLE'S UPDATE PROCEDURE. #
|
||||
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON THE NEXT UPDATE UNLESS YOU REMOVE THIS HEADER #
|
||||
# #
|
||||
# ENSURE THAT YOU DO NOT REMOVE THE REQUIRED LINE: #
|
||||
# #
|
||||
# include "/etc/lighttpd/conf-enabled/*.conf" #
|
||||
# #
|
||||
###################################################################################################
|
||||
|
||||
server.modules = (
|
||||
"mod_access",
|
||||
"mod_accesslog",
|
||||
"mod_auth",
|
||||
"mod_expire",
|
||||
"mod_redirect",
|
||||
@@ -26,15 +27,14 @@ server.modules = (
|
||||
)
|
||||
|
||||
server.document-root = "/var/www/html"
|
||||
server.error-handler-404 = "/pihole/index.php"
|
||||
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
|
||||
server.errorlog = "/var/log/lighttpd/error-pihole.log"
|
||||
server.pid-file = "/run/lighttpd.pid"
|
||||
server.username = "www-data"
|
||||
server.groupname = "www-data"
|
||||
# For lighttpd version 1.4.46 or above, the port can be overwritten in `/etc/lighttpd/external.conf` using the := operator
|
||||
# e.g. server.port := 8000
|
||||
server.port = 80
|
||||
accesslog.filename = "/var/log/lighttpd/access-pihole.log"
|
||||
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||
|
||||
# Allow streaming response
|
||||
# reference: https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_stream-response-bodyDetails
|
||||
@@ -65,37 +65,9 @@ mimetype.assign = (
|
||||
".woff2" => "font/woff2"
|
||||
)
|
||||
|
||||
# Add user chosen options held in external file
|
||||
# This uses include_shell instead of an include wildcard for compatibility
|
||||
include_shell "cat external.conf 2>/dev/null"
|
||||
# Add user chosen options held in (optional) external file
|
||||
include "external*.conf"
|
||||
|
||||
# default listening port for IPv6 falls back to the IPv4 port
|
||||
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
|
||||
# Prevent Lighttpd from enabling Let's Encrypt SSL for every blocked domain
|
||||
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
|
||||
include_shell "find /etc/lighttpd/conf-enabled -name '*.conf' -a ! -name 'letsencrypt.conf' -printf 'include \"%p\"\n' 2>/dev/null"
|
||||
|
||||
# If the URL starts with /admin, it is the Web interface
|
||||
$HTTP["url"] =~ "^/admin/" {
|
||||
# Create a response header for debugging using curl -I
|
||||
setenv.add-response-header = (
|
||||
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||
"X-Frame-Options" => "DENY"
|
||||
)
|
||||
}
|
||||
|
||||
# Block . files from being served, such as .git, .github, .gitignore
|
||||
$HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
|
||||
# allow teleporter and API qr code iframe on settings page
|
||||
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||
}
|
||||
}
|
||||
|
||||
# Default expire header
|
||||
expire.url = ( "" => "access plus 0 seconds" )
|
||||
include "/etc/lighttpd/conf-enabled/*.conf"
|
||||
|
||||
@@ -7,13 +7,15 @@
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
###############################################################################
|
||||
# FILE AUTOMATICALLY OVERWRITTEN BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
|
||||
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
|
||||
# #
|
||||
# CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE: #
|
||||
# /etc/lighttpd/external.conf #
|
||||
###############################################################################
|
||||
###################################################################################################
|
||||
# IF THIS HEADER EXISTS, THE FILE WILL BE OVERWRITTEN BY PI-HOLE'S UPDATE PROCEDURE. #
|
||||
# ANY CHANGES MADE TO THIS FILE WILL BE LOST ON THE NEXT UPDATE UNLESS YOU REMOVE THIS HEADER #
|
||||
# #
|
||||
# ENSURE THAT YOU DO NOT REMOVE THE REQUIRED LINE: #
|
||||
# #
|
||||
# include "/etc/lighttpd/conf.d/pihole-admin.conf" #
|
||||
# #
|
||||
###################################################################################################
|
||||
|
||||
server.modules = (
|
||||
"mod_access",
|
||||
@@ -27,15 +29,14 @@ server.modules = (
|
||||
)
|
||||
|
||||
server.document-root = "/var/www/html"
|
||||
server.error-handler-404 = "/pihole/index.php"
|
||||
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
|
||||
server.errorlog = "/var/log/lighttpd/error-pihole.log"
|
||||
server.pid-file = "/run/lighttpd.pid"
|
||||
server.username = "lighttpd"
|
||||
server.groupname = "lighttpd"
|
||||
# For lighttpd version 1.4.46 or above, the port can be overwritten in `/etc/lighttpd/external.conf` using the := operator
|
||||
# e.g. server.port := 8000
|
||||
server.port = 80
|
||||
accesslog.filename = "/var/log/lighttpd/access-pihole.log"
|
||||
accesslog.format = "%{%s}t|%V|%r|%s|%b"
|
||||
|
||||
# Allow streaming response
|
||||
# reference: https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_stream-response-bodyDetails
|
||||
@@ -66,9 +67,8 @@ mimetype.assign = (
|
||||
".woff2" => "font/woff2"
|
||||
)
|
||||
|
||||
# Add user chosen options held in external file
|
||||
# This uses include_shell instead of an include wildcard for compatibility
|
||||
include_shell "cat external.conf 2>/dev/null"
|
||||
# Add user chosen options held in (optional) external file
|
||||
include "external*.conf"
|
||||
|
||||
# default listening port for IPv6 falls back to the IPv4 port
|
||||
#include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
|
||||
@@ -84,26 +84,4 @@ fastcgi.server = (
|
||||
)
|
||||
)
|
||||
|
||||
# If the URL starts with /admin, it is the Web interface
|
||||
$HTTP["url"] =~ "^/admin/" {
|
||||
# Create a response header for debugging using curl -I
|
||||
setenv.add-response-header = (
|
||||
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||
"X-Frame-Options" => "DENY"
|
||||
)
|
||||
}
|
||||
|
||||
# Block . files from being served, such as .git, .github, .gitignore
|
||||
$HTTP["url"] =~ "^/admin/\.(.*)" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
|
||||
# allow teleporter and API qr code iframe on settings page
|
||||
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||
setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||
}
|
||||
}
|
||||
|
||||
# Default expire header
|
||||
expire.url = ( "" => "access plus 0 seconds" )
|
||||
include "/etc/lighttpd/conf.d/pihole-admin.conf"
|
||||
|
||||
82
advanced/pihole-admin.conf
Normal file
82
advanced/pihole-admin.conf
Normal file
@@ -0,0 +1,82 @@
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
#
|
||||
# Lighttpd config for Pi-hole
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
###############################################################################
|
||||
# FILE AUTOMATICALLY OVERWRITTEN BY PI-HOLE INSTALL/UPDATE PROCEDURE. #
|
||||
# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE #
|
||||
###############################################################################
|
||||
|
||||
server.errorlog := "/var/log/lighttpd/error-pihole.log"
|
||||
|
||||
$HTTP["url"] =~ "^/admin/" {
|
||||
server.document-root = "/var/www/html"
|
||||
server.stream-response-body = 1
|
||||
accesslog.filename = "/var/log/lighttpd/access-pihole.log"
|
||||
accesslog.format = "%{%s}t|%h|%V|%r|%s|%b"
|
||||
|
||||
fastcgi.server = (
|
||||
".php" => (
|
||||
"localhost" => (
|
||||
"socket" => "/run/lighttpd/pihole-php-fastcgi.socket",
|
||||
"bin-path" => "/usr/bin/php-cgi",
|
||||
"min-procs" => 1,
|
||||
"max-procs" => 1,
|
||||
"bin-environment" => (
|
||||
"PHP_FCGI_CHILDREN" => "4",
|
||||
"PHP_FCGI_MAX_REQUESTS" => "10000",
|
||||
),
|
||||
"bin-copy-environment" => (
|
||||
"PATH", "SHELL", "USER"
|
||||
),
|
||||
"broken-scriptfilename" => "enable",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# X-Pi-hole is a response header for debugging using curl -I
|
||||
# X-Frame-Options prevents clickjacking attacks and helps ensure your content is not embedded into other sites via < frame >, < iframe > or < object >.
|
||||
# X-XSS-Protection sets the configuration for the cross-site scripting filters built into most browsers. This is important because it tells the browser to block the response if a malicious script has been inserted from a user input. (deprecated; disabled)
|
||||
# X-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. This is important because the browser will only load external resources if their content-type matches what is expected, and not malicious hidden code.
|
||||
# Content-Security-Policy tells the browser where resources are allowed to be loaded and if it’s allowed to parse/run inline styles or Javascript. This is important because it prevents content injection attacks, such as Cross Site Scripting (XSS).
|
||||
# X-Permitted-Cross-Domain-Policies is an XML document that grants a web client, such as Adobe Flash Player or Adobe Acrobat (though not necessarily limited to these), permission to handle data across domains.
|
||||
# Referrer-Policy allows control/restriction of the amount of information present in the referral header for links away from your page—the URL path or even if the header is sent at all.
|
||||
setenv.add-response-header = (
|
||||
"X-Pi-hole" => "The Pi-hole Web interface is working!",
|
||||
"X-Frame-Options" => "DENY",
|
||||
"X-XSS-Protection" => "0",
|
||||
"X-Content-Type-Options" => "nosniff",
|
||||
"Content-Security-Policy" => "default-src 'self' 'unsafe-inline';",
|
||||
"X-Permitted-Cross-Domain-Policies" => "none",
|
||||
"Referrer-Policy" => "same-origin"
|
||||
)
|
||||
|
||||
# Block . files from being served, such as .git, .github, .gitignore
|
||||
$HTTP["url"] =~ "^/admin/\." {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
|
||||
# allow teleporter and API qr code iframe on settings page
|
||||
$HTTP["url"] =~ "/(teleporter|api_token)\.php$" {
|
||||
$HTTP["referer"] =~ "/admin/settings\.php" {
|
||||
setenv.set-response-header = ( "X-Frame-Options" => "SAMEORIGIN" )
|
||||
}
|
||||
}
|
||||
}
|
||||
else $HTTP["url"] == "/admin" {
|
||||
url.redirect = ("" => "/admin/")
|
||||
}
|
||||
|
||||
$HTTP["host"] == "pi.hole" {
|
||||
$HTTP["url"] == "/" {
|
||||
url.redirect = ("" => "/admin/")
|
||||
}
|
||||
}
|
||||
|
||||
# (keep this on one line for basic-install.sh filtering during install)
|
||||
server.modules += ( "mod_access", "mod_accesslog", "mod_redirect", "mod_fastcgi", "mod_setenv" )
|
||||
@@ -82,7 +82,7 @@ PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update versi
|
||||
PI_HOLE_INSTALL_DIR="/opt/pihole"
|
||||
PI_HOLE_CONFIG_DIR="/etc/pihole"
|
||||
PI_HOLE_BIN_DIR="/usr/local/bin"
|
||||
PI_HOLE_BLOCKPAGE_DIR="${webroot}/pihole"
|
||||
FTL_CONFIG_FILE="${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf"
|
||||
if [ -z "$useUpdateVars" ]; then
|
||||
useUpdateVars=false
|
||||
fi
|
||||
@@ -330,7 +330,7 @@ package_manager_detect() {
|
||||
# Packages required to run this install script (stored as an array)
|
||||
INSTALLER_DEPS=(git iproute2 dialog ca-certificates)
|
||||
# Packages required to run Pi-hole (stored as an array)
|
||||
PIHOLE_DEPS=(cron curl iputils-ping psmisc sudo unzip idn2 libcap2-bin dns-root-data libcap2 netcat-openbsd procps)
|
||||
PIHOLE_DEPS=(cron curl iputils-ping psmisc sudo unzip idn2 libcap2-bin dns-root-data libcap2 netcat-openbsd procps jq)
|
||||
# Packages required for the Web admin interface (stored as an array)
|
||||
# It's useful to separate this from Pi-hole, since the two repos are also setup separately
|
||||
PIHOLE_WEB_DEPS=(lighttpd "${phpVer}-common" "${phpVer}-cgi" "${phpVer}-sqlite3" "${phpVer}-xml" "${phpVer}-intl")
|
||||
@@ -357,15 +357,30 @@ package_manager_detect() {
|
||||
# These variable names match the ones for apt-get. See above for an explanation of what they are for.
|
||||
PKG_INSTALL=("${PKG_MANAGER}" install -y)
|
||||
# CentOS package manager returns 100 when there are packages to update so we need to || true to prevent the script from exiting.
|
||||
PKG_COUNT="${PKG_MANAGER} check-update | egrep '(.i686|.x86|.noarch|.arm|.src)' | wc -l || true"
|
||||
PKG_COUNT="${PKG_MANAGER} check-update | grep -E '(.i686|.x86|.noarch|.arm|.src)' | wc -l || true"
|
||||
OS_CHECK_DEPS=(grep bind-utils)
|
||||
INSTALLER_DEPS=(git dialog iproute newt procps-ng which chkconfig ca-certificates)
|
||||
PIHOLE_DEPS=(cronie curl findutils sudo unzip libidn2 psmisc libcap nmap-ncat)
|
||||
INSTALLER_DEPS=(git dialog iproute newt procps-ng chkconfig ca-certificates)
|
||||
PIHOLE_DEPS=(cronie curl findutils sudo unzip libidn2 psmisc libcap nmap-ncat jq)
|
||||
PIHOLE_WEB_DEPS=(lighttpd lighttpd-fastcgi php-common php-cli php-pdo php-xml php-json php-intl)
|
||||
LIGHTTPD_USER="lighttpd"
|
||||
LIGHTTPD_GROUP="lighttpd"
|
||||
LIGHTTPD_CFG="lighttpd.conf.fedora"
|
||||
|
||||
# If the host OS is centos (or a derivative), epel is required for lighttpd
|
||||
if ! grep -qiE 'fedora|fedberry' /etc/redhat-release; then
|
||||
if rpm -qa | grep -qi 'epel'; then
|
||||
printf " %b EPEL repository already installed\\n" "${TICK}"
|
||||
else
|
||||
local RH_RELEASE EPEL_PKG
|
||||
# EPEL not already installed, add it based on the release version
|
||||
RH_RELEASE=$(grep -oP '(?<= )[0-9]+(?=\.?)' /etc/redhat-release)
|
||||
EPEL_PKG="https://dl.fedoraproject.org/pub/epel/epel-release-latest-${RH_RELEASE}.noarch.rpm"
|
||||
printf " %b Enabling EPEL package repository (https://fedoraproject.org/wiki/EPEL)\\n" "${INFO}"
|
||||
"${PKG_INSTALL[@]}" "${EPEL_PKG}"
|
||||
printf " %b Installed %s\\n" "${TICK}" "${EPEL_PKG}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If neither apt-get or yum/dnf package managers were found
|
||||
else
|
||||
# we cannot install required packages
|
||||
@@ -375,144 +390,6 @@ package_manager_detect() {
|
||||
fi
|
||||
}
|
||||
|
||||
select_rpm_php(){
|
||||
# If the host OS is Fedora,
|
||||
if grep -qiE 'fedora|fedberry' /etc/redhat-release; then
|
||||
# all required packages should be available by default with the latest fedora release
|
||||
: # continue
|
||||
# or if host OS is CentOS,
|
||||
elif grep -qiE 'centos|scientific' /etc/redhat-release; then
|
||||
# Pi-Hole currently supports CentOS 7+ with PHP7+
|
||||
SUPPORTED_CENTOS_VERSION=7
|
||||
SUPPORTED_CENTOS_PHP_VERSION=7
|
||||
# Check current CentOS major release version
|
||||
CURRENT_CENTOS_VERSION=$(grep -oP '(?<= )[0-9]+(?=\.?)' /etc/redhat-release)
|
||||
# Check if CentOS version is supported
|
||||
if [[ $CURRENT_CENTOS_VERSION -lt $SUPPORTED_CENTOS_VERSION ]]; then
|
||||
printf " %b CentOS %s is not supported.\\n" "${CROSS}" "${CURRENT_CENTOS_VERSION}"
|
||||
printf " Please update to CentOS release %s or later.\\n" "${SUPPORTED_CENTOS_VERSION}"
|
||||
# exit the installer
|
||||
exit
|
||||
fi
|
||||
# php-json is not required on CentOS 7 as it is already compiled into php
|
||||
# verifiy via `php -m | grep json`
|
||||
if [[ $CURRENT_CENTOS_VERSION -eq 7 ]]; then
|
||||
# create a temporary array as arrays are not designed for use as mutable data structures
|
||||
CENTOS7_PIHOLE_WEB_DEPS=()
|
||||
for i in "${!PIHOLE_WEB_DEPS[@]}"; do
|
||||
if [[ ${PIHOLE_WEB_DEPS[i]} != "php-json" ]]; then
|
||||
CENTOS7_PIHOLE_WEB_DEPS+=( "${PIHOLE_WEB_DEPS[i]}" )
|
||||
fi
|
||||
done
|
||||
# re-assign the clean dependency array back to PIHOLE_WEB_DEPS
|
||||
PIHOLE_WEB_DEPS=("${CENTOS7_PIHOLE_WEB_DEPS[@]}")
|
||||
unset CENTOS7_PIHOLE_WEB_DEPS
|
||||
fi
|
||||
|
||||
if rpm -qa | grep -qi 'epel'; then
|
||||
printf " %b EPEL repository already installed\\n" "${TICK}"
|
||||
else
|
||||
# CentOS requires the EPEL repository to gain access to Fedora packages
|
||||
if [[ CURRENT_CENTOS_VERSION -eq 7 ]]; then
|
||||
EPEL_PKG="https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm"
|
||||
elif [[ CURRENT_CENTOS_VERSION -eq 8 ]]; then
|
||||
EPEL_PKG="https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm"
|
||||
fi
|
||||
printf " %b Enabling EPEL package repository (https://fedoraproject.org/wiki/EPEL)\\n" "${INFO}"
|
||||
"${PKG_INSTALL[@]}" ${EPEL_PKG}
|
||||
printf " %b Installed %s\\n" "${TICK}" "${EPEL_PKG}"
|
||||
fi
|
||||
|
||||
|
||||
# The default php on CentOS 7.x is 5.4 which is EOL
|
||||
# Check if the version of PHP available via installed repositories is >= to PHP 7
|
||||
AVAILABLE_PHP_VERSION=$("${PKG_MANAGER}" info php | grep -i version | grep -o '[0-9]\+' | head -1)
|
||||
if [[ $AVAILABLE_PHP_VERSION -ge $SUPPORTED_CENTOS_PHP_VERSION ]]; then
|
||||
# Since PHP 7 is available by default, install via default PHP package names
|
||||
: # do nothing as PHP is current
|
||||
printf "PHP 7 is installed"
|
||||
else
|
||||
REMI_PKG="remi-release"
|
||||
REMI_REPO="remi-php72"
|
||||
REMI_REPO_URL="https://rpms.remirepo.net/enterprise/${REMI_PKG}-$(rpm -E '%{rhel}').rpm"
|
||||
|
||||
# The PHP version available via default repositories is older than version 7
|
||||
dialog --no-shadow --keep-tite \
|
||||
--title "PHP 7 Update (recommended)" \
|
||||
--defaultno \
|
||||
--yesno "PHP 7.x is recommended for both security and language features.\
|
||||
\\n\\nWould you like to install PHP7 via Remi's RPM repository?\
|
||||
\\n\\nSee: https://rpms.remirepo.net for more information"\
|
||||
"${r}" "${c}" && result=0 || result=$?
|
||||
|
||||
case ${result} in
|
||||
"${DIALOG_OK}" )
|
||||
printf " %b Installing PHP 7 via Remi's RPM repository\\n" "${INFO}"
|
||||
"${PKG_INSTALL[@]}" "yum-utils" &> /dev/null
|
||||
if rpm -q ${REMI_PKG} &> /dev/null; then
|
||||
printf " %b Remi's RPM repository is already installed\\n" "${TICK}"
|
||||
else
|
||||
printf " %b Enabling Remi's RPM repository (https://rpms.remirepo.net)\\n" "${INFO}"
|
||||
yum -y install "${REMI_REPO_URL}"
|
||||
printf " %b Installed %s from %s\\n" "${TICK}" "${REMI_PKG}" "${REMI_REPO_URL}"
|
||||
printf " %b Remi's RPM repository has been enabled for PHP7\\n" "${TICK}"
|
||||
fi
|
||||
yum-config-manager --disable 'remi-php*'
|
||||
yum-config-manager --enable "${REMI_REPO}"
|
||||
|
||||
# trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
|
||||
if "${PKG_INSTALL[@]}" "php-cli" &> /dev/null; then
|
||||
printf " %b PHP7 installed/updated via Remi's RPM repository\\n" "${TICK}"
|
||||
else
|
||||
printf " %b There was a problem updating to PHP7 via Remi's RPM repository\\n" "${CROSS}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
# User chose not to install PHP 7 via Remi's RPM repository
|
||||
"${DIALOG_CANCEL}")
|
||||
# User decided to NOT update PHP from REMI, attempt to install the default available PHP version
|
||||
printf " %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n" "${INFO}"
|
||||
;;
|
||||
|
||||
# User closed the dialog window
|
||||
"${DIALOG_ESC}")
|
||||
printf " %b Escape pressed, exiting installer at Remi dialog window\\n" "${CROSS}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
else
|
||||
# Warn user of unsupported version of Fedora or CentOS
|
||||
dialog --no-shadow --keep-tite \
|
||||
--title "Unsupported RPM based distribution" \
|
||||
--defaultno \
|
||||
--no-button "Exit" \
|
||||
--yes-button "Continue" \
|
||||
--yesno "Would you like to continue installation on an unsupported RPM based distribution?\
|
||||
\\n\\nPlease ensure the following packages have been installed manually:\
|
||||
\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+"\
|
||||
"${r}" "${c}" && result=0 || result=$?
|
||||
|
||||
case ${result} in
|
||||
# User chose to continue installation on an unsupported RPM based distribution
|
||||
"${DIALOG_OK}")
|
||||
printf " %b User opted to continue installation on an unsupported RPM based distribution.\\n" "${INFO}"
|
||||
;;
|
||||
# User chose not to continue installation on an unsupported RPM based distribution
|
||||
"${DIALOG_CANCEL}")
|
||||
printf " %b User opted not to continue installation on an unsupported RPM based distribution.\\n" "${INFO}"
|
||||
exit 1
|
||||
;;
|
||||
"${DIALOG_ESC}")
|
||||
printf " %b Escape pressed, exiting installer at unsupported RPM based distribution dialog window\\n" "${CROSS}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# A function for checking if a directory is a git repository
|
||||
is_repo() {
|
||||
# Use a named, local variable instead of the vague $1, which is the first argument passed to this function
|
||||
@@ -805,7 +682,7 @@ testIPv6() {
|
||||
|
||||
find_IPv6_information() {
|
||||
# Detects IPv6 address used for communication to WAN addresses.
|
||||
IPV6_ADDRESSES=($(ip -6 address | grep 'scope global' | awk '{print $2}'))
|
||||
mapfile -t IPV6_ADDRESSES <<<"$(ip -6 address | grep 'scope global' | awk '{print $2}')"
|
||||
|
||||
# For each address in the array above, determine the type of IPv6 address it is
|
||||
for i in "${IPV6_ADDRESSES[@]}"; do
|
||||
@@ -820,13 +697,13 @@ find_IPv6_information() {
|
||||
|
||||
# Determine which address to be used: Prefer ULA over GUA or don't use any if none found
|
||||
# If the ULA_ADDRESS contains a value,
|
||||
if [[ ! -z "${ULA_ADDRESS}" ]]; then
|
||||
if [[ -n "${ULA_ADDRESS}" ]]; then
|
||||
# set the IPv6 address to the ULA address
|
||||
IPV6_ADDRESS="${ULA_ADDRESS}"
|
||||
# Show this info to the user
|
||||
printf " %b Found IPv6 ULA address\\n" "${INFO}"
|
||||
# Otherwise, if the GUA_ADDRESS has a value,
|
||||
elif [[ ! -z "${GUA_ADDRESS}" ]]; then
|
||||
elif [[ -n "${GUA_ADDRESS}" ]]; then
|
||||
# Let the user know
|
||||
printf " %b Found IPv6 GUA address\\n" "${INFO}"
|
||||
# And assign it to the global variable
|
||||
@@ -889,9 +766,9 @@ getStaticIPv4Settings() {
|
||||
--cancel-label "Exit" \
|
||||
--backtitle "IP information" \
|
||||
--title "FYI: IP Conflict" \
|
||||
--msgbox "\\nIt is possible your router could still try to assign this IP to a device, which would cause a conflict\
|
||||
But in most cases the router is smart enough to not do that.\
|
||||
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.\
|
||||
--msgbox "\\nIt is possible your router could still try to assign this IP to a device, which would cause a conflict, \
|
||||
but in most cases the router is smart enough to not do that.\n\n\
|
||||
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.\n\n\
|
||||
It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address."\
|
||||
"${r}" "${c}" && result=0 || result=$?
|
||||
|
||||
@@ -912,7 +789,7 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
|
||||
|
||||
# Ask for the IPv4 address
|
||||
_staticIPv4Temp=$(dialog --no-shadow --keep-tite --output-fd 1 \
|
||||
--cancer-label "Exit" \
|
||||
--cancel-label "Exit" \
|
||||
--ok-label "Continue" \
|
||||
--backtitle "Calibrating network interface" \
|
||||
--title "IPv4 Address" \
|
||||
@@ -950,8 +827,11 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
|
||||
|
||||
# Configure networking via dhcpcd
|
||||
setDHCPCD() {
|
||||
# Check if the IP is already in the file
|
||||
if grep -q "${IPV4_ADDRESS}" /etc/dhcpcd.conf; then
|
||||
# Regex for matching a non-commented static ip address setting
|
||||
local regex="^[ \t]*static ip_address[ \t]*=[ \t]*${IPV4_ADDRESS}"
|
||||
|
||||
# Check if static IP is already set in file
|
||||
if grep -q "${regex}" /etc/dhcpcd.conf; then
|
||||
printf " %b Static IP already configured\\n" "${INFO}"
|
||||
# If it's not,
|
||||
else
|
||||
@@ -1122,10 +1002,10 @@ If you want to specify a port other than 53, separate it with a hash.\
|
||||
# and continue the loop.
|
||||
DNSSettingsCorrect=False
|
||||
else
|
||||
dialog --no-shadow --keep-tite \
|
||||
dialog --no-shadow --no-collapse --keep-tite \
|
||||
--backtitle "Specify Upstream DNS Provider(s)" \
|
||||
--title "Upstream DNS Provider(s)" \
|
||||
--yesno "Are these settings correct?\\n\\tDNS Server 1:\\t${PIHOLE_DNS_1}\\n\\tDNS Server 2:\\t${PIHOLE_DNS_2}" \
|
||||
--yesno "Are these settings correct?\\n"$'\t'"DNS Server 1:"$'\t'"${PIHOLE_DNS_1}\\n"$'\t'"DNS Server 2:"$'\t'"${PIHOLE_DNS_2}" \
|
||||
"${r}" "${c}" && result=0 || result=$?
|
||||
|
||||
case ${result} in
|
||||
@@ -1250,8 +1130,8 @@ setAdminFlag() {
|
||||
;;
|
||||
esac
|
||||
|
||||
# If the user wants to install the Web admin interface (i.e. it has not been deselected above)
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true ]]; then
|
||||
# If the user wants to install the Web admin interface (i.e. it has not been deselected above) and did not deselect the web server via command-line argument
|
||||
if [[ "${INSTALL_WEB_INTERFACE}" == true && "${INSTALL_WEB_SERVER}" == true ]]; then
|
||||
# Get list of required PHP modules, excluding base package (common) and handler (cgi)
|
||||
local i php_modules
|
||||
for i in "${PIHOLE_WEB_DEPS[@]}"; do [[ $i == 'php'* && $i != *'-common' && $i != *'-cgi' ]] && php_modules+=" ${i#*-}"; done
|
||||
@@ -1387,35 +1267,30 @@ version_check_dnsmasq() {
|
||||
# Copy the new Pi-hole DNS config file into the dnsmasq.d directory
|
||||
install -D -m 644 -T "${dnsmasq_pihole_01_source}" "${dnsmasq_pihole_01_target}"
|
||||
printf "%b %b Installed %s\n" "${OVER}" "${TICK}" "${dnsmasq_pihole_01_target}"
|
||||
# Replace our placeholder values with the GLOBAL DNS variables that we populated earlier
|
||||
# First, swap in the interface to listen on,
|
||||
sed -i "s/@INT@/$PIHOLE_INTERFACE/" "${dnsmasq_pihole_01_target}"
|
||||
# Add settings with the GLOBAL DNS variables that we populated earlier
|
||||
# First, set the interface to listen on
|
||||
addOrEditKeyValPair "${dnsmasq_pihole_01_target}" "interface" "$PIHOLE_INTERFACE"
|
||||
if [[ "${PIHOLE_DNS_1}" != "" ]]; then
|
||||
# then swap in the primary DNS server.
|
||||
sed -i "s/@DNS1@/$PIHOLE_DNS_1/" "${dnsmasq_pihole_01_target}"
|
||||
else
|
||||
# Otherwise, remove the line which sets DNS1.
|
||||
sed -i '/^server=@DNS1@/d' "${dnsmasq_pihole_01_target}"
|
||||
# then add in the primary DNS server.
|
||||
addOrEditKeyValPair "${dnsmasq_pihole_01_target}" "server" "$PIHOLE_DNS_1"
|
||||
fi
|
||||
# Ditto if DNS2 is not empty
|
||||
if [[ "${PIHOLE_DNS_2}" != "" ]]; then
|
||||
sed -i "s/@DNS2@/$PIHOLE_DNS_2/" "${dnsmasq_pihole_01_target}"
|
||||
else
|
||||
sed -i '/^server=@DNS2@/d' "${dnsmasq_pihole_01_target}"
|
||||
addKey "${dnsmasq_pihole_01_target}" "server=$PIHOLE_DNS_2"
|
||||
fi
|
||||
|
||||
# Set the cache size
|
||||
sed -i "s/@CACHE_SIZE@/$CACHE_SIZE/" "${dnsmasq_pihole_01_target}"
|
||||
addOrEditKeyValPair "${dnsmasq_pihole_01_target}" "cache-size" "$CACHE_SIZE"
|
||||
|
||||
sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' "${dnsmasq_conf}"
|
||||
|
||||
# If the user does not want to enable logging,
|
||||
if [[ "${QUERY_LOGGING}" == false ]] ; then
|
||||
# disable it by commenting out the directive in the DNS config file
|
||||
sed -i 's/^log-queries/#log-queries/' "${dnsmasq_pihole_01_target}"
|
||||
# remove itfrom the DNS config file
|
||||
removeKey "${dnsmasq_pihole_01_target}" "log-queries"
|
||||
else
|
||||
# Otherwise, enable it by uncommenting the directive in the DNS config file
|
||||
sed -i 's/^#log-queries/log-queries/' "${dnsmasq_pihole_01_target}"
|
||||
# Otherwise, enable it by adding the directive to the DNS config file
|
||||
addKey "${dnsmasq_pihole_01_target}" "log-queries"
|
||||
fi
|
||||
|
||||
printf " %b Installing %s..." "${INFO}" "${dnsmasq_rfc6761_06_source}"
|
||||
@@ -1488,9 +1363,9 @@ installConfigs() {
|
||||
chmod 644 "${PI_HOLE_CONFIG_DIR}/dns-servers.conf"
|
||||
|
||||
# Install template file if it does not exist
|
||||
if [[ ! -r "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" ]]; then
|
||||
if [[ ! -r "${FTL_CONFIG_FILE}" ]]; then
|
||||
install -d -m 0755 ${PI_HOLE_CONFIG_DIR}
|
||||
if ! install -T -o pihole -m 664 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.conf" "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" &>/dev/null; then
|
||||
if ! install -T -o pihole -m 664 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.conf" "${FTL_CONFIG_FILE}" &>/dev/null; then
|
||||
printf " %b Error: Unable to initialize configuration file %s/pihole-FTL.conf\\n" "${COL_LIGHT_RED}" "${PI_HOLE_CONFIG_DIR}"
|
||||
return 1
|
||||
fi
|
||||
@@ -1504,37 +1379,96 @@ installConfigs() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install pihole-FTL.service
|
||||
install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.service" "/etc/init.d/pihole-FTL"
|
||||
# Install pihole-FTL systemd or init.d service, based on whether systemd is the init system or not
|
||||
# Follow debhelper logic, which checks for /run/systemd/system to derive whether systemd is the init system
|
||||
if [[ -d '/run/systemd/system' ]]; then
|
||||
install -T -m 0644 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.systemd" '/etc/systemd/system/pihole-FTL.service'
|
||||
|
||||
# Remove init.d service if present
|
||||
if [[ -e '/etc/init.d/pihole-FTL' ]]; then
|
||||
rm '/etc/init.d/pihole-FTL'
|
||||
update-rc.d pihole-FTL remove
|
||||
fi
|
||||
|
||||
# Load final service
|
||||
systemctl daemon-reload
|
||||
else
|
||||
install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.service" '/etc/init.d/pihole-FTL'
|
||||
fi
|
||||
install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL-prestart.sh" "${PI_HOLE_INSTALL_DIR}/pihole-FTL-prestart.sh"
|
||||
install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL-poststop.sh" "${PI_HOLE_INSTALL_DIR}/pihole-FTL-poststop.sh"
|
||||
|
||||
# If the user chose to install the dashboard,
|
||||
if [[ "${INSTALL_WEB_SERVER}" == true ]]; then
|
||||
# and if the Web server conf directory does not exist,
|
||||
if [[ ! -d "/etc/lighttpd" ]]; then
|
||||
# make it and set the owners
|
||||
install -d -m 755 -o "${USER}" -g root /etc/lighttpd
|
||||
# Otherwise, if the config file already exists
|
||||
elif [[ -f "${lighttpdConfig}" ]]; then
|
||||
# back up the original
|
||||
mv "${lighttpdConfig}"{,.orig}
|
||||
fi
|
||||
# and copy in the config file Pi-hole needs
|
||||
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} "${lighttpdConfig}"
|
||||
# Make sure the external.conf file exists, as lighttpd v1.4.50 crashes without it
|
||||
if [ ! -f /etc/lighttpd/external.conf ]; then
|
||||
install -m 644 /dev/null /etc/lighttpd/external.conf
|
||||
fi
|
||||
# If there is a custom block page in the html/pihole directory, replace 404 handler in lighttpd config
|
||||
if [[ -f "${PI_HOLE_BLOCKPAGE_DIR}/custom.php" ]]; then
|
||||
sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"\/pihole\/custom\.php"/' "${lighttpdConfig}"
|
||||
fi
|
||||
# Make the directories if they do not exist and set the owners
|
||||
# set permissions on /etc/lighttpd/lighttpd.conf so pihole user (other) can read the file
|
||||
chmod o+x /etc/lighttpd
|
||||
chmod o+r "${lighttpdConfig}"
|
||||
|
||||
# Ensure /run/lighttpd exists and is owned by lighttpd user
|
||||
# Needed for the php socket
|
||||
mkdir -p /run/lighttpd
|
||||
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /run/lighttpd
|
||||
mkdir -p /var/cache/lighttpd/compress
|
||||
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/compress
|
||||
mkdir -p /var/cache/lighttpd/uploads
|
||||
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/uploads
|
||||
|
||||
if grep -q -F "OVERWRITTEN BY PI-HOLE" "${lighttpdConfig}"; then
|
||||
# Attempt to preserve backwards compatibility with older versions
|
||||
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} "${lighttpdConfig}"
|
||||
# Make the directories if they do not exist and set the owners
|
||||
mkdir -p /var/cache/lighttpd/compress
|
||||
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/compress
|
||||
mkdir -p /var/cache/lighttpd/uploads
|
||||
chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/uploads
|
||||
fi
|
||||
# Copy the config file to include for pihole admin interface
|
||||
if [[ -d "/etc/lighttpd/conf.d" ]]; then
|
||||
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/pihole-admin.conf /etc/lighttpd/conf.d/pihole-admin.conf
|
||||
if grep -q -F 'include "/etc/lighttpd/conf.d/pihole-admin.conf"' "${lighttpdConfig}"; then
|
||||
:
|
||||
else
|
||||
echo 'include "/etc/lighttpd/conf.d/pihole-admin.conf"' >> "${lighttpdConfig}"
|
||||
fi
|
||||
# Avoid some warnings trace from lighttpd, which might break tests
|
||||
conf=/etc/lighttpd/conf.d/pihole-admin.conf
|
||||
if lighttpd -f "${lighttpdConfig}" -tt 2>&1 | grep -q -F "WARNING: unknown config-key: dir-listing\."; then
|
||||
echo '# Avoid some warnings trace from lighttpd, which might break tests' >> $conf
|
||||
echo 'server.modules += ( "mod_dirlisting" )' >> $conf
|
||||
fi
|
||||
if lighttpd -f "${lighttpdConfig}" -tt 2>&1 | grep -q -F "warning: please use server.use-ipv6"; then
|
||||
echo '# Avoid some warnings trace from lighttpd, which might break tests' >> $conf
|
||||
echo 'server.use-ipv6 := "disable"' >> $conf
|
||||
fi
|
||||
elif [[ -d "/etc/lighttpd/conf-available" ]]; then
|
||||
conf=/etc/lighttpd/conf-available/15-pihole-admin.conf
|
||||
install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/pihole-admin.conf $conf
|
||||
|
||||
# Get the version number of lighttpd
|
||||
version=$(dpkg-query -f='${Version}\n' --show lighttpd)
|
||||
# Test if that version is greater than or euqal to 1.4.56
|
||||
if dpkg --compare-versions "$version" "ge" "1.4.56"; then
|
||||
# If it is, then we don't need to disable the modules
|
||||
# (server.modules duplication is ignored in lighttpd 1.4.56+)
|
||||
:
|
||||
else
|
||||
# disable server.modules += ( ... ) in $conf to avoid module dups
|
||||
if awk '!/^server\.modules/{print}' $conf > $conf.$$ && mv $conf.$$ $conf; then
|
||||
:
|
||||
else
|
||||
rm $conf.$$
|
||||
fi
|
||||
fi
|
||||
|
||||
chmod 644 $conf
|
||||
if is_command lighty-enable-mod ; then
|
||||
lighty-enable-mod pihole-admin access accesslog redirect fastcgi setenv > /dev/null || true
|
||||
else
|
||||
# Otherwise, show info about installing them
|
||||
printf " %b Warning: 'lighty-enable-mod' utility not found\\n" "${INFO}"
|
||||
printf " Please ensure fastcgi is enabled if you experience issues\\n"
|
||||
fi
|
||||
else
|
||||
# lighttpd config include dir not found
|
||||
printf " %b Warning: lighttpd config include dir not found\\n" "${INFO}"
|
||||
printf " Please manually install pihole-admin.conf\\n"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1751,9 +1685,9 @@ install_dependent_packages() {
|
||||
# Running apt-get install with minimal output can cause some issues with
|
||||
# requiring user input (e.g password for phpmyadmin see #218)
|
||||
printf " %b Processing %s install(s) for: %s, please wait...\\n" "${INFO}" "${PKG_MANAGER}" "${installArray[*]}"
|
||||
printf '%*s\n' "$columns" '' | tr " " -;
|
||||
printf '%*s\n' "${c}" '' | tr " " -;
|
||||
"${PKG_INSTALL[@]}" "${installArray[@]}"
|
||||
printf '%*s\n' "$columns" '' | tr " " -;
|
||||
printf '%*s\n' "${c}" '' | tr " " -;
|
||||
return
|
||||
fi
|
||||
printf "\\n"
|
||||
@@ -1774,9 +1708,9 @@ install_dependent_packages() {
|
||||
# If there's anything to install, install everything in the list.
|
||||
if [[ "${#installArray[@]}" -gt 0 ]]; then
|
||||
printf " %b Processing %s install(s) for: %s, please wait...\\n" "${INFO}" "${PKG_MANAGER}" "${installArray[*]}"
|
||||
printf '%*s\n' "$columns" '' | tr " " -;
|
||||
printf '%*s\n' "${c}" '' | tr " " -;
|
||||
"${PKG_INSTALL[@]}" "${installArray[@]}"
|
||||
printf '%*s\n' "$columns" '' | tr " " -;
|
||||
printf '%*s\n' "${c}" '' | tr " " -;
|
||||
return
|
||||
fi
|
||||
printf "\\n"
|
||||
@@ -1785,35 +1719,6 @@ install_dependent_packages() {
|
||||
|
||||
# Install the Web interface dashboard
|
||||
installPiholeWeb() {
|
||||
printf "\\n %b Installing blocking page...\\n" "${INFO}"
|
||||
|
||||
local str="Creating directory for blocking page, and copying files"
|
||||
printf " %b %s..." "${INFO}" "${str}"
|
||||
# Install the directory,
|
||||
install -d -m 0755 ${PI_HOLE_BLOCKPAGE_DIR}
|
||||
# and the blockpage
|
||||
install -D -m 644 ${PI_HOLE_LOCAL_REPO}/advanced/{index,blockingpage}.* ${PI_HOLE_BLOCKPAGE_DIR}/
|
||||
|
||||
# Remove superseded file
|
||||
if [[ -e "${PI_HOLE_BLOCKPAGE_DIR}/index.js" ]]; then
|
||||
rm "${PI_HOLE_BLOCKPAGE_DIR}/index.js"
|
||||
fi
|
||||
|
||||
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
||||
|
||||
local str="Backing up index.lighttpd.html"
|
||||
printf " %b %s..." "${INFO}" "${str}"
|
||||
# If the default index file exists,
|
||||
if [[ -f "${webroot}/index.lighttpd.html" ]]; then
|
||||
# back it up
|
||||
mv ${webroot}/index.lighttpd.html ${webroot}/index.lighttpd.orig
|
||||
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
||||
else
|
||||
# Otherwise, don't do anything
|
||||
printf "%b %b %s\\n" "${OVER}" "${INFO}" "${str}"
|
||||
printf " No default index.lighttpd.html file found... not backing up\\n"
|
||||
fi
|
||||
|
||||
# Install Sudoers file
|
||||
local str="Installing sudoer file"
|
||||
printf "\\n %b %s..." "${INFO}" "${str}"
|
||||
@@ -1889,20 +1794,35 @@ create_pihole_user() {
|
||||
else
|
||||
# If the pihole user doesn't exist,
|
||||
printf "%b %b %s" "${OVER}" "${CROSS}" "${str}"
|
||||
local str="Creating user 'pihole'"
|
||||
printf "%b %b %s..." "${OVER}" "${INFO}" "${str}"
|
||||
# create her with the useradd command,
|
||||
local str="Checking for group 'pihole'"
|
||||
printf " %b %s..." "${INFO}" "${str}"
|
||||
if getent group pihole > /dev/null 2>&1; then
|
||||
# then add her to the pihole group (as it already exists)
|
||||
# group pihole exists
|
||||
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
||||
# then create and add her to the pihole group
|
||||
local str="Creating user 'pihole'"
|
||||
printf "%b %b %s..." "${OVER}" "${INFO}" "${str}"
|
||||
if useradd -r --no-user-group -g pihole -s /usr/sbin/nologin pihole; then
|
||||
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
||||
else
|
||||
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
|
||||
fi
|
||||
else
|
||||
# add user pihole with default group settings
|
||||
if useradd -r -s /usr/sbin/nologin pihole; then
|
||||
# group pihole does not exist
|
||||
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
|
||||
local str="Creating group 'pihole'"
|
||||
# if group can be created
|
||||
if groupadd pihole; then
|
||||
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
||||
# create and add pihole user to the pihole group
|
||||
local str="Creating user 'pihole'"
|
||||
printf "%b %b %s..." "${OVER}" "${INFO}" "${str}"
|
||||
if useradd -r --no-user-group -g pihole -s /usr/sbin/nologin pihole; then
|
||||
printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}"
|
||||
else
|
||||
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
|
||||
fi
|
||||
|
||||
else
|
||||
printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}"
|
||||
fi
|
||||
@@ -1912,33 +1832,28 @@ create_pihole_user() {
|
||||
|
||||
# This function saves any changes to the setup variables into the setupvars.conf file for future runs
|
||||
finalExports() {
|
||||
# If the setup variable file exists,
|
||||
if [[ -e "${setupVars}" ]]; then
|
||||
# update the variables in the file
|
||||
sed -i.update.bak '/PIHOLE_INTERFACE/d;/PIHOLE_DNS_1\b/d;/PIHOLE_DNS_2\b/d;/QUERY_LOGGING/d;/INSTALL_WEB_SERVER/d;/INSTALL_WEB_INTERFACE/d;/LIGHTTPD_ENABLED/d;/CACHE_SIZE/d;/DNS_FQDN_REQUIRED/d;/DNS_BOGUS_PRIV/d;/DNSMASQ_LISTENING/d;' "${setupVars}"
|
||||
fi
|
||||
# echo the information to the user
|
||||
{
|
||||
echo "PIHOLE_INTERFACE=${PIHOLE_INTERFACE}"
|
||||
echo "PIHOLE_DNS_1=${PIHOLE_DNS_1}"
|
||||
echo "PIHOLE_DNS_2=${PIHOLE_DNS_2}"
|
||||
echo "QUERY_LOGGING=${QUERY_LOGGING}"
|
||||
echo "INSTALL_WEB_SERVER=${INSTALL_WEB_SERVER}"
|
||||
echo "INSTALL_WEB_INTERFACE=${INSTALL_WEB_INTERFACE}"
|
||||
echo "LIGHTTPD_ENABLED=${LIGHTTPD_ENABLED}"
|
||||
echo "CACHE_SIZE=${CACHE_SIZE}"
|
||||
echo "DNS_FQDN_REQUIRED=${DNS_FQDN_REQUIRED:-true}"
|
||||
echo "DNS_BOGUS_PRIV=${DNS_BOGUS_PRIV:-true}"
|
||||
echo "DNSMASQ_LISTENING=${DNSMASQ_LISTENING:-local}"
|
||||
}>> "${setupVars}"
|
||||
# set or update the variables in the file
|
||||
|
||||
addOrEditKeyValPair "${setupVars}" "PIHOLE_INTERFACE" "${PIHOLE_INTERFACE}"
|
||||
addOrEditKeyValPair "${setupVars}" "PIHOLE_DNS_1" "${PIHOLE_DNS_1}"
|
||||
addOrEditKeyValPair "${setupVars}" "PIHOLE_DNS_2" "${PIHOLE_DNS_2}"
|
||||
addOrEditKeyValPair "${setupVars}" "QUERY_LOGGING" "${QUERY_LOGGING}"
|
||||
addOrEditKeyValPair "${setupVars}" "INSTALL_WEB_SERVER" "${INSTALL_WEB_SERVER}"
|
||||
addOrEditKeyValPair "${setupVars}" "INSTALL_WEB_INTERFACE" "${INSTALL_WEB_INTERFACE}"
|
||||
addOrEditKeyValPair "${setupVars}" "LIGHTTPD_ENABLED" "${LIGHTTPD_ENABLED}"
|
||||
addOrEditKeyValPair "${setupVars}" "CACHE_SIZE" "${CACHE_SIZE}"
|
||||
addOrEditKeyValPair "${setupVars}" "DNS_FQDN_REQUIRED" "${DNS_FQDN_REQUIRED:-true}"
|
||||
addOrEditKeyValPair "${setupVars}" "DNS_BOGUS_PRIV" "${DNS_BOGUS_PRIV:-true}"
|
||||
addOrEditKeyValPair "${setupVars}" "DNSMASQ_LISTENING" "${DNSMASQ_LISTENING:-local}"
|
||||
|
||||
chmod 644 "${setupVars}"
|
||||
|
||||
# Set the privacy level
|
||||
sed -i '/PRIVACYLEVEL/d' "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf"
|
||||
echo "PRIVACYLEVEL=${PRIVACY_LEVEL}" >> "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf"
|
||||
addOrEditKeyValPair "${FTL_CONFIG_FILE}" "PRIVACYLEVEL" "${PRIVACY_LEVEL}"
|
||||
|
||||
# Bring in the current settings and the functions to manipulate them
|
||||
source "${setupVars}"
|
||||
# shellcheck source=advanced/Scripts/webpage.sh
|
||||
source "${PI_HOLE_LOCAL_REPO}/advanced/Scripts/webpage.sh"
|
||||
|
||||
# Look for DNS server settings which would have to be reapplied
|
||||
@@ -1955,6 +1870,16 @@ installLogrotate() {
|
||||
|
||||
printf "\\n %b %s..." "${INFO}" "${str}"
|
||||
if [[ -f ${target} ]]; then
|
||||
|
||||
# Account for changed logfile paths from /var/log -> /var/log/pihole/ made in core v5.11.
|
||||
if grep -q "/var/log/pihole.log" ${target} || grep -q "/var/log/pihole-FTL.log" ${target}; then
|
||||
sed -i 's/\/var\/log\/pihole.log/\/var\/log\/pihole\/pihole.log/g' ${target}
|
||||
sed -i 's/\/var\/log\/pihole-FTL.log/\/var\/log\/pihole\/FTL.log/g' ${target}
|
||||
|
||||
printf "\\n\\t%b Old log file paths updated in existing logrotate file. \\n" "${INFO}"
|
||||
return 3
|
||||
fi
|
||||
|
||||
printf "\\n\\t%b Existing logrotate file found. No changes made.\\n" "${INFO}"
|
||||
# Return value isn't that important, using 2 to indicate that it's not a fatal error but
|
||||
# the function did not complete.
|
||||
@@ -1996,15 +1921,6 @@ installPihole() {
|
||||
# Give lighttpd access to the pihole group so the web interface can
|
||||
# manage the gravity.db database
|
||||
usermod -a -G pihole ${LIGHTTPD_USER}
|
||||
# If the lighttpd command is executable,
|
||||
if is_command lighty-enable-mod ; then
|
||||
# enable fastcgi and fastcgi-php
|
||||
lighty-enable-mod fastcgi fastcgi-php > /dev/null || true
|
||||
else
|
||||
# Otherwise, show info about installing them
|
||||
printf " %b Warning: 'lighty-enable-mod' utility not found\\n" "${INFO}"
|
||||
printf " Please ensure fastcgi is enabled if you experience issues\\n"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Install base files and web interface
|
||||
@@ -2012,6 +1928,16 @@ installPihole() {
|
||||
printf " %b Failure in dependent script copy function.\\n" "${CROSS}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# /opt/pihole/utils.sh should be installed by installScripts now, so we can use it
|
||||
if [ -f "${PI_HOLE_INSTALL_DIR}/utils.sh" ]; then
|
||||
# shellcheck disable=SC1091
|
||||
source "${PI_HOLE_INSTALL_DIR}/utils.sh"
|
||||
else
|
||||
printf " %b Failure: /opt/pihole/utils.sh does not exist .\\n" "${CROSS}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install config files
|
||||
if ! installConfigs; then
|
||||
printf " %b Failure in dependent config copy function.\\n" "${CROSS}"
|
||||
@@ -2050,22 +1976,22 @@ checkSelinux() {
|
||||
DEFAULT_SELINUX=$(awk -F= '/^SELINUX=/ {print $2}' /etc/selinux/config)
|
||||
case "${DEFAULT_SELINUX,,}" in
|
||||
enforcing)
|
||||
printf " %b %bDefault SELinux: %s%b\\n" "${CROSS}" "${COL_RED}" "${DEFAULT_SELINUX}" "${COL_NC}"
|
||||
printf " %b %bDefault SELinux: %s%b\\n" "${CROSS}" "${COL_RED}" "${DEFAULT_SELINUX,,}" "${COL_NC}"
|
||||
SELINUX_ENFORCING=1
|
||||
;;
|
||||
*) # 'permissive' and 'disabled'
|
||||
printf " %b %bDefault SELinux: %s%b\\n" "${TICK}" "${COL_GREEN}" "${DEFAULT_SELINUX}" "${COL_NC}"
|
||||
printf " %b %bDefault SELinux: %s%b\\n" "${TICK}" "${COL_GREEN}" "${DEFAULT_SELINUX,,}" "${COL_NC}"
|
||||
;;
|
||||
esac
|
||||
# Check the current state of SELinux
|
||||
CURRENT_SELINUX=$(getenforce)
|
||||
case "${CURRENT_SELINUX,,}" in
|
||||
enforcing)
|
||||
printf " %b %bCurrent SELinux: %s%b\\n" "${CROSS}" "${COL_RED}" "${CURRENT_SELINUX}" "${COL_NC}"
|
||||
printf " %b %bCurrent SELinux: %s%b\\n" "${CROSS}" "${COL_RED}" "${CURRENT_SELINUX,,}" "${COL_NC}"
|
||||
SELINUX_ENFORCING=1
|
||||
;;
|
||||
*) # 'permissive' and 'disabled'
|
||||
printf " %b %bCurrent SELinux: %s%b\\n" "${TICK}" "${COL_GREEN}" "${CURRENT_SELINUX}" "${COL_NC}"
|
||||
printf " %b %bCurrent SELinux: %s%b\\n" "${TICK}" "${COL_GREEN}" "${CURRENT_SELINUX,,}" "${COL_NC}"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
@@ -2139,9 +2065,8 @@ update_dialogs() {
|
||||
\\n($strAdd)"\
|
||||
"${r}" "${c}" 2 \
|
||||
"${opt1a}" "${opt1b}" \
|
||||
"${opt2a}" "${opt2b}" || true)
|
||||
"${opt2a}" "${opt2b}") || result=$?
|
||||
|
||||
result=$?
|
||||
case ${result} in
|
||||
"${DIALOG_CANCEL}" | "${DIALOG_ESC}")
|
||||
printf " %b Cancel was selected, exiting installer%b\\n" "${COL_LIGHT_RED}" "${COL_NC}"
|
||||
@@ -2238,11 +2163,7 @@ checkout_pull_branch() {
|
||||
|
||||
git_pull=$(git pull --no-rebase || return 1)
|
||||
|
||||
if [[ "$git_pull" == *"up-to-date"* ]]; then
|
||||
printf " %b %s\\n" "${INFO}" "${git_pull}"
|
||||
else
|
||||
printf "%s\\n" "$git_pull"
|
||||
fi
|
||||
printf " %b %s\\n" "${INFO}" "${git_pull}"
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -2389,7 +2310,7 @@ get_binary_name() {
|
||||
local rev
|
||||
rev=$(uname -m | sed "s/[^0-9]//g;")
|
||||
local lib
|
||||
lib=$(ldd "$(which sh)" | grep -E '^\s*/lib' | awk '{ print $1 }')
|
||||
lib=$(ldd "$(command -v sh)" | grep -E '^\s*/lib' | awk '{ print $1 }')
|
||||
if [[ "${lib}" == "/lib/ld-linux-aarch64.so.1" ]]; then
|
||||
printf "%b %b Detected AArch64 (64 Bit ARM) processor\\n" "${OVER}" "${TICK}"
|
||||
# set the binary to be used
|
||||
@@ -2646,12 +2567,6 @@ main() {
|
||||
printf " %b Checking for / installing Required dependencies for this install script...\\n" "${INFO}"
|
||||
install_dependent_packages "${INSTALLER_DEPS[@]}"
|
||||
|
||||
#In case of RPM based distro, select the proper PHP version
|
||||
if [[ "$PKG_MANAGER" == "yum" || "$PKG_MANAGER" == "dnf" ]] ; then
|
||||
select_rpm_php
|
||||
fi
|
||||
|
||||
|
||||
# If the setup variable file exists,
|
||||
if [[ -f "${setupVars}" ]]; then
|
||||
# if it's running unattended,
|
||||
@@ -2696,8 +2611,9 @@ main() {
|
||||
source "${setupVars}"
|
||||
|
||||
# Get the privacy level if it exists (default is 0)
|
||||
if [[ -f "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" ]]; then
|
||||
PRIVACY_LEVEL=$(sed -ne 's/PRIVACYLEVEL=\(.*\)/\1/p' "${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf")
|
||||
if [[ -f "${FTL_CONFIG_FILE}" ]]; then
|
||||
# get the value from $FTL_CONFIG_FILE (and ignoring all commented lines)
|
||||
PRIVACY_LEVEL=$(sed -e '/^[[:blank:]]*#/d' "${FTL_CONFIG_FILE}" | grep "PRIVACYLEVEL" | awk -F "=" 'NR==1{printf$2}')
|
||||
|
||||
# If no setting was found, default to 0
|
||||
PRIVACY_LEVEL="${PRIVACY_LEVEL:-0}"
|
||||
@@ -2797,8 +2713,7 @@ main() {
|
||||
stop_service pihole-FTL &> /dev/null
|
||||
|
||||
if [ ! -d /var/log/pihole/ ]; then
|
||||
mkdir /var/log/pihole/
|
||||
chmod 0775 /var/log/pihole/
|
||||
mkdir -m 0755 /var/log/pihole/
|
||||
fi
|
||||
|
||||
# Special handling for pihole-FTL.log -> pihole/FTL.log
|
||||
@@ -2814,7 +2729,6 @@ main() {
|
||||
|
||||
# Remaining log files
|
||||
if [ -f /var/log/pihole.log ] && [ ! -L /var/log/pihole.log ]; then
|
||||
mkdir -p /var/log/pihole/
|
||||
mv /var/log/pihole*.* /var/log/pihole/ 2>/dev/null
|
||||
fi
|
||||
|
||||
@@ -2823,9 +2737,8 @@ main() {
|
||||
# Download and compile the aggregated block list
|
||||
runGravity
|
||||
|
||||
# Force an update of the updatechecker
|
||||
# Update local and remote versions via updatechecker
|
||||
/opt/pihole/updatecheck.sh
|
||||
/opt/pihole/updatecheck.sh x remote
|
||||
|
||||
if [[ "${useUpdateVars}" == false ]]; then
|
||||
displayFinalMessage "${pw}"
|
||||
@@ -2858,7 +2771,7 @@ main() {
|
||||
|
||||
# Display where the log file is
|
||||
printf "\\n %b The install log is located at: %s\\n" "${INFO}" "${installLogLoc}"
|
||||
printf "%b%s Complete! %b\\n" "${COL_LIGHT_GREEN}" "${INSTALL_TYPE}" "${COL_NC}"
|
||||
printf " %b %b%s complete! %b\\n" "${TICK}" "${COL_LIGHT_GREEN}" "${INSTALL_TYPE}" "${COL_NC}"
|
||||
|
||||
if [[ "${INSTALL_TYPE}" == "Update" ]]; then
|
||||
printf "\\n"
|
||||
@@ -2866,6 +2779,7 @@ main() {
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ "${PH_TEST}" != true ]] ; then
|
||||
# allow to source this script without running it
|
||||
if [[ "${SKIP_INSTALL}" != true ]] ; then
|
||||
main "$@"
|
||||
fi
|
||||
|
||||
@@ -36,7 +36,7 @@ else
|
||||
fi
|
||||
|
||||
readonly PI_HOLE_FILES_DIR="/etc/.pihole"
|
||||
PH_TEST="true"
|
||||
SKIP_INSTALL="true"
|
||||
source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh"
|
||||
# setupVars set in basic-install.sh
|
||||
source "${setupVars}"
|
||||
@@ -44,8 +44,8 @@ source "${setupVars}"
|
||||
# package_manager_detect() sourced from basic-install.sh
|
||||
package_manager_detect
|
||||
|
||||
# Install packages used by the Pi-hole
|
||||
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}")
|
||||
# Uninstall packages used by the Pi-hole
|
||||
DEPS=("${INSTALLER_DEPS[@]}" "${PIHOLE_DEPS[@]}" "${OS_CHECK_DEPS[@]}")
|
||||
if [[ "${INSTALL_WEB_SERVER}" == true ]]; then
|
||||
# Install the Web dependencies
|
||||
DEPS+=("${PIHOLE_WEB_DEPS[@]}")
|
||||
@@ -131,6 +131,7 @@ removeNoPurge() {
|
||||
fi
|
||||
|
||||
if package_check lighttpd > /dev/null; then
|
||||
# Attempt to preserve backwards compatibility with older versions
|
||||
if [[ -f /etc/lighttpd/lighttpd.conf.orig ]]; then
|
||||
${SUDO} mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf
|
||||
fi
|
||||
@@ -139,6 +140,29 @@ removeNoPurge() {
|
||||
${SUDO} rm /etc/lighttpd/external.conf
|
||||
fi
|
||||
|
||||
# Fedora-based
|
||||
if [[ -f /etc/lighttpd/conf.d/pihole-admin.conf ]]; then
|
||||
${SUDO} rm /etc/lighttpd/conf.d/pihole-admin.conf
|
||||
conf=/etc/lighttpd/lighttpd.conf
|
||||
tconf=/tmp/lighttpd.conf.$$
|
||||
if awk '!/^include "\/etc\/lighttpd\/conf\.d\/pihole-admin\.conf"$/{print}' \
|
||||
$conf > $tconf && mv $tconf $conf; then
|
||||
:
|
||||
else
|
||||
rm $tconf
|
||||
fi
|
||||
${SUDO} chown root:root $conf
|
||||
${SUDO} chmod 644 $conf
|
||||
fi
|
||||
|
||||
# Debian-based
|
||||
if [[ -f /etc/lighttpd/conf-available/pihole-admin.conf ]]; then
|
||||
if is_command lighty-disable-mod ; then
|
||||
${SUDO} lighty-disable-mod pihole-admin > /dev/null || true
|
||||
fi
|
||||
${SUDO} rm /etc/lighttpd/conf-available/15-pihole-admin.conf
|
||||
fi
|
||||
|
||||
echo -e " ${TICK} Removed lighttpd configs"
|
||||
fi
|
||||
|
||||
@@ -169,6 +193,18 @@ removeNoPurge() {
|
||||
else
|
||||
service pihole-FTL stop
|
||||
fi
|
||||
${SUDO} rm -f /etc/systemd/system/pihole-FTL.service
|
||||
if [[ -d '/etc/systemd/system/pihole-FTL.service.d' ]]; then
|
||||
read -rp " ${QST} FTL service override directory /etc/systemd/system/pihole-FTL.service.d detected. Do you wish to remove this from your system? [y/N] " answer
|
||||
case $answer in
|
||||
[yY]*)
|
||||
echo -ne " ${INFO} Removing /etc/systemd/system/pihole-FTL.service.d..."
|
||||
${SUDO} rm -R /etc/systemd/system/pihole-FTL.service.d
|
||||
echo -e "${OVER} ${INFO} Removed /etc/systemd/system/pihole-FTL.service.d"
|
||||
;;
|
||||
*) echo -e " ${INFO} Leaving /etc/systemd/system/pihole-FTL.service.d in place.";;
|
||||
esac
|
||||
fi
|
||||
${SUDO} rm -f /etc/init.d/pihole-FTL
|
||||
${SUDO} rm -f /usr/bin/pihole-FTL
|
||||
echo -e "${OVER} ${TICK} Removed pihole-FTL"
|
||||
|
||||
268
gravity.sh
268
gravity.sh
@@ -40,6 +40,7 @@ gravityDBschema="${piholeGitDir}/advanced/Templates/gravity.db.sql"
|
||||
gravityDBcopy="${piholeGitDir}/advanced/Templates/gravity_copy.sql"
|
||||
|
||||
domainsExtension="domains"
|
||||
curl_connect_timeout=10
|
||||
|
||||
# Source setupVars from install script
|
||||
setupVars="${piholeDir}/setupVars.conf"
|
||||
@@ -51,6 +52,14 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set up tmp dir variable in case it's not configured
|
||||
: "${GRAVITY_TMPDIR:=/tmp}"
|
||||
|
||||
if [ ! -d "${GRAVITY_TMPDIR}" ] || [ ! -w "${GRAVITY_TMPDIR}" ]; then
|
||||
echo -e " ${COL_LIGHT_RED}Gravity temporary directory does not exist or is not a writeable directory, falling back to /tmp. ${COL_NC}"
|
||||
GRAVITY_TMPDIR="/tmp"
|
||||
fi
|
||||
|
||||
# Source pihole-FTL from install script
|
||||
pihole_FTL="${piholeDir}/pihole-FTL.conf"
|
||||
if [[ -f "${pihole_FTL}" ]]; then
|
||||
@@ -136,15 +145,27 @@ update_gravity_timestamp() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Update timestamp when the gravity table was last updated successfully
|
||||
set_abp_info() {
|
||||
pihole-FTL sqlite3 "${gravityDBfile}" "INSERT OR REPLACE INTO info (property,value) VALUES ('abp_domains',${abp_domains});"
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to update ABP domain status in database ${gravityDBfile}\\n ${output}"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Import domains from file and store them in the specified database table
|
||||
database_table_from_file() {
|
||||
# Define locals
|
||||
local table source backup_path backup_file tmpFile type
|
||||
local table src backup_path backup_file tmpFile list_type
|
||||
table="${1}"
|
||||
source="${2}"
|
||||
src="${2}"
|
||||
backup_path="${piholeDir}/migration_backup"
|
||||
backup_file="${backup_path}/$(basename "${2}")"
|
||||
tmpFile="$(mktemp -p "/tmp" --suffix=".gravity")"
|
||||
tmpFile="$(mktemp -p "${GRAVITY_TMPDIR}" --suffix=".gravity")"
|
||||
|
||||
local timestamp
|
||||
timestamp="$(date --utc +'%s')"
|
||||
@@ -155,13 +176,13 @@ database_table_from_file() {
|
||||
|
||||
# Special handling for domains to be imported into the common domainlist table
|
||||
if [[ "${table}" == "whitelist" ]]; then
|
||||
type="0"
|
||||
list_type="0"
|
||||
table="domainlist"
|
||||
elif [[ "${table}" == "blacklist" ]]; then
|
||||
type="1"
|
||||
list_type="1"
|
||||
table="domainlist"
|
||||
elif [[ "${table}" == "regex" ]]; then
|
||||
type="3"
|
||||
list_type="3"
|
||||
table="domainlist"
|
||||
fi
|
||||
|
||||
@@ -174,9 +195,9 @@ database_table_from_file() {
|
||||
rowid+=1
|
||||
fi
|
||||
|
||||
# Loop over all domains in ${source} file
|
||||
# Loop over all domains in ${src} file
|
||||
# Read file line by line
|
||||
grep -v '^ *#' < "${source}" | while IFS= read -r domain
|
||||
grep -v '^ *#' < "${src}" | while IFS= read -r domain
|
||||
do
|
||||
# Only add non-empty lines
|
||||
if [[ -n "${domain}" ]]; then
|
||||
@@ -185,10 +206,10 @@ database_table_from_file() {
|
||||
echo "${rowid},\"${domain}\",${timestamp}" >> "${tmpFile}"
|
||||
elif [[ "${table}" == "adlist" ]]; then
|
||||
# Adlist table format
|
||||
echo "${rowid},\"${domain}\",1,${timestamp},${timestamp},\"Migrated from ${source}\",,0,0,0" >> "${tmpFile}"
|
||||
echo "${rowid},\"${domain}\",1,${timestamp},${timestamp},\"Migrated from ${src}\",,0,0,0" >> "${tmpFile}"
|
||||
else
|
||||
# White-, black-, and regexlist table format
|
||||
echo "${rowid},${type},\"${domain}\",1,${timestamp},${timestamp},\"Migrated from ${source}\"" >> "${tmpFile}"
|
||||
echo "${rowid},${list_type},\"${domain}\",1,${timestamp},${timestamp},\"Migrated from ${src}\"" >> "${tmpFile}"
|
||||
fi
|
||||
rowid+=1
|
||||
fi
|
||||
@@ -201,14 +222,14 @@ database_table_from_file() {
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to fill table ${table}${type} in database ${gravityDBfile}\\n ${output}"
|
||||
echo -e "\\n ${CROSS} Unable to fill table ${table}${list_type} in database ${gravityDBfile}\\n ${output}"
|
||||
gravity_Cleanup "error"
|
||||
fi
|
||||
|
||||
# Move source file to backup directory, create directory if not existing
|
||||
mkdir -p "${backup_path}"
|
||||
mv "${source}" "${backup_file}" 2> /dev/null || \
|
||||
echo -e " ${CROSS} Unable to backup ${source} to ${backup_path}"
|
||||
mv "${src}" "${backup_file}" 2> /dev/null || \
|
||||
echo -e " ${CROSS} Unable to backup ${src} to ${backup_path}"
|
||||
|
||||
# Delete tmpFile
|
||||
rm "${tmpFile}" > /dev/null 2>&1 || \
|
||||
@@ -243,7 +264,7 @@ database_adlist_number() {
|
||||
return;
|
||||
fi
|
||||
|
||||
output=$( { printf ".timeout 30000\\nUPDATE adlist SET number = %i, invalid_domains = %i WHERE id = %i;\\n" "${num_source_lines}" "${num_invalid}" "${1}" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
output=$( { printf ".timeout 30000\\nUPDATE adlist SET number = %i, invalid_domains = %i WHERE id = %i;\\n" "${num_domains}" "${num_non_domains}" "${1}" | pihole-FTL sqlite3 "${gravityDBfile}"; } 2>&1 )
|
||||
status="$?"
|
||||
|
||||
if [[ "${status}" -ne 0 ]]; then
|
||||
@@ -417,7 +438,7 @@ gravity_DownloadBlocklists() {
|
||||
echo -e "${OVER} ${TICK} ${str}"
|
||||
fi
|
||||
|
||||
target="$(mktemp -p "/tmp" --suffix=".gravity")"
|
||||
target="$(mktemp -p "${GRAVITY_TMPDIR}" --suffix=".gravity")"
|
||||
|
||||
# Use compression to reduce the amount of data that is transferred
|
||||
# between the Pi-hole and the ad list provider. Use this feature
|
||||
@@ -518,45 +539,88 @@ gravity_DownloadBlocklists() {
|
||||
gravity_Blackbody=true
|
||||
}
|
||||
|
||||
# num_target_lines does increase for every correctly added domain in pareseList()
|
||||
num_target_lines=0
|
||||
num_source_lines=0
|
||||
num_invalid=0
|
||||
|
||||
# global variable to indicate if we found ABP style domains during the gravity run
|
||||
# is saved in gravtiy's info table to signal FTL if such domains are available
|
||||
abp_domains=0
|
||||
parseList() {
|
||||
local adlistID="${1}" src="${2}" target="${3}" incorrect_lines
|
||||
# This sed does the following things:
|
||||
# 1. Remove all domains containing invalid characters. Valid are: a-z, A-Z, 0-9, dot (.), minus (-), underscore (_)
|
||||
# 2. Append ,adlistID to every line
|
||||
local adlistID="${1}" src="${2}" target="${3}" temp_file temp_file_base non_domains sample_non_domains valid_domain_pattern abp_domain_pattern
|
||||
|
||||
# Create a temporary file for the sed magic instead of using "${target}" directly
|
||||
# this allows to split the sed commands to improve readability
|
||||
# we use a file handle here and remove the temporary file immediately so the content will be deleted in any case
|
||||
# when the script stops
|
||||
temp_file_base="$(mktemp -p "/tmp" --suffix=".gravity")"
|
||||
exec 3>"$temp_file_base"
|
||||
rm "${temp_file_base}"
|
||||
temp_file="/proc/$$/fd/3"
|
||||
|
||||
# define valid domain patterns
|
||||
# no need to include uppercase letters, as we convert to lowercase in gravity_ParseFileIntoDomains() already
|
||||
# adapted from https://stackoverflow.com/a/30007882
|
||||
# supported ABP style: ||subdomain.domain.tlp^
|
||||
|
||||
valid_domain_pattern="([a-z0-9]([a-z0-9_-]{0,61}[a-z0-9]){0,1}\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]"
|
||||
abp_domain_pattern="\|\|${valid_domain_pattern}\^"
|
||||
|
||||
|
||||
# 1. Add all valid domains
|
||||
sed -r "/^${valid_domain_pattern}$/!d" "${src}" > "${temp_file}"
|
||||
|
||||
# 2. Add valid ABP style domains if there is at least one such domain
|
||||
if grep -E "^${abp_domain_pattern}$" -m 1 -q "${src}"; then
|
||||
echo " ${INFO} List contained AdBlock Plus style domains"
|
||||
abp_domains=1
|
||||
sed -r "/^${abp_domain_pattern}$/!d" "${src}" >> "${temp_file}"
|
||||
fi
|
||||
|
||||
|
||||
# Find lines containing no domains or with invalid characters (not matching regex above)
|
||||
# This is simply everything that is not in $temp_file compared to $src
|
||||
# Remove duplicates from the list
|
||||
mapfile -t non_domains < <(grep -Fvf "${temp_file}" "${src}" | sort -u )
|
||||
|
||||
# 3. Remove trailing period (see https://github.com/pi-hole/pi-hole/issues/4701)
|
||||
# 4. Ensures there is a newline on the last line
|
||||
sed -e "/[^a-zA-Z0-9.\_-]/d;s/\.$//;s/$/,${adlistID}/;/.$/a\\" "${src}" >> "${target}"
|
||||
# Find (up to) five domains containing invalid characters (see above)
|
||||
incorrect_lines="$(sed -e "/[^a-zA-Z0-9.\_-]/!d" "${src}" | head -n 5)"
|
||||
# 4. Append ,adlistID to every line
|
||||
# 5. Ensures there is a newline on the last line
|
||||
# and write everything to the target file
|
||||
sed "s/\.$//;s/$/,${adlistID}/;/.$/a\\" "${temp_file}" >> "${target}"
|
||||
|
||||
local num_target_lines_new num_correct_lines
|
||||
# Get number of lines in source file
|
||||
num_source_lines="$(grep -c "^" "${src}")"
|
||||
# Get the new number of lines in destination file
|
||||
num_target_lines_new="$(grep -c "^" "${target}")"
|
||||
# Number of new correctly added lines
|
||||
num_correct_lines="$(( num_target_lines_new-num_target_lines ))"
|
||||
# Update number of lines in target file
|
||||
num_target_lines="$num_target_lines_new"
|
||||
num_invalid="$(( num_source_lines-num_correct_lines ))"
|
||||
if [[ "${num_invalid}" -eq 0 ]]; then
|
||||
echo " ${INFO} Analyzed ${num_source_lines} domains"
|
||||
# A list of items of common local hostnames not to report as unusable
|
||||
# Some lists (i.e StevenBlack's) contain these as they are supposed to be used as HOST files
|
||||
# but flagging them as unusable causes more confusion than it's worth - so we suppress them from the output
|
||||
false_positives="localhost|localhost.localdomain|local|broadcasthost|localhost|ip6-localhost|ip6-loopback|lo0 localhost|ip6-localnet|ip6-mcastprefix|ip6-allnodes|ip6-allrouters|ip6-allhosts"
|
||||
|
||||
# if there are any non-domains, filter the array for false-positives
|
||||
# Credit: https://stackoverflow.com/a/40264051
|
||||
if [[ "${#non_domains[@]}" -gt 0 ]]; then
|
||||
mapfile -d $'\0' -t non_domains < <(printf '%s\0' "${non_domains[@]}" | grep -Ezv "^${false_positives}")
|
||||
fi
|
||||
|
||||
# Get a sample of non-domain entries, limited to 5 (the list should already have been de-duplicated)
|
||||
IFS=" " read -r -a sample_non_domains <<< "$(tr ' ' '\n' <<< "${non_domains[@]}" | head -n 5 | tr '\n' ' ')"
|
||||
|
||||
# Get the number of domains added
|
||||
num_domains="$(grep -c "^" "${temp_file}")"
|
||||
# Get the number of non_domains (this is the number of entries left after stripping the source of comments/duplicates/false positives/domains)
|
||||
num_non_domains="${#non_domains[@]}"
|
||||
|
||||
# If there are unusable lines, we display some information about them. This is not error or major cause for concern.
|
||||
if [[ "${num_non_domains}" -ne 0 ]]; then
|
||||
echo " ${INFO} Imported ${num_domains} domains, ignoring ${num_non_domains} non-domain entries"
|
||||
echo " Sample of non-domain entries:"
|
||||
for each in "${sample_non_domains[@]}"
|
||||
do
|
||||
echo " - ${each}"
|
||||
done
|
||||
else
|
||||
echo " ${INFO} Analyzed ${num_source_lines} domains, ${num_invalid} domains invalid!"
|
||||
echo " ${INFO} Imported ${num_domains} domains"
|
||||
fi
|
||||
|
||||
# Display sample of invalid lines if we found some
|
||||
if [[ -n "${incorrect_lines}" ]]; then
|
||||
echo " Sample of invalid domains:"
|
||||
while IFS= read -r line; do
|
||||
echo " - ${line}"
|
||||
done <<< "${incorrect_lines}"
|
||||
fi
|
||||
# close file handle
|
||||
exec 3<&-
|
||||
}
|
||||
|
||||
compareLists() {
|
||||
local adlistID="${1}" target="${2}"
|
||||
|
||||
@@ -587,7 +651,7 @@ gravity_DownloadBlocklistFromUrl() {
|
||||
local heisenbergCompensator="" patternBuffer str httpCode success="" ip
|
||||
|
||||
# Create temp file to store content on disk instead of RAM
|
||||
patternBuffer=$(mktemp -p "/tmp" --suffix=".phgpb")
|
||||
patternBuffer=$(mktemp -p "${GRAVITY_TMPDIR}" --suffix=".phgpb")
|
||||
|
||||
# Determine if $saveLocation has read permission
|
||||
if [[ -r "${saveLocation}" && $url != "file"* ]]; then
|
||||
@@ -641,7 +705,7 @@ gravity_DownloadBlocklistFromUrl() {
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
httpCode=$(curl -s -L ${compression} ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" -A "${agent}" "${url}" -o "${patternBuffer}" 2> /dev/null)
|
||||
httpCode=$(curl --connect-timeout ${curl_connect_timeout} -s -L ${compression} ${cmd_ext} ${heisenbergCompensator} -w "%{http_code}" -A "${agent}" "${url}" -o "${patternBuffer}" 2> /dev/null)
|
||||
|
||||
case $url in
|
||||
# Did we "download" a local file?
|
||||
@@ -709,8 +773,8 @@ gravity_DownloadBlocklistFromUrl() {
|
||||
else
|
||||
echo -e " ${CROSS} List download failed: ${COL_LIGHT_RED}no cached list available${COL_NC}"
|
||||
# Manually reset these two numbers because we do not call parseList here
|
||||
num_source_lines=0
|
||||
num_invalid=0
|
||||
num_domains=0
|
||||
num_non_domains=0
|
||||
database_adlist_number "${adlistID}"
|
||||
database_adlist_status "${adlistID}" "4"
|
||||
fi
|
||||
@@ -719,72 +783,37 @@ gravity_DownloadBlocklistFromUrl() {
|
||||
|
||||
# Parse source files into domains format
|
||||
gravity_ParseFileIntoDomains() {
|
||||
local source="${1}" destination="${2}" firstLine
|
||||
local src="${1}" destination="${2}"
|
||||
|
||||
# Determine if we are parsing a consolidated list
|
||||
#if [[ "${source}" == "${piholeDir}/${matterAndLight}" ]]; then
|
||||
# Remove comments and print only the domain name
|
||||
# Most of the lists downloaded are already in hosts file format but the spacing/formatting is not contiguous
|
||||
# This helps with that and makes it easier to read
|
||||
# It also helps with debugging so each stage of the script can be researched more in depth
|
||||
# 1) Remove carriage returns
|
||||
# 2) Convert all characters to lowercase
|
||||
# 3) Remove comments (text starting with "#", include possible spaces before the hash sign)
|
||||
# 4) Remove lines containing "/"
|
||||
# 5) Remove leading tabs, spaces, etc.
|
||||
# 6) Delete lines not matching domain names
|
||||
< "${source}" tr -d '\r' | \
|
||||
tr '[:upper:]' '[:lower:]' | \
|
||||
sed 's/\s*#.*//g' | \
|
||||
sed -r '/(\/).*$/d' | \
|
||||
sed -r 's/^.*\s+//g' | \
|
||||
sed -r '/([^\.]+\.)+[^\.]{2,}/!d' > "${destination}"
|
||||
chmod 644 "${destination}"
|
||||
return 0
|
||||
#fi
|
||||
# Remove comments and print only the domain name
|
||||
# Most of the lists downloaded are already in hosts file format but the spacing/formatting is not contiguous
|
||||
# This helps with that and makes it easier to read
|
||||
# It also helps with debugging so each stage of the script can be researched more in depth
|
||||
# 1) Convert all characters to lowercase
|
||||
tr '[:upper:]' '[:lower:]' < "${src}" > "${destination}"
|
||||
|
||||
# Individual file parsing: Keep comments, while parsing domains from each line
|
||||
# We keep comments to respect the list maintainer's licensing
|
||||
read -r firstLine < "${source}"
|
||||
# 2) Remove carriage returns
|
||||
sed -i 's/\r$//' "${destination}"
|
||||
|
||||
# Determine how to parse individual source file formats
|
||||
if [[ "${firstLine,,}" =~ (adblock|ublock|^!) ]]; then
|
||||
# Compare $firstLine against lower case words found in Adblock lists
|
||||
echo -e " ${CROSS} Format: Adblock (list type not supported)"
|
||||
elif grep -q "^address=/" "${source}" &> /dev/null; then
|
||||
# Parse Dnsmasq format lists
|
||||
echo -e " ${CROSS} Format: Dnsmasq (list type not supported)"
|
||||
elif grep -q -E "^https?://" "${source}" &> /dev/null; then
|
||||
# Parse URL list if source file contains "http://" or "https://"
|
||||
# Scanning for "^IPv4$" is too slow with large (1M) lists on low-end hardware
|
||||
echo -ne " ${INFO} Format: URL"
|
||||
# 3a) Remove comments (text starting with "#", include possible spaces before the hash sign)
|
||||
sed -i 's/\s*#.*//g' "${destination}"
|
||||
|
||||
awk '
|
||||
# Remove URL scheme, optional "username:password@", and ":?/;"
|
||||
# The scheme must be matched carefully to avoid blocking the wrong URL
|
||||
# in cases like:
|
||||
# http://www.evil.com?http://www.good.com
|
||||
# See RFC 3986 section 3.1 for details.
|
||||
/[:?\/;]/ { gsub(/(^[a-zA-Z][a-zA-Z0-9+.-]*:\/\/(.*:.*@)?|[:?\/;].*)/, "", $0) }
|
||||
# Skip lines which are only IPv4 addresses
|
||||
/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ { next }
|
||||
# Print if nonempty
|
||||
length { print }
|
||||
' "${source}" 2> /dev/null > "${destination}"
|
||||
chmod 644 "${destination}"
|
||||
# 3b) Remove lines starting with ! (ABP Comments)
|
||||
sed -i 's/\s*!.*//g' "${destination}"
|
||||
|
||||
echo -e "${OVER} ${TICK} Format: URL"
|
||||
else
|
||||
# Default: Keep hosts/domains file in same format as it was downloaded
|
||||
output=$( { mv "${source}" "${destination}"; } 2>&1 )
|
||||
chmod 644 "${destination}"
|
||||
# 3c) Remove lines starting with [ (ABP Header)
|
||||
sed -i 's/\s*\[.*//g' "${destination}"
|
||||
|
||||
if [[ ! -e "${destination}" ]]; then
|
||||
echo -e "\\n ${CROSS} Unable to move tmp file to ${piholeDir}
|
||||
${output}"
|
||||
gravity_Cleanup "error"
|
||||
fi
|
||||
fi
|
||||
# 4) Remove lines containing "/"
|
||||
sed -i -r '/(\/).*$/d' "${destination}"
|
||||
|
||||
# 5) Remove leading tabs, spaces, etc. (Also removes leading IP addresses)
|
||||
sed -i -r 's/^.*\s+//g' "${destination}"
|
||||
|
||||
# 6) Remove empty lines
|
||||
sed -i '/^$/d' "${destination}"
|
||||
|
||||
chmod 644 "${destination}"
|
||||
}
|
||||
|
||||
# Report number of entries in a table
|
||||
@@ -839,7 +868,7 @@ gravity_Cleanup() {
|
||||
# Delete tmp content generated by Gravity
|
||||
rm ${piholeDir}/pihole.*.txt 2> /dev/null
|
||||
rm ${piholeDir}/*.tmp 2> /dev/null
|
||||
rm /tmp/*.phgpb 2> /dev/null
|
||||
rm "${GRAVITY_TMPDIR}"/*.phgpb 2> /dev/null
|
||||
|
||||
# Ensure this function only runs when gravity_SetDownloadOptions() has completed
|
||||
if [[ "${gravity_Blackbody:-}" == true ]]; then
|
||||
@@ -870,15 +899,19 @@ gravity_Cleanup() {
|
||||
|
||||
database_recovery() {
|
||||
local result
|
||||
local str="Checking integrity of existing gravity database"
|
||||
local str="Checking integrity of existing gravity database (this can take a while)"
|
||||
local option="${1}"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA integrity_check" 2>&1)"; then
|
||||
result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA integrity_check" 2>&1)"
|
||||
|
||||
if [[ ${result} = "ok" ]]; then
|
||||
echo -e "${OVER} ${TICK} ${str} - no errors found"
|
||||
|
||||
str="Checking foreign keys of existing gravity database"
|
||||
str="Checking foreign keys of existing gravity database (this can take a while)"
|
||||
echo -ne " ${INFO} ${str}..."
|
||||
if result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA foreign_key_check" 2>&1)"; then
|
||||
unset result
|
||||
result="$(pihole-FTL sqlite3 "${gravityDBfile}" "PRAGMA foreign_key_check" 2>&1)"
|
||||
if [[ -z ${result} ]]; then
|
||||
echo -e "${OVER} ${TICK} ${str} - no errors found"
|
||||
if [[ "${option}" != "force" ]]; then
|
||||
return
|
||||
@@ -1012,6 +1045,9 @@ fi
|
||||
# Update gravity timestamp
|
||||
update_gravity_timestamp
|
||||
|
||||
# Set abp_domain info field
|
||||
set_abp_info
|
||||
|
||||
# Ensure proper permissions are set for the database
|
||||
chown pihole:pihole "${gravityDBfile}"
|
||||
chmod g+w "${piholeDir}" "${gravityDBfile}"
|
||||
|
||||
@@ -11,8 +11,6 @@ Pi-hole : A black-hole for internet advertisements
|
||||
.br
|
||||
\fBpihole -a\fR (\fB-c|-f|-k\fR)
|
||||
.br
|
||||
\fBpihole -a -e\fR email
|
||||
.br
|
||||
\fBpihole -a -i\fR interface
|
||||
.br
|
||||
\fBpihole -a -l\fR privacylevel
|
||||
@@ -25,7 +23,7 @@ Pi-hole : A black-hole for internet advertisements
|
||||
.br
|
||||
pihole -r
|
||||
.br
|
||||
pihole -t
|
||||
\fBpihole\fR \fB-t\fR [arg]
|
||||
.br
|
||||
pihole -g\fR
|
||||
.br
|
||||
@@ -115,11 +113,15 @@ Available commands and options:
|
||||
Reconfigure or Repair Pi-hole subsystems
|
||||
.br
|
||||
|
||||
\fB-t, tail\fR
|
||||
\fB-t, tail\fR [arg]
|
||||
.br
|
||||
View the live output of the Pi-hole log
|
||||
.br
|
||||
|
||||
[arg] Optional argument to filter the log for
|
||||
(regular expressions are supported)
|
||||
.br
|
||||
|
||||
\fB-a, admin\fR [options]
|
||||
.br
|
||||
|
||||
@@ -132,9 +134,6 @@ Available commands and options:
|
||||
-f, fahrenheit Set Fahrenheit as preferred temperature unit
|
||||
.br
|
||||
-k, kelvin Set Kelvin as preferred temperature unit
|
||||
.br
|
||||
-e, email Set an administrative contact address for the
|
||||
Block Page
|
||||
.br
|
||||
-i, interface Specify dnsmasq's interface listening behavior
|
||||
.br
|
||||
|
||||
144
pihole
144
pihole
@@ -16,7 +16,6 @@ readonly PI_HOLE_SCRIPT_DIR="/opt/pihole"
|
||||
# error due to modifying a readonly variable.
|
||||
setupVars="/etc/pihole/setupVars.conf"
|
||||
PI_HOLE_BIN_DIR="/usr/local/bin"
|
||||
readonly FTL_PID_FILE="/run/pihole-FTL.pid"
|
||||
|
||||
readonly colfile="${PI_HOLE_SCRIPT_DIR}/COL_TABLE"
|
||||
source "${colfile}"
|
||||
@@ -24,6 +23,14 @@ source "${colfile}"
|
||||
utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh"
|
||||
source "${utilsfile}"
|
||||
|
||||
versionsfile="/etc/pihole/versions"
|
||||
if [ -f "${versionsfile}" ]; then
|
||||
# Only source versionsfile if the file exits
|
||||
# fixes a warning during installation where versionsfile does not exist yet
|
||||
# but gravity calls `pihole -status` and thereby sourcing the file
|
||||
source "${versionsfile}"
|
||||
fi
|
||||
|
||||
webpageFunc() {
|
||||
source "${PI_HOLE_SCRIPT_DIR}/webpage.sh"
|
||||
main "$@"
|
||||
@@ -36,19 +43,20 @@ listFunc() {
|
||||
}
|
||||
|
||||
debugFunc() {
|
||||
local automated
|
||||
local web
|
||||
local automated
|
||||
local web
|
||||
local check_database_integrity
|
||||
# Pull off the `debug` leaving passed call augmentation flags in $1
|
||||
shift
|
||||
|
||||
# Pull off the `debug` leaving passed call augmentation flags in $1
|
||||
shift
|
||||
if [[ "$@" == *"-a"* ]]; then
|
||||
automated="true"
|
||||
fi
|
||||
if [[ "$@" == *"-w"* ]]; then
|
||||
web="true"
|
||||
fi
|
||||
for value in "$@"; do
|
||||
[[ "$value" == *"-a"* ]] && automated="true"
|
||||
[[ "$value" == *"-w"* ]] && web="true"
|
||||
[[ "$value" == *"-c"* ]] && check_database_integrity="true"
|
||||
[[ "$value" == *"--check_database"* ]] && check_database_integrity="true"
|
||||
done
|
||||
|
||||
AUTOMATED=${automated:-} WEBCALL=${web:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
|
||||
AUTOMATED=${automated:-} WEBCALL=${web:-} CHECK_DATABASE=${check_database_integrity:-} "${PI_HOLE_SCRIPT_DIR}"/piholeDebug.sh
|
||||
exit 0
|
||||
}
|
||||
|
||||
@@ -63,14 +71,22 @@ arpFunc() {
|
||||
}
|
||||
|
||||
updatePiholeFunc() {
|
||||
shift
|
||||
"${PI_HOLE_SCRIPT_DIR}"/update.sh "$@"
|
||||
exit 0
|
||||
if [ -n "${DOCKER_VERSION}" ]; then
|
||||
unsupportedFunc
|
||||
else
|
||||
shift
|
||||
"${PI_HOLE_SCRIPT_DIR}"/update.sh "$@"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
reconfigurePiholeFunc() {
|
||||
/etc/.pihole/automated\ install/basic-install.sh --reconfigure
|
||||
exit 0;
|
||||
if [ -n "${DOCKER_VERSION}" ]; then
|
||||
unsupportedFunc
|
||||
else
|
||||
/etc/.pihole/automated\ install/basic-install.sh --reconfigure
|
||||
exit 0;
|
||||
fi
|
||||
}
|
||||
|
||||
updateGravityFunc() {
|
||||
@@ -91,8 +107,12 @@ chronometerFunc() {
|
||||
|
||||
|
||||
uninstallFunc() {
|
||||
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
|
||||
exit 0
|
||||
if [ -n "${DOCKER_VERSION}" ]; then
|
||||
unsupportedFunc
|
||||
else
|
||||
"${PI_HOLE_SCRIPT_DIR}"/uninstall.sh
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
versionFunc() {
|
||||
@@ -100,34 +120,21 @@ versionFunc() {
|
||||
exec "${PI_HOLE_SCRIPT_DIR}"/version.sh "$@"
|
||||
}
|
||||
|
||||
# Get PID of main pihole-FTL process
|
||||
getFTLPID() {
|
||||
local pid
|
||||
|
||||
if [ -s "${FTL_PID_FILE}" ]; then
|
||||
# -s: FILE exists and has a size greater than zero
|
||||
pid="$(<"$FTL_PID_FILE")"
|
||||
# Exploit prevention: unset the variable if there is malicious content
|
||||
# Verify that the value read from the file is numeric
|
||||
[[ "$pid" =~ [^[:digit:]] ]] && unset pid
|
||||
fi
|
||||
|
||||
# If FTL is not running, or the PID file contains malicious stuff, substitute
|
||||
# negative PID to signal this to the caller
|
||||
echo "${pid:=-1}"
|
||||
}
|
||||
|
||||
restartDNS() {
|
||||
local svcOption svc str output status pid icon
|
||||
local svcOption svc str output status pid icon FTL_PID_FILE
|
||||
svcOption="${1:-restart}"
|
||||
|
||||
# get the current path to the pihole-FTL.pid
|
||||
FTL_PID_FILE="$(getFTLPIDFile)"
|
||||
|
||||
# Determine if we should reload or restart
|
||||
if [[ "${svcOption}" =~ "reload-lists" ]]; then
|
||||
# Reloading of the lists has been requested
|
||||
# Note 1: This will NOT re-read any *.conf files
|
||||
# Note 2: We cannot use killall here as it does
|
||||
# not know about real-time signals
|
||||
pid="$(getFTLPID)"
|
||||
|
||||
pid="$(getFTLPID ${FTL_PID_FILE})"
|
||||
if [[ "$pid" -eq "-1" ]]; then
|
||||
svc="true"
|
||||
str="FTL is not running"
|
||||
@@ -140,7 +147,7 @@ restartDNS() {
|
||||
elif [[ "${svcOption}" =~ "reload" ]]; then
|
||||
# Reloading of the DNS cache has been requested
|
||||
# Note: This will NOT re-read any *.conf files
|
||||
pid="$(getFTLPID)"
|
||||
pid="$(getFTLPID ${FTL_PID_FILE})"
|
||||
if [[ "$pid" -eq "-1" ]]; then
|
||||
svc="true"
|
||||
str="FTL is not running"
|
||||
@@ -315,33 +322,36 @@ analyze_ports() {
|
||||
}
|
||||
|
||||
statusFunc() {
|
||||
# Determine if there is pihole-FTL service is listening
|
||||
local pid port ftl_api_port
|
||||
# Determine if there is pihole-FTL service is listening
|
||||
local pid port ftl_api_port ftl_pid_file
|
||||
|
||||
pid="$(getFTLPID)"
|
||||
ftl_api_port="$(getFTLAPIPort)"
|
||||
if [[ "$pid" -eq "-1" ]]; then
|
||||
case "${1}" in
|
||||
"web") echo "-1";;
|
||||
*) echo -e " ${CROSS} DNS service is NOT running";;
|
||||
esac
|
||||
return 0
|
||||
else
|
||||
#get the DNS port pihole-FTL is listening on by using FTL's telnet API
|
||||
port="$(echo ">dns-port >quit" | nc 127.0.0.1 "$ftl_api_port")"
|
||||
if [[ "${port}" == "0" ]]; then
|
||||
case "${1}" in
|
||||
"web") echo "-1";;
|
||||
*) echo -e " ${CROSS} DNS service is NOT listening";;
|
||||
esac
|
||||
return 0
|
||||
ftl_pid_file="$(getFTLPIDFile)"
|
||||
|
||||
pid="$(getFTLPID ${ftl_pid_file})"
|
||||
|
||||
ftl_api_port="$(getFTLAPIPort)"
|
||||
if [[ "$pid" -eq "-1" ]]; then
|
||||
case "${1}" in
|
||||
"web") echo "-1";;
|
||||
*) echo -e " ${CROSS} DNS service is NOT running";;
|
||||
esac
|
||||
return 0
|
||||
else
|
||||
if [[ "${1}" != "web" ]]; then
|
||||
echo -e " ${TICK} FTL is listening on port ${port}"
|
||||
analyze_ports "${port}"
|
||||
fi
|
||||
#get the DNS port pihole-FTL is listening on by using FTL's telnet API
|
||||
port="$(echo ">dns-port >quit" | nc 127.0.0.1 "$ftl_api_port")"
|
||||
if [[ "${port}" == "0" ]]; then
|
||||
case "${1}" in
|
||||
"web") echo "-1";;
|
||||
*) echo -e " ${CROSS} DNS service is NOT listening";;
|
||||
esac
|
||||
return 0
|
||||
else
|
||||
if [[ "${1}" != "web" ]]; then
|
||||
echo -e " ${TICK} FTL is listening on port ${port}"
|
||||
analyze_ports "${port}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Determine if Pi-hole's blocking is enabled
|
||||
if grep -q "BLOCKING_ENABLED=false" /etc/pihole/setupVars.conf; then
|
||||
@@ -439,6 +449,11 @@ updateCheckFunc() {
|
||||
exit 0
|
||||
}
|
||||
|
||||
unsupportedFunc(){
|
||||
echo "Function not supported in Docker images"
|
||||
exit 0
|
||||
}
|
||||
|
||||
helpFunc() {
|
||||
echo "Usage: pihole [options]
|
||||
Example: 'pihole -w -h'
|
||||
@@ -455,6 +470,7 @@ Whitelist/Blacklist Options:
|
||||
|
||||
Debugging Options:
|
||||
-d, debug Start a debugging session
|
||||
Add '-c' or '--check-database' to include a Pi-hole database integrity check
|
||||
Add '-a' to automatically upload the log to tricorder.pi-hole.net
|
||||
-f, flush Flush the Pi-hole log
|
||||
-r, reconfigure Reconfigure or Repair Pi-hole subsystems
|
||||
@@ -562,7 +578,7 @@ case "${1}" in
|
||||
"restartdns" ) restartDNS "$2";;
|
||||
"-a" | "admin" ) webpageFunc "$@";;
|
||||
"checkout" ) piholeCheckoutFunc "$@";;
|
||||
"updatechecker" ) updateCheckFunc "$@";;
|
||||
"updatechecker" ) shift; updateCheckFunc "$@";;
|
||||
"arpflush" ) arpFunc "$@";;
|
||||
"-t" | "tail" ) tailFunc "$2";;
|
||||
esac
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
FROM centos:7
|
||||
RUN yum install -y dialog git python3
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
|
||||
RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
|
||||
ADD test/centos7.epel.override /etc/yum/pluginconf.d/fastestmirror.conf
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM quay.io/centos/centos:stream8
|
||||
RUN yum install -y git
|
||||
RUN yum install -y git initscripts
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
@@ -12,7 +12,7 @@ ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM buildpack-deps:impish-scm
|
||||
FROM quay.io/centos/centos:stream9
|
||||
RUN yum install -y --allowerasing curl git initscripts
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
@@ -7,12 +8,11 @@ RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole
|
||||
ADD . $GITDIR
|
||||
RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/
|
||||
ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
@@ -11,7 +11,7 @@ ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
|
||||
@@ -11,7 +11,7 @@ ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM fedora:34
|
||||
RUN dnf install -y git
|
||||
FROM fedora:36
|
||||
RUN dnf install -y git initscripts
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
@@ -12,7 +12,7 @@ ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
@@ -1,4 +1,5 @@
|
||||
FROM buildpack-deps:bionic-scm
|
||||
FROM fedora:37
|
||||
RUN dnf install -y git initscripts
|
||||
|
||||
ENV GITDIR /etc/.pihole
|
||||
ENV SCRIPTDIR /opt/pihole
|
||||
@@ -11,7 +12,7 @@ ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
@@ -12,7 +12,7 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
|
||||
@@ -12,7 +12,7 @@ ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN true && \
|
||||
chmod +x $SCRIPTDIR/*
|
||||
|
||||
ENV PH_TEST true
|
||||
ENV SKIP_INSTALL true
|
||||
ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net
|
||||
|
||||
#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
[main]
|
||||
verbose = 0
|
||||
socket_timeout = 3
|
||||
enabled = 1
|
||||
hostfilepath = /var/cache/yum/timedhosts.txt
|
||||
maxhostfileage = 1
|
||||
exclude=.edu
|
||||
179
test/conftest.py
179
test/conftest.py
@@ -6,12 +6,12 @@ from textwrap import dedent
|
||||
|
||||
|
||||
SETUPVARS = {
|
||||
'PIHOLE_INTERFACE': 'eth99',
|
||||
'PIHOLE_DNS_1': '4.2.2.1',
|
||||
'PIHOLE_DNS_2': '4.2.2.2'
|
||||
"PIHOLE_INTERFACE": "eth99",
|
||||
"PIHOLE_DNS_1": "4.2.2.1",
|
||||
"PIHOLE_DNS_2": "4.2.2.2",
|
||||
}
|
||||
|
||||
IMAGE = 'pytest_pihole:test_container'
|
||||
IMAGE = "pytest_pihole:test_container"
|
||||
|
||||
tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
|
||||
cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
|
||||
@@ -38,132 +38,187 @@ testinfra.backend.docker.DockerBackend.run = run_bash
|
||||
@pytest.fixture
|
||||
def host():
|
||||
# run a container
|
||||
docker_id = subprocess.check_output(
|
||||
['docker', 'run', '-t', '-d', '--cap-add=ALL', IMAGE]).decode().strip()
|
||||
docker_id = (
|
||||
subprocess.check_output(["docker", "run", "-t", "-d", "--cap-add=ALL", IMAGE])
|
||||
.decode()
|
||||
.strip()
|
||||
)
|
||||
|
||||
# return a testinfra connection to the container
|
||||
docker_host = testinfra.get_host("docker://" + docker_id)
|
||||
|
||||
yield docker_host
|
||||
# at the end of the test suite, destroy the container
|
||||
subprocess.check_call(['docker', 'rm', '-f', docker_id])
|
||||
subprocess.check_call(["docker", "rm", "-f", docker_id])
|
||||
|
||||
|
||||
# Helper functions
|
||||
def mock_command(script, args, container):
|
||||
'''
|
||||
"""
|
||||
Allows for setup of commands we don't really want to have to run for real
|
||||
in unit tests
|
||||
'''
|
||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||
mock_script = dedent(r'''\
|
||||
"""
|
||||
full_script_path = "/usr/local/bin/{}".format(script)
|
||||
mock_script = dedent(
|
||||
r"""\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1" in'''.format(script=script))
|
||||
case "\$1" in""".format(
|
||||
script=script
|
||||
)
|
||||
)
|
||||
for k, v in args.items():
|
||||
case = dedent('''
|
||||
case = dedent(
|
||||
"""
|
||||
{arg})
|
||||
echo {res}
|
||||
exit {retcode}
|
||||
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||
;;""".format(
|
||||
arg=k, res=v[0], retcode=v[1]
|
||||
)
|
||||
)
|
||||
mock_script += case
|
||||
mock_script += dedent('''
|
||||
esac''')
|
||||
container.run('''
|
||||
mock_script += dedent(
|
||||
"""
|
||||
esac"""
|
||||
)
|
||||
container.run(
|
||||
"""
|
||||
cat <<EOF> {script}\n{content}\nEOF
|
||||
chmod +x {script}
|
||||
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
||||
content=mock_script,
|
||||
scriptlog=script))
|
||||
rm -f /var/log/{scriptlog}""".format(
|
||||
script=full_script_path, content=mock_script, scriptlog=script
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def mock_command_passthrough(script, args, container):
|
||||
'''
|
||||
"""
|
||||
Per other mock_command* functions, allows intercepting of commands we don't want to run for real
|
||||
in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
|
||||
be passed through to the actual command.
|
||||
|
||||
Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
|
||||
'''
|
||||
orig_script_path = container.check_output('command -v {}'.format(script))
|
||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||
mock_script = dedent(r'''\
|
||||
"""
|
||||
orig_script_path = container.check_output("command -v {}".format(script))
|
||||
full_script_path = "/usr/local/bin/{}".format(script)
|
||||
mock_script = dedent(
|
||||
r"""\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1" in'''.format(script=script))
|
||||
case "\$1" in""".format(
|
||||
script=script
|
||||
)
|
||||
)
|
||||
for k, v in args.items():
|
||||
case = dedent('''
|
||||
case = dedent(
|
||||
"""
|
||||
{arg})
|
||||
echo {res}
|
||||
exit {retcode}
|
||||
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||
;;""".format(
|
||||
arg=k, res=v[0], retcode=v[1]
|
||||
)
|
||||
)
|
||||
mock_script += case
|
||||
mock_script += dedent(r'''
|
||||
mock_script += dedent(
|
||||
r"""
|
||||
*)
|
||||
{orig_script_path} "\$@"
|
||||
;;'''.format(orig_script_path=orig_script_path))
|
||||
mock_script += dedent('''
|
||||
esac''')
|
||||
container.run('''
|
||||
;;""".format(
|
||||
orig_script_path=orig_script_path
|
||||
)
|
||||
)
|
||||
mock_script += dedent(
|
||||
"""
|
||||
esac"""
|
||||
)
|
||||
container.run(
|
||||
"""
|
||||
cat <<EOF> {script}\n{content}\nEOF
|
||||
chmod +x {script}
|
||||
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
||||
content=mock_script,
|
||||
scriptlog=script))
|
||||
rm -f /var/log/{scriptlog}""".format(
|
||||
script=full_script_path, content=mock_script, scriptlog=script
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def mock_command_run(script, args, container):
|
||||
'''
|
||||
"""
|
||||
Allows for setup of commands we don't really want to have to run for real
|
||||
in unit tests
|
||||
'''
|
||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||
mock_script = dedent(r'''\
|
||||
"""
|
||||
full_script_path = "/usr/local/bin/{}".format(script)
|
||||
mock_script = dedent(
|
||||
r"""\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1 \$2" in'''.format(script=script))
|
||||
case "\$1 \$2" in""".format(
|
||||
script=script
|
||||
)
|
||||
)
|
||||
for k, v in args.items():
|
||||
case = dedent('''
|
||||
case = dedent(
|
||||
"""
|
||||
\"{arg}\")
|
||||
echo {res}
|
||||
exit {retcode}
|
||||
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||
;;""".format(
|
||||
arg=k, res=v[0], retcode=v[1]
|
||||
)
|
||||
)
|
||||
mock_script += case
|
||||
mock_script += dedent('''
|
||||
esac''')
|
||||
container.run('''
|
||||
mock_script += dedent(
|
||||
"""
|
||||
esac"""
|
||||
)
|
||||
container.run(
|
||||
"""
|
||||
cat <<EOF> {script}\n{content}\nEOF
|
||||
chmod +x {script}
|
||||
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
||||
content=mock_script,
|
||||
scriptlog=script))
|
||||
rm -f /var/log/{scriptlog}""".format(
|
||||
script=full_script_path, content=mock_script, scriptlog=script
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def mock_command_2(script, args, container):
|
||||
'''
|
||||
"""
|
||||
Allows for setup of commands we don't really want to have to run for real
|
||||
in unit tests
|
||||
'''
|
||||
full_script_path = '/usr/local/bin/{}'.format(script)
|
||||
mock_script = dedent(r'''\
|
||||
"""
|
||||
full_script_path = "/usr/local/bin/{}".format(script)
|
||||
mock_script = dedent(
|
||||
r"""\
|
||||
#!/bin/bash -e
|
||||
echo "\$0 \$@" >> /var/log/{script}
|
||||
case "\$1 \$2" in'''.format(script=script))
|
||||
case "\$1 \$2" in""".format(
|
||||
script=script
|
||||
)
|
||||
)
|
||||
for k, v in args.items():
|
||||
case = dedent('''
|
||||
case = dedent(
|
||||
"""
|
||||
\"{arg}\")
|
||||
echo \"{res}\"
|
||||
exit {retcode}
|
||||
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
||||
;;""".format(
|
||||
arg=k, res=v[0], retcode=v[1]
|
||||
)
|
||||
)
|
||||
mock_script += case
|
||||
mock_script += dedent('''
|
||||
esac''')
|
||||
container.run('''
|
||||
mock_script += dedent(
|
||||
"""
|
||||
esac"""
|
||||
)
|
||||
container.run(
|
||||
"""
|
||||
cat <<EOF> {script}\n{content}\nEOF
|
||||
chmod +x {script}
|
||||
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
||||
content=mock_script,
|
||||
scriptlog=script))
|
||||
rm -f /var/log/{scriptlog}""".format(
|
||||
script=full_script_path, content=mock_script, scriptlog=script
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def run_script(Pihole, script):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
docker-compose
|
||||
pytest
|
||||
pytest-xdist
|
||||
pytest-cov
|
||||
pytest-testinfra
|
||||
tox
|
||||
docker-compose == 1.29.2
|
||||
pytest == 7.2.2
|
||||
pytest-xdist == 3.2.1
|
||||
pytest-testinfra == 7.0.0
|
||||
tox == 4.4.7
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
setup_requires=['pytest-runner'],
|
||||
tests_require=['pytest'],
|
||||
py_modules=[],
|
||||
setup_requires=["pytest-runner"],
|
||||
tests_require=["pytest"],
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,22 +1,27 @@
|
||||
def test_key_val_replacement_works(host):
|
||||
''' Confirms addOrEditKeyValPair either adds or replaces a key value pair in a given file '''
|
||||
host.run('''
|
||||
"""Confirms addOrEditKeyValPair either adds or replaces a key value pair in a given file"""
|
||||
host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value1"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_TWO" "value2"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value3"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_FOUR" "value4"
|
||||
''')
|
||||
output = host.run('''
|
||||
"""
|
||||
)
|
||||
output = host.run(
|
||||
"""
|
||||
cat ./testoutput
|
||||
''')
|
||||
expected_stdout = 'KEY_ONE=value3\nKEY_TWO=value2\nKEY_FOUR=value4\n'
|
||||
"""
|
||||
)
|
||||
expected_stdout = "KEY_ONE=value3\nKEY_TWO=value2\nKEY_FOUR=value4\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_key_addition_works(host):
|
||||
''' Confirms addKey adds a key (no value) to a file without duplicating it '''
|
||||
host.run('''
|
||||
"""Confirms addKey adds a key (no value) to a file without duplicating it"""
|
||||
host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
addKey "./testoutput" "KEY_ONE"
|
||||
addKey "./testoutput" "KEY_ONE"
|
||||
@@ -24,17 +29,41 @@ def test_key_addition_works(host):
|
||||
addKey "./testoutput" "KEY_TWO"
|
||||
addKey "./testoutput" "KEY_THREE"
|
||||
addKey "./testoutput" "KEY_THREE"
|
||||
''')
|
||||
output = host.run('''
|
||||
"""
|
||||
)
|
||||
output = host.run(
|
||||
"""
|
||||
cat ./testoutput
|
||||
''')
|
||||
expected_stdout = 'KEY_ONE\nKEY_TWO\nKEY_THREE\n'
|
||||
"""
|
||||
)
|
||||
expected_stdout = "KEY_ONE\nKEY_TWO\nKEY_THREE\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_key_addition_substr(host):
|
||||
"""Confirms addKey adds substring keys (no value) to a file"""
|
||||
host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
addKey "./testoutput" "KEY_ONE"
|
||||
addKey "./testoutput" "KEY_O"
|
||||
addKey "./testoutput" "KEY_TWO"
|
||||
addKey "./testoutput" "Y_TWO"
|
||||
"""
|
||||
)
|
||||
output = host.run(
|
||||
"""
|
||||
cat ./testoutput
|
||||
"""
|
||||
)
|
||||
expected_stdout = "KEY_ONE\nKEY_O\nKEY_TWO\nY_TWO\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_key_removal_works(host):
|
||||
''' Confirms removeKey removes a key or key/value pair '''
|
||||
host.run('''
|
||||
"""Confirms removeKey removes a key or key/value pair"""
|
||||
host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
addOrEditKeyValPair "./testoutput" "KEY_ONE" "value1"
|
||||
addOrEditKeyValPair "./testoutput" "KEY_TWO" "value2"
|
||||
@@ -42,33 +71,102 @@ def test_key_removal_works(host):
|
||||
addKey "./testoutput" "KEY_FOUR"
|
||||
removeKey "./testoutput" "KEY_TWO"
|
||||
removeKey "./testoutput" "KEY_FOUR"
|
||||
''')
|
||||
output = host.run('''
|
||||
"""
|
||||
)
|
||||
output = host.run(
|
||||
"""
|
||||
cat ./testoutput
|
||||
''')
|
||||
expected_stdout = 'KEY_ONE=value1\nKEY_THREE=value3\n'
|
||||
"""
|
||||
)
|
||||
expected_stdout = "KEY_ONE=value1\nKEY_THREE=value3\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLAPIPort_default(host):
|
||||
''' Confirms getFTLAPIPort returns the default API port '''
|
||||
output = host.run('''
|
||||
"""Confirms getFTLAPIPort returns the default API port"""
|
||||
output = host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
getFTLAPIPort
|
||||
''')
|
||||
expected_stdout = '4711\n'
|
||||
"""
|
||||
)
|
||||
expected_stdout = "4711\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLAPIPort_custom(host):
|
||||
''' Confirms getFTLAPIPort returns a custom API port in a custom PORTFILE location '''
|
||||
host.run('''
|
||||
echo "PORTFILE=/tmp/port.file" > /etc/pihole/pihole-FTL.conf
|
||||
echo "1234" > /tmp/port.file
|
||||
''')
|
||||
output = host.run('''
|
||||
"""Confirms getFTLAPIPort returns a custom API port"""
|
||||
host.run(
|
||||
"""
|
||||
echo "FTLPORT=1234" > /etc/pihole/pihole-FTL.conf
|
||||
"""
|
||||
)
|
||||
output = host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
getFTLAPIPort
|
||||
''')
|
||||
expected_stdout = '1234\n'
|
||||
"""
|
||||
)
|
||||
expected_stdout = "1234\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLAPIPort_malicious(host):
|
||||
"""Confirms getFTLAPIPort returns 4711 if the setting in pihole-FTL.conf contains non-digits"""
|
||||
host.run(
|
||||
"""
|
||||
echo "FTLPORT=*$ssdfsd" > /etc/pihole/pihole-FTL.conf
|
||||
"""
|
||||
)
|
||||
output = host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
getFTLAPIPort
|
||||
"""
|
||||
)
|
||||
expected_stdout = "4711\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLPIDFile_default(host):
|
||||
"""Confirms getFTLPIDFile returns the default PID file path"""
|
||||
output = host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
getFTLPIDFile
|
||||
"""
|
||||
)
|
||||
expected_stdout = "/run/pihole-FTL.pid\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLPID_default(host):
|
||||
"""Confirms getFTLPID returns the default value if FTL is not running"""
|
||||
output = host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
getFTLPID
|
||||
"""
|
||||
)
|
||||
expected_stdout = "-1\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
|
||||
def test_getFTLPIDFile_and_getFTLPID_custom(host):
|
||||
"""Confirms getFTLPIDFile returns a custom PID file path"""
|
||||
host.run(
|
||||
"""
|
||||
tmpfile=$(mktemp)
|
||||
echo "PIDFILE=${tmpfile}" > /etc/pihole/pihole-FTL.conf
|
||||
echo "1234" > ${tmpfile}
|
||||
"""
|
||||
)
|
||||
output = host.run(
|
||||
"""
|
||||
source /opt/pihole/utils.sh
|
||||
FTL_PID_FILE=$(getFTLPIDFile)
|
||||
getFTLPID "${FTL_PID_FILE}"
|
||||
"""
|
||||
)
|
||||
expected_stdout = "1234\n"
|
||||
assert expected_stdout == output.stdout
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
from .conftest import (
|
||||
tick_box,
|
||||
info_box,
|
||||
mock_command,
|
||||
)
|
||||
|
||||
|
||||
def test_php_upgrade_default_optout_centos_eq_7(host):
|
||||
'''
|
||||
confirms the default behavior to opt-out of installing PHP7 from REMI
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optout_centos_eq_7(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-out of installing PHP7 from REMI
|
||||
(php not currently installed)
|
||||
'''
|
||||
# dialog returns Cancel for user prompt
|
||||
mock_command('dialog', {'*': ('', '1')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optin_centos_eq_7(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-in to installing PHP7 from REMI
|
||||
(php not currently installed)
|
||||
'''
|
||||
# dialog returns Continue for user prompt
|
||||
mock_command('dialog', {'*': ('', '0')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
assert 'opt-out' not in package_manager_detect.stdout
|
||||
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert remi_package.is_installed
|
||||
@@ -1,68 +0,0 @@
|
||||
from .conftest import (
|
||||
tick_box,
|
||||
info_box,
|
||||
mock_command,
|
||||
)
|
||||
|
||||
|
||||
def test_php_upgrade_default_continue_centos_gte_8(host):
|
||||
'''
|
||||
confirms the latest version of CentOS continues / does not optout
|
||||
(should trigger on CentOS7 only)
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
|
||||
' Deprecated PHP may be in use.')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
# ensure remi was not installed on latest CentOS
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optout_skipped_centos_gte_8(host):
|
||||
'''
|
||||
confirms installer skips user opt-out of installing PHP7 from REMI on
|
||||
latest CentOS (should trigger on CentOS7 only)
|
||||
(php not currently installed)
|
||||
'''
|
||||
# dialog dialog returns Cancel for user prompt
|
||||
mock_command('dialog', {'*': ('', '1')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
unexpected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS.'
|
||||
' Deprecated PHP may be in use.')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
# ensure remi was not installed on latest CentOS
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_upgrade_user_optin_skipped_centos_gte_8(host):
|
||||
'''
|
||||
confirms installer skips user opt-in to installing PHP7 from REMI on
|
||||
latest CentOS (should trigger on CentOS7 only)
|
||||
(php not currently installed)
|
||||
'''
|
||||
# dialog dialog returns Continue for user prompt
|
||||
mock_command('dialog', {'*': ('', '0')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
assert 'opt-out' not in package_manager_detect.stdout
|
||||
unexpected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
unexpected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert unexpected_stdout not in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
@@ -7,119 +7,21 @@ from .conftest import (
|
||||
)
|
||||
|
||||
|
||||
def test_release_supported_version_check_centos(host):
|
||||
'''
|
||||
confirms installer exits on unsupported releases of CentOS
|
||||
'''
|
||||
# modify /etc/redhat-release to mock an unsupported CentOS release
|
||||
host.run('echo "CentOS Linux release 6.9" > /etc/redhat-release')
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = cross_box + (' CentOS 6 is not supported.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = 'Please update to CentOS release 7 or later'
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
|
||||
|
||||
def test_enable_epel_repository_centos(host):
|
||||
'''
|
||||
"""
|
||||
confirms the EPEL package repository is enabled when installed on CentOS
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
"""
|
||||
package_manager_detect = host.run(
|
||||
"""
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' Enabling EPEL package repository '
|
||||
'(https://fedoraproject.org/wiki/EPEL)')
|
||||
"""
|
||||
)
|
||||
expected_stdout = info_box + (
|
||||
" Enabling EPEL package repository " "(https://fedoraproject.org/wiki/EPEL)"
|
||||
)
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = tick_box + ' Installed'
|
||||
expected_stdout = tick_box + " Installed"
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
epel_package = host.package('epel-release')
|
||||
epel_package = host.package("epel-release")
|
||||
assert epel_package.is_installed
|
||||
|
||||
|
||||
def test_php_version_lt_7_detected_upgrade_default_optout_centos(host):
|
||||
'''
|
||||
confirms the default behavior to opt-out of upgrading to PHP7 from REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = host.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = host.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_version_lt_7_detected_upgrade_user_optout_centos(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-out to upgrade to PHP7 via REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = host.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = host.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
# dialog returns Cancel for user prompt
|
||||
mock_command('dialog', {'*': ('', '1')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
|
||||
def test_php_version_lt_7_detected_upgrade_user_optin_centos(host):
|
||||
'''
|
||||
confirms installer behavior when user opt-in to upgrade to PHP7 via REMI
|
||||
'''
|
||||
# first we will install the default php version to test installer behavior
|
||||
php_install = host.run('yum install -y php')
|
||||
assert php_install.rc == 0
|
||||
php_package = host.package('php')
|
||||
default_centos_php_version = php_package.version.split('.')[0]
|
||||
if int(default_centos_php_version) >= 7: # PHP7 is supported/recommended
|
||||
pytest.skip("Test deprecated . Detected default PHP version >= 7")
|
||||
# dialog returns Continue for user prompt
|
||||
mock_command('dialog', {'*': ('', '0')}, host)
|
||||
package_manager_detect = host.run('''
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
install_dependent_packages PIHOLE_WEB_DEPS[@]
|
||||
''')
|
||||
expected_stdout = info_box + (' User opt-out of PHP 7 upgrade on CentOS. '
|
||||
'Deprecated PHP may be in use.')
|
||||
assert expected_stdout not in package_manager_detect.stdout
|
||||
expected_stdout = info_box + (' Enabling Remi\'s RPM repository '
|
||||
'(https://rpms.remirepo.net)')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
expected_stdout = tick_box + (' Remi\'s RPM repository has '
|
||||
'been enabled for PHP7')
|
||||
assert expected_stdout in package_manager_detect.stdout
|
||||
remi_package = host.package('remi-release')
|
||||
assert remi_package.is_installed
|
||||
updated_php_package = host.package('php')
|
||||
updated_php_version = updated_php_package.version.split('.')[0]
|
||||
assert int(updated_php_version) == 7
|
||||
|
||||
@@ -6,60 +6,70 @@ from .conftest import (
|
||||
|
||||
|
||||
def mock_selinux_config(state, host):
|
||||
'''
|
||||
"""
|
||||
Creates a mock SELinux config file with expected content
|
||||
'''
|
||||
"""
|
||||
# validate state string
|
||||
valid_states = ['enforcing', 'permissive', 'disabled']
|
||||
valid_states = ["enforcing", "permissive", "disabled"]
|
||||
assert state in valid_states
|
||||
# getenforce returns the running state of SELinux
|
||||
mock_command('getenforce', {'*': (state.capitalize(), '0')}, host)
|
||||
mock_command("getenforce", {"*": (state.capitalize(), "0")}, host)
|
||||
# create mock configuration with desired content
|
||||
host.run('''
|
||||
host.run(
|
||||
"""
|
||||
mkdir /etc/selinux
|
||||
echo "SELINUX={state}" > /etc/selinux/config
|
||||
'''.format(state=state.lower()))
|
||||
""".format(
|
||||
state=state.lower()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_selinux_enforcing_exit(host):
|
||||
'''
|
||||
"""
|
||||
confirms installer prompts to exit when SELinux is Enforcing by default
|
||||
'''
|
||||
"""
|
||||
mock_selinux_config("enforcing", host)
|
||||
check_selinux = host.run('''
|
||||
check_selinux = host.run(
|
||||
"""
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = cross_box + ' Current SELinux: Enforcing'
|
||||
"""
|
||||
)
|
||||
expected_stdout = cross_box + " Current SELinux: enforcing"
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
expected_stdout = 'SELinux Enforcing detected, exiting installer'
|
||||
expected_stdout = "SELinux Enforcing detected, exiting installer"
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 1
|
||||
|
||||
|
||||
def test_selinux_permissive(host):
|
||||
'''
|
||||
"""
|
||||
confirms installer continues when SELinux is Permissive
|
||||
'''
|
||||
"""
|
||||
mock_selinux_config("permissive", host)
|
||||
check_selinux = host.run('''
|
||||
check_selinux = host.run(
|
||||
"""
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = tick_box + ' Current SELinux: Permissive'
|
||||
"""
|
||||
)
|
||||
expected_stdout = tick_box + " Current SELinux: permissive"
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 0
|
||||
|
||||
|
||||
def test_selinux_disabled(host):
|
||||
'''
|
||||
"""
|
||||
confirms installer continues when SELinux is Disabled
|
||||
'''
|
||||
"""
|
||||
mock_selinux_config("disabled", host)
|
||||
check_selinux = host.run('''
|
||||
check_selinux = host.run(
|
||||
"""
|
||||
source /opt/pihole/basic-install.sh
|
||||
checkSelinux
|
||||
''')
|
||||
expected_stdout = tick_box + ' Current SELinux: Disabled'
|
||||
"""
|
||||
)
|
||||
expected_stdout = tick_box + " Current SELinux: disabled"
|
||||
assert expected_stdout in check_selinux.stdout
|
||||
assert check_selinux.rc == 0
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
def test_epel_and_remi_not_installed_fedora(host):
|
||||
'''
|
||||
"""
|
||||
confirms installer does not attempt to install EPEL/REMI repositories
|
||||
on Fedora
|
||||
'''
|
||||
package_manager_detect = host.run('''
|
||||
"""
|
||||
package_manager_detect = host.run(
|
||||
"""
|
||||
source /opt/pihole/basic-install.sh
|
||||
package_manager_detect
|
||||
select_rpm_php
|
||||
''')
|
||||
assert package_manager_detect.stdout == ''
|
||||
"""
|
||||
)
|
||||
assert package_manager_detect.stdout == ""
|
||||
|
||||
epel_package = host.package('epel-release')
|
||||
epel_package = host.package("epel-release")
|
||||
assert not epel_package.is_installed
|
||||
remi_package = host.package('remi-release')
|
||||
assert not remi_package.is_installed
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _centos_7.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py ./test_centos_7_support.py
|
||||
@@ -1,8 +1,8 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
envlist = py3
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
[testenv:py3]
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _centos_8.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py ./test_centos_8_support.py
|
||||
commands = docker buildx build --load --progress plain -f _centos_8.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py
|
||||
|
||||
8
test/tox.centos_9.ini
Normal file
8
test/tox.centos_9.ini
Normal file
@@ -0,0 +1,8 @@
|
||||
[tox]
|
||||
envlist = py3
|
||||
|
||||
[testenv:py3]
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker buildx build --load --progress plain -f _centos_9.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py
|
||||
@@ -1,8 +1,8 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
envlist = py3
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
[testenv:py3]
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _debian_10.Dockerfile -t pytest_pihole:test_container ../
|
||||
commands = docker buildx build --load --progress plain -f _debian_10.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
envlist = py3
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
[testenv:py3]
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _debian_11.Dockerfile -t pytest_pihole:test_container ../
|
||||
commands = docker buildx build --load --progress plain -f _debian_11.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
||||
|
||||
8
test/tox.fedora_36.ini
Normal file
8
test/tox.fedora_36.ini
Normal file
@@ -0,0 +1,8 @@
|
||||
[tox]
|
||||
envlist = py3
|
||||
|
||||
[testenv:py3]
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker buildx build --load --progress plain -f _fedora_36.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_fedora_support.py
|
||||
@@ -1,8 +1,8 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
envlist = py3
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _fedora_34.Dockerfile -t pytest_pihole:test_container ../
|
||||
commands = docker buildx build --load --progress plain -f _fedora_37.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_fedora_support.py
|
||||
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_18.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
||||
@@ -1,8 +1,8 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
envlist = py3
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
[testenv:py3]
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_20.Dockerfile -t pytest_pihole:test_container ../
|
||||
commands = docker buildx build --load --progress plain -f _ubuntu_20.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_21.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
||||
@@ -1,8 +1,8 @@
|
||||
[tox]
|
||||
envlist = py38
|
||||
envlist = py3
|
||||
|
||||
[testenv]
|
||||
whitelist_externals = docker
|
||||
[testenv:py3]
|
||||
allowlist_externals = docker
|
||||
deps = -rrequirements.txt
|
||||
commands = docker build -f _ubuntu_22.Dockerfile -t pytest_pihole:test_container ../
|
||||
commands = docker buildx build --load --progress plain -f _ubuntu_22.Dockerfile -t pytest_pihole:test_container ../
|
||||
pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py
|
||||
|
||||
Reference in New Issue
Block a user